花了一天多的時間看懂了自適應哈夫曼編碼的原理並且用鏈式樹的結構完成了**。
原理:
自適應哈夫曼樹的節點結構體如下:
struct node ;
};
是乙個帶有父節點指標的樹節點。兩個數值分別為該節點的權重和節點編號。
自適應哈夫曼樹滿足如下兩個原則:
1、父節點的節點編號一定比子節點大
2、節點編號大的節點,權重值也一定大。
這兩個原則被稱為兄弟屬性。
而自適應哈夫曼編碼的過程就是在編碼過程中實時調整哈夫曼樹以保證滿足兄弟屬性。
步驟:
一、 建立空哈夫曼樹,樹的根節點標識為nyt。
二、 讀取乙個字元,當這個字元沒有在哈夫曼樹里出現過的時候,構建新子樹,根節點權重值為1,左孩子為nyt,右孩子為該字元,用子樹替換標識為nyt的節點。同時輸出nyt的編碼和字元。
當字元出現過時,輸出該字元的哈夫曼編碼。
三、 從被輸出的節點開始往上走,每乙個節點權重值加1,但是在加權重值之前,需要判斷該節點是否為同權重值裡節點編號最大的。如果不是為最大,則與最大節點交換位置(節點的子樹也要交換而不是只交換單個節點)。交換後再互換節點編號,這樣權重值需要被加1的節點就保證為同級節點編號最大的節點。
**如下:
標頭檔案:
#pragma once
#include using std::ifstream;
using std::ofstream;
using std::cout;
using std::cin;
using std::endl;
struct node ;
};class binarytree
; binarytree(int num = 0,int weight = 0);
~binarytree();
bool swap(node* p_nodea, node* p_nodeb);
bool addnode(node* p_parent, node* p_child, brother brotherstate);
node* findnode(node *p);
void deletenode(node *p_node);
node* getroot()
bool setnodenum(node* p_node,int num);
brother getbrotherstate(node *p_node);
bool isancestor(node* p_nodechild, node* p_nodeancestor);
private:
node *p_root; };
class huffmantree
; std::string gethuffmancode(node *p);
node * findlarge(node *);
//乙個儲存哪些字元已經存在於樹中的緩衝
std::vectorbuffers;
ifstream is;
ofstream os;
};
實現:
#include "stdafx.h"
#include "huffmantree.h"
int huffmantree::sum = 1;
//二叉樹成員函式實現
binarytree::binarytree(int num,int weight)
binarytree::~binarytree()
bool binarytree::swap(node * p_nodea, node * p_nodeb)
else
} else
else
} ptemp = p_nodea->p_parent;
p_nodea->p_parent = p_nodeb->p_parent;
p_nodeb->p_parent = ptemp;
return true;
}bool binarytree::addnode(node * p_parent, node * p_child, brother brotherstate)
p_parent->p_left = p_child;
} else if (brotherstate == rightchild)
p_parent->p_right = p_child;
} else
p_child->p_parent = p_parent;
return true;
}node * binarytree::findnode(node *p)
queue.pop();
if (p_node->p_left != nullptr)
if (p_node->p_right != nullptr)
} return nullptr;
}bool binarytree::setnodenum(node* p_node, int num)
}bool binarytree::isancestor(node * p_nodechild, node * p_nodeancestor)
else
} return false;
}void binarytree::deletenode(node *p_node)
if (p_node->p_right != nullptr)
delete p_node;
}binarytree::brother binarytree::getbrotherstate(node *p_node)
else
}//哈夫曼樹成員函式實現
huffmantree::huffmantree():tree(0,0)
huffmantree::~huffmantree()
bool huffmantree::readfile(char * filename)
return true;
}//獲取節點的哈夫曼編碼
std::string huffmantree::gethuffmancode(node *p_n)
else
p_n = p_n->p_parent;
} while (!code.empty())
return huffmancode;
}//找到所在塊中最大節點編號的節點
node * huffmantree::findlarge(node *p_node)
//同權重下的large比p小,則置large為p
else if(large->num > p->num)
}p = p->p_left;
} else
} //large不可能是根節點,當large為根節點時返回原節點
if (large == tree.getroot())
return large;
}//編碼函式
bool huffmantree::encode(char * out_filename)
os.open(out_filename, std::ios_base::out);
if (!os.is_open())
//讀取字元,設定nyt節點為根節點
char cbuffer;
node *nyt = tree.getroot();
while (!is.eof())
exist = true;
cout << cbuffer << " 在樹中存在,編碼為: " << existnode->value << endl;
break;
}} if (exist)
else
os << cbuffer;
cout << cbuffer << "首次出現,設定編碼為:" << code << cbuffer << endl;
//將新的字元放進buffers中
charmap* new_cm = new charmap();
new_cm->key = cbuffer;
new_cm->p = nyt->p_right;
new_cm->value = gethuffmancode(nyt->p_right);
buffers.push_back(*new_cm);
//依次增加權重
node *root = nyt->p_parent;
weightadd(root);
//設定新的nyt節點為原nyt節點的左孩子
nyt = nyt->p_left;
} } return false;
}//從當前節點往上依次權重值加一,但是加一前先判斷是否符合兄弟屬性
void huffmantree::weightadd(node * p_node)
} p_node->weight++;
cout << "節點" << p_node->num << "權重值加1" << "為:" << p_node->weight << endl;
p_node = p_node->p_parent;
}}
主程式:
int main()
最終效果:
哈夫曼編碼 哈夫曼樹
1.定義 哈夫曼編碼主要用於資料壓縮。哈夫曼編碼是一種可變長編碼。該編碼將出現頻率高的字元,使用短編碼 將出現頻率低的字元,使用長編碼。變長編碼的主要問題是,必須實現非字首編碼,即在乙個字符集中,任何乙個字元的編碼都不是另乙個字元編碼的字首。如 0 10就是非字首編碼,而0 01不是非字首編碼。2....
哈夫曼樹 哈夫曼編碼
定義從a結點到b結點所經過的分支序列為從a結點到b結點的路徑 定義從a結點到b結點所進過的分支個數為從a結點到b結點的路徑長度 從二叉樹的根結點到二叉樹中所有結點的路徑長度紙盒為該二叉樹的路徑長度 huffman樹 帶權值路徑長度最小的擴充二叉樹應是權值大的外界點舉例根結點最近的擴充二叉樹,該樹即為...
哈夫曼編碼 哈夫曼樹
哈夫曼樹是乙個利用權值進行優化編碼的乙個比較奇怪的樹,他的實現比較簡單,用途也比較單一。哈夫曼樹的實現,實現要求 通過哈夫曼樹可以保證在編碼過程中不會出現例如 1000和100這樣的編碼規則,否則就會編碼失敗,因為1000和100在某些情況下的編碼會一模一樣。通過哈夫曼樹可以保證權值大的值進行編碼時...