本文以實例形式講述了C++實現哈夫曼樹簡單創建與遍歷的方法,比較經典的C++算法。
本例實現的功能為:給定n個帶權的節點,如何構造一棵n個帶有給定權值的葉節點的二叉樹,使其帶全路徑長度WPL最小。
據此構造出最優樹算法如下:
哈夫曼算法:
1. 將n個權值分別為w1,w2,w3,....wn-1,wn的節點按權值遞增排序,將每個權值作為一棵二叉樹。構成n棵二叉樹森林F={T1,T2,T3,T4,...Tn},其中每個二叉樹都只有一個權值,其左右字數為空
2. 在森林F中選取根節點權值最小二叉樹,作為左右字數構成一棵新的二叉樹,并使得新的二叉樹的根節點為
其左右字數權值之和,其中葉子都是最初的樹
3. 在森林F中刪除這兩棵樹,同時將新得到的二叉樹代替這兩個樹加入到森林F中,因此森林中二叉樹的個數比以前少一顆
4. 對新的森林重復2和3,知道森林中只有一棵樹位置,這棵樹就是哈夫曼樹.
#include <iostream>using namespace std;#define LEAFNUM 10 //葉子節點數,也就是權值樹#define HUFNUM 2*LEAFNUM#define MAXWEIGHT 999.9//*********存儲結構***********class HufTree;//***** Node**********class NODE{private: char Data; //節點的數據域 double Weight; //節點的權值域 int Lchild,Rchild,Parent; //節點的左孩子右孩子及雙親域public: NODE() //構造函數 { Data = '/0'; Weight = 0; Lchild = -1; Rchild = -1; Parent = -1; //給節點的數據初始化 } int Re_L(){return Lchild;} int Re_R(){return Rchild;} char Re_Data(){return Data;} double Re_Weight(){return Weight;} friend class HufTree; //聲明友元};//Node//********HufTree類**********class HufTree{private: int NodeNum; NODE HufArry[HUFNUM];public: HufTree(){NodeNum = 0;} void SetHuf(int,double,char); //設置權值與數據域 void CreatHuf(); //創建哈夫曼樹 void SelectMin(int,int&,int&); //查找哈夫曼樹種兩個權值最小的樹 void Find_Root_and_Print(); //查找樹根節點位置 void PrintHuf(int); //遍歷哈夫曼樹};//huftree void HufTree::SetHuf(int i,double wei,char ch){ HufArry[i].Data = ch; HufArry[i].Weight = wei;}void HufTree::CreatHuf(){ cout<<"每次查詢兩個最小樹的位置:"<<endl; for(int i = LEAFNUM; i < HUFNUM - 1; i++) { int p1 = 0; int p2 = 0; SelectMin(i,p1,p2); //找出當前樹種權值最小的兩顆樹 cout<<p1<<" < - > "<<p2<<endl; HufArry[p1].Parent = i; //設置兩顆最小樹的雙親 HufArry[p2].Parent = i; HufArry[i].Lchild = p1; //設置這棵3節點的樹的根的權值以及孩子 HufArry[i].Rchild = p2; HufArry[i].Weight = HufArry[p1].Weight + HufArry[p2].Weight; } cout<<"************************"<<endl;}void HufTree::SelectMin(int i,int &p1,int &p2){ int least1 = MAXWEIGHT; int least2 = MAXWEIGHT; for(int j = 0; j < i; j++) { if(HufArry[j].Parent == -1) { if(HufArry[j].Weight < least1) { least2 = least1; least1 = HufArry[j].Weight; p2 = p1; p1 = j; } else { if(HufArry[j].Weight < least2) { least2 = HufArry[j].Weight; p2 = j; } } } }}void HufTree::Find_Root_and_Print(){ int root; for(int i = 0; i < HUFNUM - 1; i++) { if(HufArry[i].Parent == -1) { root = i; break; } } PrintHuf(root);}void HufTree::PrintHuf(int position){ if(NodeNum == LEAFNUM) { return; } else { if(HufArry[position].Data != '/0') //如果是葉子節點 { cout<<"權值:"<<HufArry[position].Weight<<"<-> 數據:"<<HufArry[position].Data<<" 此節點為葉子"<<endl; NodeNum = NodeNum + 1; } else { cout<<"權值:"<<HufArry[position].Weight<<" 此節點無數據域,不是葉子"<<endl; PrintHuf(HufArry[position].Lchild); PrintHuf(HufArry[position].Rchild); } } }int main(){ HufTree Tree; cout<<"請輸入"<<LEAFNUM<<"對(權值,數據):"<<endl; double wei; char ch; for(int i = 0; i < LEAFNUM; i++) { cin>>wei; cin>>ch; Tree.SetHuf(i,wei,ch); } Tree.CreatHuf(); //創建哈夫曼樹 Tree.Find_Root_and_Print(); //遍歷哈夫曼樹 return 0;}
測試結果:
1 a2 b5 c7 d4 e13 f3 g6 h11 i8 l
新聞熱點
疑難解答