05-樹9 Huffman Codes
構造哈夫曼樹
為了實現哈夫曼演算法,可以利用最小堆來儲存最優解點。因此可以通過刪除最小堆的根,並插入兩個和來實現哈夫曼演算法。因此在最小堆結構中的DATA應是指向哈夫曼樹的指標陣列。刪除最小堆的根時也應當保留刪除兩個節點指向的哈夫曼樹,並且做到在返回時左子樹和右子樹也都不為NULL。直到堆中只有一個有效元素時就說明一棵哈夫曼樹生成完成了。:happy:
最小堆與哈夫曼的結構
typedef struct HuffmanTree * TNode;
typedef struct Heap * MinHeap;
struct HuffmanTree{
int weight;
TNode Left;
TNode Right;
};
struct Heap{
TNode * Data;
int Size;
int MaxSize;
};
這裡是最基本的最小堆和哈夫曼結構的構建。?
注意⚠️:在後面對heap中的Data建立空間時應該首先對Data進行建立Data = (TNode *)malloc(sizeof(TNode) * (N + 1))
再對Data中的每一項進行建立空間的操作Data[i] = (TNode)malloc(sizeof(struct HuffmanTree))
。這應該是初學C語言才會出錯的點,但是當時寫程式的時候真的沒看出來,還是看了其他部落格上的標準程式碼才發現了錯誤。
最小堆的插入與刪除操作
插入操作
int InsertHeap(MinHeap H, int a)
{
int i = ++H->Size;
for(; H->Data[i/2]->weight > a; i /= 2)
H->Data[i] = H->Data[i/2];
H->Data[i] = (TNode)malloc(sizeof(struct HuffmanTree));
H->Data[i]->weight = a;
H->Data[i]->Left = H->Data[i]->Right = NULL;
return i;
}
唯一不同的地方就是Data的型別改變了, 並且再插入操作中要設定哈夫曼根節點指向的左子樹和右子樹均為空。在後續實現哈夫曼演算法時會在其他函式中更新指向的左子樹和右子樹的值,因此需要將本來返回的null函式值要改成堆陣列的index。看到哈夫曼樹的構建就會清楚啦!
刪除操作
TNode DeleteHeapMin( MinHeap H )
{
int Parent, Child;
TNode MinItem = H->Data[1];
TNode tmp = H->Data[H->Size--];
for(Parent = 1; Parent * 2 <= H->Size; Parent = Child)
{
Child = Parent * 2;
if((Child != H->Size) && (H->Data[Child]->weight > H->Data[Child + 1]->weight))
Child++;
if(tmp->weight <= H->Data[Child]->weight)
break;
else
H->Data[Parent] = H->Data[Child];
}
H->Data[Parent] = tmp;
return MinItem;
}
習慣上還是將根節點儲存在第一個元素。這樣比較好記憶和操作。
之前寫的版本竟然還是隻傳了哈夫曼樹中的weight,我怕不是個傻子。
哈夫曼樹的構建
TNode Huffman(MinHeap H)
{
while(H->Size > 1)
{
TNode A, B;
A = DeleteHeapMin(H);
B = DeleteHeapMin(H);
int f = InsertHeap(H, A->weight + B->weight);
H->Data[f]->Left = A;
H->Data[f]->Right = B;
}
return H->Data[1];
}
當堆只有一個有效節點的時候就說明所有哈夫曼樹的節點都整合到了一起,說明哈夫曼樹就構建好啦!
計算WSL
int WPL( TNode T, int Depth)
{
if(T->Left == NULL && T->Right == NULL)
return Depth * T->weight;
else
{
int leftWPL = 0, rightWPL = 0;
if(T->Left) leftWPL = WPL(T->Left, Depth + 1);
if(T->Right) rightWPL = WPL(T->Right, Depth + 1);
return rightWPL + leftWPL;
}
}
利用遞迴的思想計算WSL。這學期一直在看Standard ML,感覺寫C的遞迴已經有點不適應了。
另:判斷某組編碼是否為最優編碼
某組編碼為最優編碼的條件有三個:
- 有最小權值
- 具有唯一性:只是路徑的節點不能表示為某一元素,即每一個代表編碼的節點不能有左子樹和右子樹
- 不能有度為1的點。
為什麼需要通過構造哈夫曼樹來判斷某組編碼是否為最優編碼呢?這是我在看浙大mooc時的一個疑問。後來我直到,這是為了得到該組編碼的WSL。WSL是首先判斷某組編碼是否為最優編碼的第一個條件。
還有另一個重要的條件就是每一個代表編碼的節點應該沒有左子樹或者右子樹,並且在找到該編碼的路徑中不能經過已經有值的節點(兩個條件實際上是等價的,然而為了解決這個問題需要在程式中考慮到這兩個問題)。第一個方面是先考慮的,先走的步長長的編碼,後一個方面是後給出的,走的步長短的編碼。所以在編寫程式的時候一定要多方謎案考慮,比如我就因為判斷的是“某節點沒有左子樹並且沒有右子樹”而出現答案錯誤。
int judge(int N, int f[], int CodeLen)
{
int flag = 1, w = 0;
TNode T = (TNode)malloc(sizeof(struct HuffmanTree));
T->Left = T->Right = NULL;
T->weight = -1;
for(int i = 0; i < N; i++)
{
char c, s[N + 1];
getchar();
scanf("%c %s", &c, s);
int length = strlen(s);
if(length > N) flag = 0;
w += length * f[i];
int j = 0;
TNode tmp = T;
while(s[j] != '\0')
{
if(s[j] == '0')
{
if(!tmp->Left)
{
tmp->Left = (TNode)malloc(sizeof(struct HuffmanTree));
tmp->Left->weight = -1;
tmp->Left->Left = tmp->Left->Right = NULL;
tmp = tmp->Left;
}
else
{
if(tmp->Left->weight != -1) {
flag = 0;
tmp = tmp->Left;
}
else
tmp = tmp->Left;
}
}
else
{
if(!tmp->Right)
{
tmp->Right = (TNode)malloc(sizeof(struct HuffmanTree));
tmp->Right->weight = -1;
tmp->Right->Right = tmp->Right->Left = NULL;
tmp = tmp->Right;
}
else
{
if(tmp->Right->weight != -1) {
//printf("**warning**\n");
flag = 0;
tmp = tmp->Right;
}
else
tmp = tmp->Right;
}
}
j++;
}
tmp->weight = i;
if(tmp->Left != NULL || tmp->Right != NULL)
flag = 0;
}
if(w > CodeLen)
flag = 0;
free(T);
return flag;
}
相關文章
- SICP:符號求導、集合表示和Huffman樹(Python實現)符號求導Python
- LRC codes理解
- System Error CodesError
- 2.13.5 DBCA Exit Codes
- SAP Workflow Tcodes ( Transaction Codes )
- 05-表操作
- SAP Important note on transporting tax codesImport
- 量子糾錯碼——Stabilizer codes
- 05-待填坑...
- pandas 05-變形
- 05-行內函數函數
- 05-常用選擇器
- 05-資料型別資料型別
- 『dfn、樹剖雜項』Day9
- 基於Huffman樹的層次化Softmax:面向大規模神經網路的高效機率計算方法神經網路
- [JRKSJ R9] 在相思樹下 III
- 05-快速理解SparkSQL的DataSetSparkSQL
- qoj9230 Routing K-Codes 題解
- 【linux】驅動-9-裝置樹外掛Linux
- 機器學習 Day 9 | 決策樹基礎機器學習
- 貪心演算法——Huffman 壓縮編碼的實現演算法
- DDD | 05-什麼是倉儲層
- Matplotlib 05-樣式色彩秀芳華
- 0二叉樹簡單 牛客NC9.二叉樹
- T9-POJ 1415 模擬輸入法+字典樹
- 05-自己建立mapmodel自定義遷移方式
- 05-論說文:審題與立意(2)
- 05-論證基礎:綜合運用
- 05-無約束優化演算法優化演算法
- Vue 框架-05-動態繫結 css 樣式Vue框架CSS
- 手寫 Hibernate ORM 框架 05-基本效果測試ORM框架
- awk基礎05-自定義函式和指令碼函式指令碼
- Python2+Selenium入門05-關於WebElement類PythonWeb
- 計算機實驗室之樹莓派:課程 9 螢幕04計算機樹莓派
- 題解:洛谷 P10878 [JRKSJ R9] 在相思樹下 III
- 【題解】Solution Set - NOIP2024集訓Day9 樹上問題
- 微信小程式開發05-日曆元件的實現微信小程式元件
- 9/9