哈夫曼之謎

2022-08-01 10:39:14 字數 2448 閱讀 1084

這篇部落格裡我先是介紹了什麼是哈夫曼樹,然後給出了如何去構造其的演算法,接著引進哈夫曼編碼,最後拓展到了動態哈夫曼樹。廢話不多說,開始吧!

要介紹哈夫曼樹,得先了解幾個概念:

講道理,假設給你一篇文件,裡面全是a,b,c,d,e,你統計出來它們的出現頻率,如下:

字元概論

a0.12

b0.4

c0.15

d0.08

e0.25

字母是以ascii碼儲存的,乙個字元8位,在知道概率的情況下,這種儲存方式很浪費硬碟空間,設計乙個編碼方式,讓它們在最小空間內儲存,且具有字首性(任何乙個字元的編碼不會是別的字元的編碼字首),這時候哈夫曼編碼應運而生。

只需要將字元概率看成權值即可,然後構造哈夫曼樹,在左子樹的邊上標記'0',右標記'1',則每個字元的路徑上標記相連即編碼。

簡單**實現:

//假設c是乙個n個字元的集合,其中每個字元c屬於c且c.freq給出它們的概率,q是以freq比較的最小優先佇列

huffman(c)

靜態哈夫曼編碼最大的缺點是它需要對原始資料進行兩遍掃瞄:第一遍統計字元頻率,第二遍根據頻率得到的哈夫曼樹對原始資料進行編碼。而動態哈夫曼樹對t+1個字元的編碼是根據前面t個字元而來,不需要重新進行掃瞄。

構造規則:

例如,已經壓縮完32個字元

接著壓縮乙個'b',先要調整:

接著更新結點:

;node * root = new node; // 定義哈夫曼樹的根節點

vectorweight; //儲存同權重中最大序號的節點

vectorleaf; //儲存所有葉子節點

//初始化root和weight

void init()

//引數化初始化nyt節點

void init_nyt(node * nyt)

//根到葉節點路徑上所有節點權重加一

void increase(node * leaf)

root->weight += 1;

}//更新weight

void change_weight(node * present)

if(!flag)

weight.push_back(tmp);

tmp = tmp->parent;}}

}//返回同權重最大節點

node * max(int wei)

}for(;i < num;i++)

return max;

}//交換節點以便維持哈夫曼樹性質

void exchange(node * present)

else

p = tmp->parent;

tmp = p;}}

}//編碼

void encode(ofstream & out)

num2 = static_cast(code.size());

for(int j=0;j> str;

node * p;

node * q; //記錄當前的nyt節點

node * nyt; //即nyt節點

node * present; //記錄當前節點

int i = 0;

bool flag;

while(str[i] != '\0')

}if(!flag)

else

present = leaf[j];

exchange(present);

increase(present);

change_weight(present);

encode(out);

out << endl;

i ++;}}

int main()

哈夫曼編碼 哈夫曼樹

1.定義 哈夫曼編碼主要用於資料壓縮。哈夫曼編碼是一種可變長編碼。該編碼將出現頻率高的字元,使用短編碼 將出現頻率低的字元,使用長編碼。變長編碼的主要問題是,必須實現非字首編碼,即在乙個字符集中,任何乙個字元的編碼都不是另乙個字元編碼的字首。如 0 10就是非字首編碼,而0 01不是非字首編碼。2....

哈夫曼樹 哈夫曼編碼

定義從a結點到b結點所經過的分支序列為從a結點到b結點的路徑 定義從a結點到b結點所進過的分支個數為從a結點到b結點的路徑長度 從二叉樹的根結點到二叉樹中所有結點的路徑長度紙盒為該二叉樹的路徑長度 huffman樹 帶權值路徑長度最小的擴充二叉樹應是權值大的外界點舉例根結點最近的擴充二叉樹,該樹即為...

哈夫曼編碼 哈夫曼樹

哈夫曼樹是乙個利用權值進行優化編碼的乙個比較奇怪的樹,他的實現比較簡單,用途也比較單一。哈夫曼樹的實現,實現要求 通過哈夫曼樹可以保證在編碼過程中不會出現例如 1000和100這樣的編碼規則,否則就會編碼失敗,因為1000和100在某些情況下的編碼會一模一樣。通過哈夫曼樹可以保證權值大的值進行編碼時...