【資料結構】哈夫曼樹的建立與基礎應用
根據給定的n個權值生成哈夫曼二叉樹,輸出赫夫曼編碼及進行譯碼
哈夫曼樹的結點的結構體
struct huffmannode//哈夫曼樹結點的結構體
{
int weight;//結點權重
int parent;//父結點
int leftchild;//左子樹
int rightchild; //右子樹
};
建樹
void creat_tree(huffmannode tree[], int w[],int n)//建哈夫曼樹
{
int node1 = 0, node2 = 0;
for(int i=0;i<2*n-1;++i)//初始化結點
{
tree[i].parent = -1;
tree[i].leftchild = -1;
tree[i].rightchild = -1;
}
for(int i=0;i<n;++i)//將輸入的結點值輸入哈夫曼樹
{
tree[i].weight = w[i];
}
for(int k=n;k<2*n-1;++k)
{
select(tree,k,node1,node2);//找到最小結點,次小結點
tree[k].weight = tree[node1].weight + tree[node2].weight;//生成新結點,權重為兩結點之和
tree[node1].parent = k;//最小結點父結點為新結點
tree[node2].parent = k;//次小結點父結點為新結點
tree[k].leftchild = node1;//新結點左子樹為最小結點
tree[k].rightchild = node2;//新結點右子樹為次小結點
}
}
思路:將最開始輸入的結點放入待選擇結點列表,不斷選擇權重最小與權重次小的結點,用他們生成新的結點,並使新結點成為他們的父結點,再將新結點也放入待選擇的結點列表,直至新生成了n-1個結點,此時該父結點也為根結點,最後這2*n-1個結點就成為了哈夫曼樹。
建樹時使用的查詢函式
void select(huffmannode tree[],int k,int &node1,int &node2)//在尚未使用的結點中,找到兩個權重最小的結點
{
node1 = -1, node2 = -1;//初始化兩個沒有父結點的最小結點的位置
int minweight = 1e8;//初始化最小權重
for(int i=0;i<k;++i)
{
if(tree[i].parent==-1)//沒有父結點
{
if(tree[i].weight<minweight)//小於最小權重
{
minweight = tree[i].weight;//更新最小權重
node1 = i;//更新最小點位置
}
}
}
minweight = 1e8;//初始化權重
for(int i=0;i<k;++i)
{
if(tree[i].parent==-1&&i!=node1)//沒有父結點且不是最小結點
{
if(tree[i].weight<minweight)//更新次小結點
{
minweight = tree[i].weight;
node2 = i;
}
}
}
}
思路:兩遍遍歷,第一遍找到未連線父結點且權重最小的點,將其標記為node1;第二遍,找到除了node1之外,未連線父結點且權重最小的點,將其標記為node2.
生成結點對應的哈夫曼編碼
void form_code(huffmannode tree[],int n)//生成哈夫曼編碼
{
int cur, parent, start;
string huffcode;
for(int i=0;i<n;++i)//遍歷n個輸入的結點
{
cur = i;
parent = tree[i].parent;
while(parent!=-1)//當沒有到達根結點,向上尋找父結點
{
if(tree[parent].leftchild==cur)//如果當前結點是左子樹
{
huffcode = '0' + huffcode;//在哈夫曼編碼前加0
}
else
{
huffcode = '1' + huffcode;//加1
}
cur = parent;//更新當前結點
parent = tree[parent].parent;//更新父結點
}
code[tree[i].weight] = huffcode;//將生成的哈夫曼編碼用map儲存
translate[huffcode] = ch[i];//將哈夫曼編碼對應的值儲存
huffcode.clear();//清空哈夫曼編碼
}
}
思路:分別以n個輸入的結點為起點,不斷向上尋找它的父結點,直到父結點到達根結點,如果對於父結點來講,當前結點是左子結點,則在已生成的哈夫曼編碼前加上0,如果是右子結點,則加上1。在生成完整編碼後用map容器儲存編碼。
完整程式碼
#include<iostream>
#include<cstdio>
#include<string>
#include<map>
using namespace std;
const int Size = 1e4+5;
struct huffmannode//哈夫曼樹結點的結構體
{
int weight;//結點權重
int parent;//父結點
int leftchild;//左子樹
int rightchild; //右子樹
};
map<int,string> code;//儲存值對應的哈夫曼編碼
map<string,char> translate;//儲存哈夫曼編碼對應的值
map<char,int> alp;
char ch[105];
int w[105];
void select(huffmannode tree[],int k,int &node1,int &node2)//在尚未使用的結點中,找到兩個權重最小的結點
{
node1 = -1, node2 = -1;//初始化兩個沒有父結點的最小結點的位置
int minweight = 1e8;//初始化最小權重
for(int i=0;i<k;++i)
{
if(tree[i].parent==-1)//沒有父結點
{
if(tree[i].weight<minweight)//小於最小權重
{
minweight = tree[i].weight;//更新最小權重
node1 = i;//更新最小點位置
}
}
}
minweight = 1e8;//初始化權重
for(int i=0;i<k;++i)
{
if(tree[i].parent==-1&&i!=node1)//沒有父結點且不是最小結點
{
if(tree[i].weight<minweight)//更新次小結點
{
minweight = tree[i].weight;
node2 = i;
}
}
}
}
void creat_tree(huffmannode tree[], int w[],int n)//建哈夫曼樹
{
int node1 = 0, node2 = 0;
for(int i=0;i<2*n-1;++i)//初始化結點
{
tree[i].parent = -1;
tree[i].leftchild = -1;
tree[i].rightchild = -1;
}
for(int i=0;i<n;++i)//將輸入的結點值輸入哈夫曼樹
{
tree[i].weight = w[i];
}
for(int k=n;k<2*n-1;++k)
{
select(tree,k,node1,node2);//找到最小結點,次小結點
tree[k].weight = tree[node1].weight + tree[node2].weight;//生成新結點,權重為兩結點之和
tree[node1].parent = k;//最小結點父結點為新結點
tree[node2].parent = k;//次小結點父結點為新結點
tree[k].leftchild = node1;//新結點左子樹為最小結點
tree[k].rightchild = node2;//新結點右子樹為次小結點
}
}
void form_code(huffmannode tree[],int n)//生成哈夫曼編碼
{
int cur, parent, start;
string huffcode;
for(int i=0;i<n;++i)//遍歷n個輸入的結點
{
cur = i;
parent = tree[i].parent;
while(parent!=-1)//當沒有到達根結點,向上尋找父結點
{
if(tree[parent].leftchild==cur)//如果當前結點是左子樹
{
huffcode = '0' + huffcode;//在哈夫曼編碼前加0
}
else
{
huffcode = '1' + huffcode;//加1
}
cur = parent;//更新當前結點
parent = tree[parent].parent;//更新父結點
}
code[tree[i].weight] = huffcode;//將生成的哈夫曼編碼用map儲存
translate[huffcode] = ch[i];//將哈夫曼編碼對應的值儲存
huffcode.clear();//清空哈夫曼編碼
}
}
void print_code(huffmannode tree[],int n)//輸出
{
cout << "得到的哈夫曼值為" << endl;
for(int i=0;i<n;++i)
{
cout << ch[i] << ":" << tree[i].weight << "的哈夫曼值為" << code[tree[i].weight] << endl;
}
}
void translate_code(string unknown)//翻譯編碼
{
string s;
for(int i=0;i<unknown.size();++i)//讀入未知編碼
{
s = s + unknown[i];
if(translate[s]!=0)//已讀入部分成功匹配現有編碼
{
cout << translate[s];//輸出對應值
s.clear();//清空已讀入部分
}
}
cout << endl;
}
void translate_string(string unknown)//編碼字串
{
for(int i=0;i<unknown.size();++i)//讀入未知編碼
{
cout << code[alp[unknown[i]]];
}
cout << endl;
}
int main()
{
int n;
cout << "請輸入結點的數量(解碼過程)" << endl;
cin >> n;
cout << "請輸入結點各自的字元和值" << endl;
for(int i=0;i<n;++i)
{
cin >> ch[i];
cin >> w[i];
alp[ch[i]] = w[i];
}
huffmannode *tree = new huffmannode[2*n-1];
creat_tree(tree,w,n);
form_code(tree,n);
print_code(tree,n);
string unknown;
cout << "請輸入一段待翻譯的01字串(譯碼過程)" << endl;
cin >> unknown;
cout << "翻譯結果為" << endl;
translate_code(unknown);
cout << "請輸入一段字串(編碼過程)" <<endl;
cin >> unknown;
cout << "轉碼結果為" << endl;
translate_string(unknown);
return 0;
}
相關文章
- 資料結構與演算法——赫夫曼樹(哈夫曼樹)資料結構演算法
- Java 樹結構實際應用 二(哈夫曼樹和哈夫曼編碼)Java
- 資料結構與演算法:哈夫曼樹資料結構演算法
- 【資料結構X.11】程式碼實現 哈夫曼樹的建立,建立,構造,實現哈夫曼編碼資料結構
- 資料結構-哈夫曼樹(python實現)資料結構Python
- 重學資料結構之哈夫曼樹資料結構
- 6.6 哈夫曼樹及其應用
- Task A2 哈夫曼樹的應用
- 哈夫曼樹
- 資料結構之哈弗曼樹資料結構
- 哈夫曼樹及其應用(檔案壓縮)
- C#資料結構-赫夫曼樹C#資料結構
- 高階資料結構---赫(哈)夫曼樹及java程式碼實現資料結構Java
- 一本正經的聊資料結構(6):最優二叉樹 —— 哈夫曼樹資料結構二叉樹
- 哈夫曼樹及其編碼
- 哈夫曼樹學習筆記筆記
- 哈夫曼編碼
- 最優二叉樹(哈夫曼樹)Java實現二叉樹Java
- 哈夫曼編碼 —— Lisp 與 Python 實現LispPython
- 小任的第一篇部落格-哈夫曼樹
- 資料結構基礎--字首樹&&字尾樹資料結構
- 有趣的赫夫曼樹
- 公共基礎知識-資料結構-樹資料結構
- 樹狀的資料結構的建立資料結構
- 曼哈頓距離與切比雪夫距離
- 【資料結構】二叉樹的建立與遍歷資料結構二叉樹
- 資料結構基礎03-紅黑樹資料結構
- 資料結構與演算法-kd二叉樹(基礎)資料結構演算法二叉樹
- 【資料結構】二叉樹的基礎知識資料結構二叉樹
- 曼哈頓距離與切比雪夫距離的互化
- 一本正經的聊資料結構(7):哈弗曼編碼資料結構
- 樹結構的應用
- 【資料結構基礎應用】【查詢和排序演算法】資料結構排序演算法
- Redis基礎(一)資料結構與資料型別Redis資料結構資料型別
- 《資料結構》實驗08--樹及其應用資料結構
- Redis的資料結構與應用場景Redis資料結構
- 資料結構與演算法 基礎排序資料結構演算法排序
- JavaScript 資料結構與基礎演算法JavaScript資料結構演算法