• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ハフマン符号のプログラム)

ハフマン符号プログラムの作成と圧縮率の測定

quenistaの回答

  • quenista
  • ベストアンサー率28% (122/425)
回答No.4

全体のソースでは無い様ですし、全てのロジックを確認した訳では無いので、一つ一つの動作は御自分で確認して見て下さい。 /* 各符号から上の要素番号をたどれなくなるまでたどりながら、自分が左側にいたら0を右側にいたら1を並べていくと、その逆順がその記号のハフマン符号となる。*/ /* これを各符号に対して行い,それぞれのハフマンコードを2次元配列Hcodeに格納する。 /* 例えば,記号('A' = 65)のハフマンコードが"011"の場合 Hcode[65][0] = 0; Hcode[65][1] = 1; Hcode[65][2] = 1; */ 先ず、Hcode[][]の配列がこのプログラム中には無いですが、他に有るのですね? parentに値が有る間(0x100以外の時)は、何処かの分岐木の下で有ると言う事です。 このソースの場合、デーブル・チェーン構造になってますので、それを辿って下さいと言う事です。 例えば、あるコード一つで見てみると、code[(コード)].parentの中に上位のコード番号が入っています。 そのコードに戻ると、.left或いは.rightの中にコード番号が入っています。 つまり、 search_code=code; parent_code=code[code].parent; while(code[code].parent!=0x100){ if(code[code[parent_code].parent].left==parent_code){ Hcode[search_code][0]=0; } else{ Hcode[search_code][0]=1; } parent_code=code[parent_code].parent; hcode_count[search_code]++; } と言う様な事を、256文字分行えば良いと思います。 hcode_countは、後で使う為に追加しました。(0初期化) fclose(fp2); ↑put_bit関数の中が解らないのですが、データを書き込んでからクローズした方が良いのでは? /* (d) */ /* もう一度ファイルを読み込み,その記号に対応するハフマンコードをファイルに書いていく。 */ /* (d)の書き込みにはput_bit関数を使って書き込むことができる。 */ /* また注意点として,put_bit関数は8bitたまった時点でファイルに書き込みを行うので,ファイルの記号をすべて処理した時に,最後に8bitたまっていない場合残りのbitに'0'を書き込む必要がある。*/ ファイルのオープンは解って居られると思いますので、他の部分だけ...。 上記のロジックで、Hcodeにハフマンコードが、hcode_countにハフマンコードのビット数が入ってます。 それを、Fileに書き出せば良いのです。 又、書き出したビット数を数えて置くと、空白を埋めるビット数は解ると思います。 bit_count=0; while((i=fgetc(fp1))!=EOF){ for(hcode_count[i]-1;loop>=0;loop++){ bit_put(Hcode[search_code][loop]); bit_count++; } } for(loop=0;loop<(bit_count&0xF);loop++) bit_put(0); てな感じですかね? 最後に、ファイルのクローズを忘れずに...。 一つ一つの動きを良く理解出来ますよう、頑張って下さいね。

satoru00
質問者

補足

search_code=code; parent_code=code[code].parent; while(code[code].parent!=0x100){ if(code[code[parent_code].parent].left==parent_code){ Hcode[search_code][0]=0; } else{ Hcode[search_code][0]=1; } parent_code=code[parent_code].parent; hcode_count[search_code]++; } CODE search_code; int parent_code; と定義すると,parent_code=code[code].parent; のところで error C2107: ポインタでない式に、添字が使われました。 error C2231: '.parent' : 左のオペランドが 'struct' へのポインタです。'->' を使用してください。 とエラーになってしまいました。 int *parent_code; と定義すると,また parent_code=code[code].parent; のところで error C2107: ポインタでない式に、添字が使われました。 error C2231: '.parent' : 左のオペランドが 'struct' へのポインタです。'->' を使用してください。 warning C4047: '=' : 間接参照のレベルが 'int *' と 'int ' で異なっています。 とエラーになってしまいました。 どうすればよいのでしょうか。 また,hcode_countはどのように定義すればよいのでしょうか。とりあえず,いまの段階までのプログラムを送ります。よろしかったらデバックしてください。 /**************************************************** ハフマン符号 ****************************************************/ #include <stdio.h> #include <stdlib.h> #define SIZE 256 /* 二分木 */ typedef struct _node { unsigned int count; /* 頻度 */ int parent; /* 上の要素番号 */ int left; /* 左側を 0 */ int right; /* 右側を 1 */ } CODE; CODE code[2*SIZE+1]; CODE *search_code; int mozi_count[SIZE]; int *parent_code; int Hcode[SIZE][SIZE]; int hcode_count[SIZE]; /* ? */ int bit_count; FILE *fp1,*fp2; void put_bit(unsigned int bit); int main() { int i, total = 0; char input_fname[] = "read.txt"; char output_fname[] = "out2.txt"; int min1, min2, freeNode, root; /* (a) */ /* データの初期化 */ for( i = 0; i < 2*SIZE+1; i++ ) code[i].count = 0; for( i = 0; i < SIZE; i++ ) mozi_count[i] = 0; /* 文字頻度をカウント */ if((fp1 = fopen(input_fname,"r")) == NULL){ fprintf(stderr,"%s: can't opn file\n", input_fname); exit(1); } while((i=fgetc(fp1)) !=EOF){ code[i].count++; mozi_count[i]++; total++; } /* (b) */ /* ハフマン符号を生成する */ /* ハフマン木をつくる */ code[2*SIZE].count = 0x100; /* 番兵 */ for (freeNode = SIZE; ; freeNode++) { min1 = min2 = 2*SIZE; for (i = 2*SIZE-1; i >= 0; i--) if (code[i].count > 0) { if (code[i].count < code[min1].count) { min2 = min1; min1 = i; } else if (code[i].count < code[min2].count) min2 = i; } if (min2 == 513 - 1) break; code[freeNode].count = code[min1].count + code[min2].count; code[freeNode].left = min1; code[freeNode].right = min2; code[min1].parent = code[min2].parent = freeNode; code[min1].count = code[min2].count = 0; } root = min1; search_code=code; parent_code=code[code].parent; while(code[code].parent!=0x100){ if(code[code[parent_code].parent].left==parent_code){ Hcode[search_code][0]=0; } else{ Hcode[search_code][0]=1; } parent_code=code[parent_code].parent; hcode_count[search_code]++: } /* (c) */ if((fp2 = fopen(output_fname,"w")) == NULL){ fprintf(stderr,"%s: can't opn file\n", output_fname); exit(1); } for(i=0;i<SIZE;i++){ fprintf(fp2,"%d ", mozi_count[i]); } bit_count=0; while((i=fgetc(fp1))!=EOF){ for(hcode_count[i]-1;loop>=0;loop++){ put_bit(Hcode[search_code][loop]); bit_count++; } } for(loop=0;loop<(7-(bit_count&0xF));loop++) put_bit(0); fclose(fp1); fclose(fp2); } void put_bit(unsigned int bit) { static unsigned int mask = 0x80; static unsigned int byte = 0x00; if(bit != 0){ byte = byte | mask; } mask = mask >> 1; //8bit貯まったか if(mask == 0x00){ if(fputc(byte,fp2) == EOF){ printf("Can't write \n"); exit(1); } mask = 0x80; byte = 0x00; } } /* end of file */ /******************* 関数put_bit 引数として,0,または1を渡すと,1bitづつファイルに書き込む (ファイルポインタはグローバル変数として用意する) 実際には,8bit貯まった時点でbyte単位で出力する *******************/ void put_bit(unsigned int bit) { static unsigned int mask = 0x80; static unsigned int byte = 0x00; if(bit != 0){ byte = byte | mask; } mask = mask >> 1; //8bit貯まったか if(mask == 0x00){ if(fputc(byte,fpcode) == EOF){ printf("Can't write \n"); exit(1); } mask = 0x80; byte = 0x00; } } /*使用例(100bitを書き込む)(配列array[100]に0,1が格納されているとする)*/ /*for(i = 0;i < 100;i++)                 */ /* put_bit(array[i]);            */ /*for(i = 0;i < 7;i++) put_bitは8bit単位で書き込むので最後の   */ /* put_bit(0); bitを書き込むために最後の2行が必要となる。 */ /*(この例の場合は,残った4bitを書き込めばよいので,7でなく4でもできる) */

関連するQ&A

  • 2元ハフマン符号化プログラムが作れなくて困っています。

    以下のC言語のプログラムを作成出来る方、いらっしゃいましたらソースファイルを載せて下さい。 2元ハフマン符号化プログラム:具体的な無記憶情報源が入力されたときに、そのハフマン記号を出力される ご教授よろしくおねがいします

  • ハフマン符号化について

    ハフマン符号化についてですが、圧縮のためであるので、 ハフマン符号化を行いなさいといわれた場合において、 木構造の1と0の取り方はどんなものでも良いのでしょうか? 生起確率が A:0.12 B:0.12 C:0.28 D:0.48 であった場合、 添付画像の青い文字のように符号化を行い、 A:000 B:001 C:01 D:1 としても、赤い文字のように符号化を行い、 A:111 B:110 C:10 D:0 としても、どちらでもハフマン符号化としては正解なのでしょうか? また、0と1を階層ごとにランダムにとっても問題ないのでしょうか?

  • ブロックハフマン符号化プログラムの作成

    現在学校の研究で「ブロック(n次拡大情報源)ハフマン符号化」プログラムをC言語で作成しています。 これは、通常のハフマン符号化でデータ1個ごとに出現頻度を調べてそれぞれにハフマン符号を割り当てるところを、ファイル中で隣り合うデータ2個(あるいは3個、4個、・・・n個)を一かたまりと見なし、それぞれの出現頻度を調べてハフマン符号を割り当てる、というものです。 通常のハフマン符号化は以前作成したことがあるのですが、これをどのようにして上記のようなプログラムに改変すればいいのかわかりません。 ちなみに、データのバッファリングは以下のようにし、 #define BUFFER_SIZE 102400 unsigned char buffer[BUFFER_SIZE]; (中略) int i,c; i = 0; while(i < BUFFER_SIZE && (c = fgetc(fp_i)) != EOF) { buffer[i] = c; i++; } 各データの出現頻度は以下のようにして調べています。 #define N 256 (中略) int hist[N * 2]; for(i = 0;i < (N * 2);i++) hist[i] = 0; for(i = 0;i < size;i++) hist[data[i]]++; ※data[i]は前述のbuffer[i]、sizeは前述のi(圧縮対象データのファイルサイズ)です。 やはり、バッファリングに使う配列をもう少しサイズの大きい型で宣言するとこから始めるべきでしょうか? ご教授お願いします。

  • ハフマン符号化の問題を解くプログラム

    ハフマンの符号化の問題を解くプログラムをC言語(コンソールアプリケーション)で作りたいのですが ファイルの圧縮とかをするプログラムはいろいろなサイトにあったのですが、 簡単な情報源を与えられたものを符号化するプログラムで参考にできるようなサイトは見つかりませんでした。 誰かプログラムの例を教えていただけないでしょうか? 入力する例はつぎのようなものです S=(a1, a2, a3, a4, a5, a6/0.35, 0.15, 0.15, 0.20, 0.10, 0.05)

  • VB2008  ハフマン符号のプログラム

    ハフマン符号のプログラムソースを探しています! http://www.ccad.sist.chukyo-u.ac.jp/~mito/syllabi/daisu/huffman/index.htm#TOP に、Visual C++で作成されたプログラムがあります。 これを、VB2008に書きかえることのできる方いらっしゃいませんか? 符号化と複合化を別に(コントロールのボタンを用いて「符号化」、「複合化」とできるなど)していただければありがたいです。 ぜひ、よろしくお願いします!!

  • ハフマン符号化による圧縮

    1と0でできたN×Nの行列 例えば 0 1 1 1 1 0 0 1 1 0 0 0 1 1 0 0 1 1 1 0 0 1 1 0 1 1 0 0 1 0 0 0 1 1 0 0 というような行列を ___ |01|1 1 1 0 |01|1 0 0 0  ̄ ̄ ̄  1 1  0 0 1 1  1 0  0 1 1 0  1 1  0 0 1 0  0 0  1 1 0 0 このように4ビットごとに分けてハフマン符号化による圧縮を行うプログラムを作りたいと考えていますが、よくわかりません。どなたか教えてください。 また四角で囲んだところは0101と考えていいそうです。

  • JPEG画像にさらにハフマン符号化をかけると・・・?

    現在卒業研究の一環で「なぜJPEG画像にハフマン符号化をかけてもほとんど圧縮できないのか?」というテーマについて考えています。 研究の過程でハフマン符号化プログラムを組み、様々な種類のJPEG画像を圧縮し、圧縮率を検証しました。その結果、フルカラー画像もグレースケール画像もほとんど圧縮できませんでしたが、単純な線画(白地に黒い線を数本引いただけのもの)の画像のみ元の2割程度まで圧縮できました。 最初はやはりJPEG画像には元からハフマン符号化がかかっているから圧縮率が悪いのかな、とも思ったのですが、『単純な線画の画像のみ元の2割程度まで圧縮できている』ので、単に「元からハフマン符号化がかかっているから」では説明がつかないように思えます。 おおまかで構いませんので、これの原因について皆様のご意見をお聞かせください。よろしくお願いします。

  • ハフマン符号 情報源記号と符号語の対応表

    S=(a1 0.15 , a2 0.3 , a3 0.05 , a4 0.2 a5 0.25 , a6 0.05) この情報源Sに対するハフマン符号をハフマン符号の木を構成することにより、情報源記号と符号語の対応表を示せ。 という問題があるのですが、これについて質問です。 符号の木は、これらのa1~a6が二進数でどうなるのかがわからないと書けないと思うのですが、この問題にはその二進数の割り当てがしてありません。 これは最初からa1ならば0やa2ならば01という風に決まっていたり、また、勝手に割り当ててもいいのでしょうか? どなたかご教授お願いします。

  • Huffmannのプログラム

    Huffman法のプログラムをC言語で作成する上で、Huffman木の作成と符号化のところがなかなか出来なくて困っています。 英文を読み込んで、各文字の出現回数を数えて、というところまではいけるのですが… 教えていただけませんか?(特にHuffman木を作るところ) Huffman法の仕組みは分かるのですが…

  • Huffman木の作成の問題

    Huffman法のプログラムを作成する上で、Huffman木の作成と符号化のところがなかなか出来なくて困っています。 英文を読み込んで、各文字の出現回数を数えて、というところまではいけるのですが… 教えていただけませんか?