歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C++ 哈弗曼編碼的實現與反編碼

C++ 哈弗曼編碼的實現與反編碼

日期:2017/3/1 11:08:23   编辑:Linux編程

C++ 哈弗曼編碼的實現與反編碼

  1. #include<iostream>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. using namespace std;
  5. typedef struct{
  6. int weight;
  7. int parent,lchild,rchild;
  8. int asc;
  9. }HTNode,*HuffmanTree; //定義赫夫曼存儲結構
  10. struct node{
  11. int ASCII;
  12. int n;
  13. };
  14. struct node a[127];
  15. struct node w[127];
  16. //一些全局變量
  17. int count;
  18. HTNode H_T[250];
  19. char ** HC;
  20. char filename[20];
  21. //函數聲明
  22. void menu1(); //菜單1
  23. HuffmanTree HeapSort(HuffmanTree HT,int length); //堆排序
  24. void MinHeapify(HuffmanTree HT, int k,int len); //調整成一個小頂堆
  25. void buildMinHeap(HuffmanTree HT,int len); //建一個小頂堆
  26. void swap(HTNode &t1,HTNode &t2); //交換兩結構體
  27. void savefile(); //把輸入的英文文章保存到文件
  28. void loadfile(); //從文件中讀取文章
  29. HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n); //建立赫夫曼數並存入文件
  30. void BianMa(HuffmanTree HT,int n ); //字符編碼
  31. void BianMa_all(HuffmanTree HT,char**HC,char *filename); //整篇文章編碼
  32. int loadfile2(); //從文件讀入文章
  33. void JieMa(); //解碼
  34. //主函數
  35. void main()
  36. {
  37. char s;
  38. while(s!='0')
  39. {
  40. system("cls");
  41. cout<<"/n/n/n";
  42. cout<<"/t/t/t/t赫夫曼編碼/譯碼器"<<endl<<endl<<endl<<endl<<endl;
  43. cout<<"/t/t/t/t 1.編碼"<<endl<<endl<<endl<<endl;
  44. cout<<"/t/t/t/t 2.譯碼"<<endl<<endl<<endl<<endl;
  45. cout<<"/t/t/t/t 0.退出"<<endl<<endl<<endl<<endl;
  46. cout<<"/t請輸入0—2進行選擇,按回車確認";
  47. cin>>s;
  48. switch(s)
  49. {
  50. case '1': menu1(); break;
  51. case '2':
  52. {
  53. system("cls");
  54. JieMa();
  55. system("pause");
  56. break;
  57. }
  58. }
  59. }
  60. }
  61. //菜單1
  62. void menu1(){
  63. char s;
  64. int i;
  65. int a;
  66. char c;
  67. char fpname[20]="article.txt";
  68. HuffmanTree HT;
  69. while(s!='0'){
  70. system("cls");
  71. cout<<"/n/t/t/t/t編碼界面";
  72. cout<<"/n/n/n/t/t/t/t1.輸入英文文章"<<endl;
  73. cout<<"/n/n/t/t/t/t2.從文件中讀入文章"<<endl;
  74. cout<<"/n/n/t/t/t/t0.返回上一層"<<endl;
  75. cout<<"/n/t請輸入0—2進行選擇,按回車確認";
  76. cin>>s;
  77. switch(s){
  78. case'1':
  79. system("cls");
  80. savefile();
  81. loadfile();
  82. CreateHuffman(HT,w,count);
  83. BianMa(HT,count);
  84. BianMa_all(HT,HC,fpname);
  85. system("cls");
  86. cout<<"出現字符種類共計:";
  87. cout<<count<<endl;
  88. for(i=1;i<=count;i++)
  89. { a=HT[i].asc;
  90. c=(char)a;
  91. cout<<"________________________________________________________________________________"<<endl;
  92. cout<<"/t/t/t字符:";
  93. cout<<c<<endl;
  94. cout<<"/t/t/tASCII碼:";
  95. cout<<a<<endl;
  96. cout<<"/t/t/t頻數:";
  97. cout<<HT[i].weight<<endl;
  98. cout<<"/t/t/t赫夫曼編碼:";
  99. cout<<HC[i]<<endl;
  100. }
  101. cout<<"________________________________________________________________________________";
  102. cout<<"/n/t/t整篇文章的編碼已存入文件“赫夫曼編碼.txt”"<<endl;
  103. system("pause");
  104. break;
  105. case'2':
  106. system("cls");
  107. if(loadfile2())
  108. { system("pause");
  109. return;}
  110. CreateHuffman(HT,w,count);
  111. BianMa(HT,count);
  112. BianMa_all(HT,HC,filename);
  113. system("cls");
  114. cout<<"出現字符種類共計:";
  115. cout<<count<<endl;
  116. for(i=1;i<=count;i++)
  117. { a=HT[i].asc;
  118. c=(char)a;
  119. cout<<"________________________________________________________________________________"<<endl;
  120. cout<<"/t/t/t字符:";
  121. cout<<c<<endl;
  122. cout<<"/t/t/tASCII碼:";
  123. cout<<a<<endl;
  124. cout<<"/t/t/t頻數:";
  125. cout<<HT[i].weight<<endl;
  126. cout<<"/t/t/t赫夫曼編碼:";
  127. cout<<HC[i]<<endl;
  128. }
  129. cout<<"________________________________________________________________________________";
  130. cout<<"/n/t/t整篇文章的編碼已存入文件“赫夫曼編碼.txt”"<<endl;
  131. system("pause");
  132. break;
  133. }
  134. }
  135. }
  136. //交換結構體
  137. void swap(HTNode &t1,HTNode &t2)
  138. {
  139. HTNode m;
  140. m = t1;
  141. t1 = t2;
  142. t2 = m;
  143. }
  144. //從鍵盤輸入文章並保存
  145. void savefile(){
  146. FILE *fp;
  147. char article;
  148. if((fp=fopen("article.txt","w"))==NULL){
  149. printf("打開文件不成功!");
  150. exit(0);
  151. }
  152. cout<<"請輸入英文文章,以#結束:";
  153. getchar();
  154. article=getchar();
  155. while(article!='#'){
  156. fputc(article,fp);
  157. article=getchar();
  158. }
  159. fclose(fp);
  160. }
  161. //從文件讀取文章,並統計字符出現頻數
  162. void loadfile(){
  163. FILE *fp;
  164. char ch;
  165. int i,k,j=0;
  166. count=0;
  167. for(i=0;i<=127;i++) //把所有字符的ascii碼存在數組
  168. { a[i].ASCII=i;
  169. a[i].n=0;
  170. }
  171. if((fp=fopen("article.txt","r"))==NULL){
  172. printf("打開文件不成功!");
  173. exit(0);
  174. }
  175. ch=fgetc(fp);
  176. k=(int)ch;
  177. a[k].n++;
  178. while(!feof(fp)){
  179. ch=fgetc(fp);
  180. k=(int)ch;
  181. a[k].n++;
  182. }
  183. fclose(fp);
  184. for(i=0;i<=127;i++) //統計字符種類總數
  185. {
  186. ch=(char)i;
  187. if(a[i].n){
  188. count++;
  189. }
  190. }
  191. for(i=0;i<=127;i++)
  192. {
  193. for(;j<count;)
  194. {
  195. if(a[i].n)
  196. {
  197. w[j].n=a[i].n;
  198. w[j].ASCII=a[i].ASCII;
  199. j++;
  200. break;
  201. }
  202. else break;
  203. }
  204. }
  205. }
  206. //調整為小頂堆
  207. void MinHeapify(HuffmanTree HT, int k,int len)
  208. {
  209. int left=k*2;
  210. int right=k*2+1;
  211. int large;
  212. int l=len;
  213. large = k;
  214. if (left<=l&&HT[left].weight<HT[large].weight)
  215. large = left;
  216. if (right<=l&& HT[right].weight<HT[large].weight)
  217. large=right;
  218. if (large!=k)
  219. {
  220. swap(HT[k],HT[large]);
  221. MinHeapify(HT,large,l);
  222. }
  223. }
  224. //建立小頂堆
  225. void buildMinHeap(HuffmanTree HT,int len)
  226. {
  227. int i;
  228. for (i=len/2;i>=1;i--)
  229. {
  230. MinHeapify(HT,i,len);
  231. }
  232. }
  233. //堆排序
  234. HuffmanTree HeapSort(HuffmanTree HT,int length)
  235. {
  236. int i;
  237. int l=length;
  238. buildMinHeap(HT,length);
  239. for (i=length;i>= 2;i--)
  240. {
  241. swap(HT[1],HT[i]);
  242. length--;
  243. MinHeapify(HT,1,length);
  244. }
  245. return HT;
  246. }
  247. //建立赫夫曼數
  248. HuffmanTree CreateHuffman(HuffmanTree &HT,struct node *w,int n)
  249. {
  250. int i,m,s1,s2,k1,k2,j,x,a;
  251. FILE *fp,*fp2;
  252. if(n<=1) return HT;
  253. m=2*n-1;
  254. HT=(HuffmanTree)malloc((m+1)*sizeof(HTNode));//0不用
  255. for(i=1,j=0;i<=n;i++,j++)
  256. { HT[i].asc=w[j].ASCII;
  257. HT[i].weight=w[j].n;
  258. HT[i].parent=0;
  259. HT[i].lchild=0;
  260. HT[i].rchild=0;
  261. }
  262. for(;i<=m;i++)
  263. { a=250+i;
  264. HT[i].asc=a;//父親節點的asc可以是大於127的任意值
  265. HT[i].weight=0;
  266. HT[i].parent=0;
  267. HT[i].lchild=0;
  268. HT[i].rchild=0;
  269. }
  270. for(i=1;i<=n;i++){
  271. H_T[i].asc=HT[i].asc;
  272. H_T[i].parent=HT[i].parent;
  273. H_T[i].lchild=HT[i].lchild;
  274. H_T[i].rchild=HT[i].rchild;
  275. H_T[i].weight=HT[i].weight;
  276. }
  277. for(i=n+1,x=n;i<=m;i++,x--)
  278. {
  279. HeapSort(H_T,x);
  280. k1=H_T[x].asc;
  281. k2=H_T[x-1].asc;
  282. for(j=1;j<=127;j++)
  283. {
  284. if(HT[j].asc==k1)
  285. { s1=j;break;}
  286. }
  287. for(j=1;j<=127;j++)
  288. {
  289. if(HT[j].asc==k2)
  290. { s2=j;break;}
  291. }
  292. HT[s2].parent=i;
  293. HT[s1].parent=i;
  294. HT[i].lchild=s1;
  295. HT[i].rchild=s2;
  296. HT[i].weight=HT[s1].weight+HT[s2].weight;
  297. H_T[x-1].asc=HT[i].asc;
  298. H_T[x-1].lchild=HT[i].lchild;
  299. H_T[x-1].parent=HT[i].parent;
  300. H_T[x-1].rchild=HT[i].rchild;
  301. H_T[x-1].weight=HT[i].weight;
  302. }
  303. if((fp2=fopen("count.txt","w"))==NULL) //保存赫夫曼樹
  304. {
  305. cout<<"文件打開不成功!"<<endl;
  306. exit(0);
  307. }
  308. fputc(count,fp2);
  309. if((fp=fopen("HuffmanTree.dat","wb"))==NULL)
  310. { cout<<"文件打開不成功!"<<endl;
  311. exit(0);
  312. }
  313. for(i=1;i<=(2*count-1);i++){
  314. fwrite(&HT[i],sizeof(HTNode),1,fp);
  315. }
  316. fclose(fp);
  317. fclose(fp2);
  318. return HT;
  319. }
  320. //逆向編碼
  321. void BianMa(HuffmanTree HT,int n){
  322. char *cd,temp;
  323. int c,f,i,j,len,p,q;
  324. cd=(char *)malloc(n*sizeof(char));
  325. HC=(char * *)malloc(n*sizeof(char*));
  326. for(i=1;i<=n;i++){
  327. for(c=i,f=HT[i].parent,j=0;f!=0;c=f,f=HT[f].parent,j++)
  328. { if(HT[f].lchild==c) cd[j]='0';
  329. else cd[j]='1';
  330. if(HT[f].parent==0)
  331. cd[j+1]='/0';
  332. }
  333. len=strlen(cd);
  334. for(p=0,q=len-1;p<=q;p++,q--)
  335. {
  336. temp=cd[q];
  337. cd[q]=cd[p];
  338. cd[p]=temp;
  339. }
  340. cd[len]='/0';
  341. HC[i]=(char*)malloc((len+10)*sizeof(char));
  342. strcpy(HC[i],cd);
  343. }
  344. }
  345. //整篇文章編碼,並存入文件
  346. void BianMa_all(HuffmanTree HT,char**HC,char *filename){
  347. char ch;
  348. int k,i;
  349. FILE *fp,*fp2;
  350. char code[100];
  351. if((fp=fopen(filename,"r"))==NULL){
  352. printf("打開文件不成功!");
  353. exit(0);
  354. }
  355. if((fp2=fopen("赫夫曼編碼.txt","w"))==NULL){
  356. printf("打開文件不成功!");
  357. exit(0);
  358. }
  359. ch=fgetc(fp);
  360. k=(int)ch;
  361. while(!feof(fp))
  362. {
  363. for(i=1;i<=count;i++)
  364. {
  365. if(k==HT[i].asc)
  366. strcpy(code,HC[i]);
  367. }
  368. fputs(code,fp2);
  369. ch=fgetc(fp);
  370. k=(int)ch;
  371. }
  372. fclose(fp);
  373. fclose(fp2);
  374. }
  375. void JieMa(){
  376. int i,k,a,t,n=0;
  377. FILE *fp1,*fp2,*fp3;
  378. char ch,c;
  379. HuffmanTree ht;
  380. if((fp3=fopen("count.txt","r"))==NULL) //從文件讀出字符總數
  381. {
  382. printf("打開文件不成功!");
  383. exit(0);
  384. }
  385. n=fgetc(fp3);
  386. ht=(HuffmanTree)malloc(2*n*sizeof(HTNode));
  387. if((fp1=fopen("赫夫曼編碼.txt","r"))==NULL)
  388. {
  389. printf("打開文件不成功!");
  390. exit(0);
  391. }
  392. if((fp2=fopen("HuffmanTree.dat","rb"))==NULL)
  393. { cout<<"文件打開不成功!"<<endl;
  394. exit(0);
  395. }
  396. for(i=1;i<=2*n-1;i++)
  397. fread(&ht[i],sizeof(HTNode),1,fp2);
  398. for(i=1;i<=2*n-1;i++)
  399. {
  400. if(ht[i].parent==0){t=k=i;break;}
  401. }
  402. ch=fgetc(fp1);
  403. while(!feof(fp1)){
  404. if(ch=='0')
  405. {
  406. k=ht[k].lchild;
  407. if(ht[k].lchild==0)
  408. {a=ht[k].asc;
  409. c=(char)a;
  410. printf("%c",c);;
  411. k=t;
  412. }
  413. }
  414. if(ch=='1')
  415. {
  416. k=ht[k].rchild;
  417. if(ht[k].lchild==0)
  418. { a=ht[k].asc;
  419. c=(char)a;
  420. printf("%c",c);
  421. k=t;
  422. }
  423. }
  424. ch=fgetc(fp1);
  425. }
  426. fclose(fp1);
  427. fclose(fp2);
  428. }
  429. //讀取文件中的文章,可自己選擇文件
  430. int loadfile2(){
  431. FILE *fp;
  432. char ch;
  433. int i,k,j=0;
  434. count=0;
  435. for(i=0;i<=127;i++)
  436. { a[i].ASCII=i;
  437. a[i].n=0;
  438. }
  439. cout<<"/n/n/n/t/t/t請輸入你要打開的文件名:";
  440. cin>>filename;
  441. if((fp=fopen(filename,"r"))==NULL){
  442. printf("打開文件不成功!");
  443. return 1;
  444. }
  445. ch=fgetc(fp);
  446. k=(int)ch;
  447. a[k].n++;
  448. while(!feof(fp)){
  449. ch=fgetc(fp);
  450. k=(int)ch;
  451. a[k].n++;
  452. }
  453. fclose(fp);
  454. for(i=0;i<=127;i++){
  455. ch=(char)i;
  456. if(a[i].n){
  457. count++;
  458. }
  459. }
  460. for(i=0;i<=127;i++)
  461. {
  462. for(;j<count;)
  463. {
  464. if(a[i].n)
  465. {
  466. w[j].n=a[i].n;
  467. w[j].ASCII=a[i].ASCII;
  468. j++;
  469. break;
  470. }
  471. else break;
  472. }
  473. }
  474. return 0;
  475. }
Copyright © Linux教程網 All Rights Reserved