演算法導論 貪心演算法之赫夫曼編碼

2021-06-28 12:54:29 字數 3448 閱讀 4814

討論赫夫曼編碼問題,赫夫曼編碼的思想就是變長編碼。變長編碼就是讓字元表中出現概率高的字元的編碼長度盡可能小,而出現概率高的字元的編碼長度相對較長。然後還要遵循字首碼的要求,就是任意乙個編碼都不是其他編碼的字首碼,這樣方便解碼。

對於下表中的字元和相應的出現概率,有對應圖中的編碼樹:

可以比較容易的看出來,每個葉節點就代表乙個字元,從根節點到葉節點走過的路徑拼接起來,就代表這個字元的編碼,比如f是1100,e是1101,而f和e是深度最深的節點也是概率最小的兩個節點。這也就是我們要求的赫夫曼編碼形式。這種最優的編碼形式,總是一顆滿的二叉樹。

算導上有大量的篇幅來論證用貪心演算法,每次選擇概率最小的兩個節點來,可以完成赫夫曼編碼。這裡只說實現方法。

由於每次都要找出出現概率最小的那個節點,彈出來,並刪掉,所以我們可以使用最小優先佇列來做。注意一點是,編碼樹的葉子節點個數等於字元的個數,而內部節點個數則等於字元的個數減去一,所以求內部節點的迴圈只需要n-1次即可,n為字元數。

小根堆操作:

#include #include using namespace std;

#define max_index 11

struct node

};//陣列從1號元素開始算起

int left_child(int i)

int right_child(int i)

int parent(int child)

void swap(node* a, node* b)

void print_heap(node* a, int len)

cout << endl;}/*

* 將乙個左右子樹都是小根堆的堆轉化成小根堆

*/void min_heapify(node heap, int root, int n)

if (r <= n && heap[min].freq > heap[r].freq)

if (min != root) }/*

* 構建乙個小根堆

*/void build_min_heap(node heap, int n)

}

最小優先佇列操作:

/*

* 最小優先佇列要實現的操作:

* * ①insert(s,x)

* * ②minimum(s)

* * ③extract_min(s)

* * ④decrease_key(s,x,k)

* */

/* * 最小優先佇列

*/struct min_priority_queue

};/*

* 返回最小元素

*/node* heap_minimum(min_priority_queue* mpq)

return mpq->min_heap + 1;}/*

* 彈出並移除最小的元素

*/node* heap_extract_min(min_priority_queue* mpq)

//這裡必須要新建乙個節點返回去,如果直接返回原節點,則會導致後面insert的時候,左右孩子的指標指向的內容發生變化

//新建乙個節點

node* min = new node();

//複製最小節點的內容到新建節點,最後將新建的節點的指標返回

*min = *(mpq->min_heap + 1);

swap(mpq->min_heap + 1, mpq->min_heap + mpq->len);

//刪除彈出的節點,防止記憶體洩露

delete (mpq->min_heap + mpq->len);

//將最後乙個節點從堆中去掉

(mpq->len)--;

//重新維護小根堆的性質

min_heapify(mpq->min_heap, 1, mpq->len);

//返回min

return min;}/*

* 把優先佇列中原來為x的元素的值,換成k,並維護最小堆的性質

*/void heap_decrease_key(min_priority_queue* mpq, int i, node* n)

mpq->min_heap[i].freq = n->freq;

while (i >= 1 && mpq->min_heap[i].freq < mpq->min_heap[parent(i)].freq) }/*

* 插入元素

*/void heap_insert(min_priority_queue* mpq, node* n)

/* * 列印節點陣列

*/void print_node_array(node* n_arr, int max_index)

cout << endl;

}

赫夫曼編碼形成編碼樹:

//哈夫曼編碼樹

struct huffman_tree

};/*

* 赫夫曼編碼,返回編碼樹的頭結點

*/void huffman(min_priority_queue* mpq,huffman_tree* t)

// return heap_extract_min(mpq);

t->root=heap_extract_min(mpq);}/*

* 中序遍歷編碼樹

*/void print_coded_tree(node* root) }/*

* 刪除編碼樹的節點

*/void delete_coded_tree(node* root)

}int main() ;

node node_arr[max_index + 1];

for (int i = 0; i < 12; i++)

//新建乙個最小優先佇列物件,應用上面的陣列

min_priority_queue* mpq = new min_priority_queue(node_arr, max_index);

huffman_tree* t = new huffman_tree();

huffman(mpq,t);

print_coded_tree(t->root); //10個內部節點和原來的11個葉子節點,一共21個節點

delete_coded_tree(t->root);

return 0;

}

形成小根堆耗時o(n),而在huffman(min_priority_queue* mpq,huffman_tree* t)中的n-1次for迴圈,每次for 都要做常數次維護小根堆性質的操作,每次的複雜度為o(lgn),所以總共是:o(n+n*lgn)=o(nlgn)。

小白高階之貪心演算法 赫夫曼編碼

赫夫曼編碼是根據字元的使用頻率對字元進行編碼的一種編碼方法,其用於壓縮資料的效果非常好。一般用二叉樹表示赫夫曼編碼,使用頻率越低的字元,其深度越大。其中q表示乙個按頻率從小到大排序的優先佇列。在赫夫曼編碼的表示中,通常用字首碼的表達方法。字首碼即沒有任何碼字是其他碼字的字首,其作用是簡化解碼過程。用...

貪心演算法 赫夫曼編碼問題(Huffman)

赫夫曼編碼是一種廣泛用於資料壓縮的問題,該演算法的主要優勢在於節約了儲存和傳輸成本。舉乙個例子 假設要傳輸的資料為 那麼傳輸成本就是 45 3 30 3 29 3 10 3 8 3 5 3 381個字元 先合併最小頻率的2個字元對應的子樹,計算合併後的子樹的頻率 重新排序各個子樹 重複步驟1 重複步...

演算法導論之貪心演算法

參考 下面請看示例題 有n個商品,每個商品的重量為wi,為 pi,現有乙個揹包,最多能裝 的重量 其中 0 i問 怎樣裝能使包中裝入的商品價值最高 對於每個商品可以只裝該商品的一部分 偽 引數分別為 n 物品數 m 揹包最多能裝的重量 v 價值陣列 w重量陣列 void knapsack int n...