本例程實現二叉樹的二叉鏈表存儲結構類的定義、實現、應用以及Huffman樹,包括:
三種構造函數:
1、鍵盤輸入擴展二叉樹的前序序列構造二叉樹
2、由擴展二叉樹的前序遍歷序列s構造二叉樹
3、由擴展二叉樹的前序遍歷序列sp,中序遍歷序列sm構造二叉樹
析構函數:釋放二叉鏈表中各結點的存儲空間
獲得指向根結點的指針
二叉樹的遍歷:
1、前中後序遍歷二叉樹的遞歸實現
2、前中後序遍歷二叉樹的非遞歸實現,後序遍歷二叉樹只進一次棧的非遞歸實現
3、層序遍歷二叉樹
應用:
1、求二叉樹結點個數
2、前序遍歷順序輸出二叉樹葉子結點
3、非遞歸中序遍歷順序輸出二叉樹葉子結點
4、求二叉樹的高度
5、計算二叉樹中有所有葉子結點的和
6、Huffman樹
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
int m=0;
template <class T>
struct BiNode //二叉樹的結點結構
{
T data;
BiNode<T> *lchild, *rchild;
};
template <class T>
struct BiNodeTag //用於後序遍歷二叉樹非遞歸實現(2次進棧)的結點結構
{
char tag;
BiNode<T> *pt;
};
template <class T>
class BiTree
{ //二叉樹類
public:
BiTree( ); //構造函數,鍵盤輸入擴展二叉樹的前序序列構造二叉樹
BiTree(char *s); //構造函數,由擴展二叉樹的前序遍歷序列s構造二叉樹
BiTree(string sp,string sm); //構造函數,由擴展二叉樹的前序遍歷序列sp,中序遍歷序列sm構造二叉樹
~BiTree(void); //析構函數,釋放二叉鏈表中各結點的存儲空間
BiNode<T>* Getroot(); //獲得指向根結點的指針
void PreOrder(BiNode<T> *root); //前序遍歷二叉樹遞歸
void PreOrder0(BiNode<T> *root); //前序遍歷二叉樹非遞歸
void InOrder(BiNode<T> *root); //中序遍歷二叉樹遞歸
void InOrder0(BiNode<T> *root); //中序遍歷二叉樹非遞歸
void PostOrder(BiNode<T> *root); //後序遍歷二叉樹遞歸
void PostOrder0(BiNode<T> *root); //後序遍歷二叉樹非遞歸
void PostOrder1(BiNode<T> *root); //後序遍歷二叉樹非遞歸1,只進一次棧
void LevelOrder(BiNode<T> *root); //層序遍歷二叉樹
private:
BiNode<T> *root; //指向根結點的頭指針
BiNode<T> *Creat(); //無參構造函數調用
BiNode<T> *Creat(char *s); //有參構造函數調用
BiNode<T> *Creat(string sp,string sm); //有參構造函數調用
void Release(BiNode<T> *root); //析構函數調用
};
/*
*前置條件:二叉樹不存在
*輸 入:無
*功 能:構造一棵二叉樹
*輸 出:無
*後置條件:產生一棵二叉樹
*/
template<class T>
BiTree<T>::BiTree(char *s )
{
m=0;
root = Creat(s);
}
template<class T>
BiTree<T>::BiTree( )
{
root = Creat();
}
template<class T>
BiTree<T>::BiTree(string sp,string sm )
{
root = Creat(sp,sm);
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:釋放二叉鏈表中各結點的存儲空間
*輸 出:無
*後置條件:二叉樹不存在
*/
template<class T>
BiTree<T>::~BiTree(void)
{
Release(root);
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:獲取指向二叉樹根結點的指針
*輸 出:指向二叉樹根結點的指針
*後置條件:二叉樹不變
*/
template<class T>
BiNode<T>* BiTree<T>::Getroot( )
{
return root;
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:前序遍歷二叉樹
*輸 出:二叉樹中結點的一個線性排列
*後置條件:二叉樹不變
*/
template<class T>
void BiTree<T>::PreOrder(BiNode<T> *root)
{
if(root==NULL) return;
else{
cout<<root->data<<" ";
PreOrder(root->lchild);
PreOrder(root->rchild);
}
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:中序遍歷二叉樹
*輸 出:二叉樹中結點的一個線性排列
*後置條件:二叉樹不變
*/
template <class T>
void BiTree<T>::InOrder (BiNode<T> *root)
{
if (root==NULL) return; //遞歸調用的結束條件
else{
InOrder(root->lchild); //中序遞歸遍歷root的左子樹
cout<<root->data<<" "; //訪問根結點的數據域
InOrder(root->rchild); //中序遞歸遍歷root的右子樹
}
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:後序遍歷二叉樹
*輸 出:二叉樹中結點的一個線性排列
*後置條件:二叉樹不變
*/
template <class T>
void BiTree<T>::PostOrder(BiNode<T> *root)
{
if (root==NULL) return; //遞歸調用的結束條件
else{
PostOrder(root->lchild); //後序遞歸遍歷root的左子樹
PostOrder(root->rchild); //後序遞歸遍歷root的右子樹
cout<<root->data<<" "; //訪問根結點的數據域
}
}
/*
*前置條件:二叉樹已存在
*輸 入:無
*功 能:層序遍歷二叉樹
*輸 出:二叉樹中結點的一個線性排列
*後置條件:二叉樹不變
*/
template <class T>
void BiTree<T>::LevelOrder(BiNode<T> *root)
{
const int MaxSize = 100;
int front = 0;
int rear = 0; //採用順序隊列,並假定不會發生上溢
BiNode<T>* Q[MaxSize];
BiNode<T>* q;
if (root==NULL) return;
else{
Q[rear++] = root;
while (front != rear)
{
q = Q[front++];
cout<<q->data<<" ";
if (q->lchild != NULL) Q[rear++] = q->lchild;
if (q->rchild != NULL) Q[rear++] = q->rchild;
}
}
}
/*
*前置條件:空二叉樹
*輸 入:數據ch;
*功 能:初始化一棵二叉樹,構造函數調用
*輸 出:無
*後置條件:產生一棵二叉樹
*/
//int m=0;
template <class T>
BiNode<T>* BiTree<T>::Creat(char *s)
{
BiNode<T>* root;
char ch=s[m++];
//cout<<"請輸入創建一棵二叉樹的結點數據"<<endl;
//cin>>ch;
if (ch=='#') root = NULL;
else{
root = new BiNode<T>; //生成一個結點
root->data=ch;
root->lchild = Creat(s ); //遞歸建立左子樹
root->rchild = Creat(s ); //遞歸建立右子樹
}
return root;
}
template <class T>
BiNode<T>* BiTree<T>::Creat(string sp,string sm)
{
BiNode<T>* root=NULL;
if(sp.length() > 0)
{
root=new BiNode<T> ;
root->data=sp[0];
int index=sm.find(sp[0]);
string in_left_str=sm.substr(0, index);
string in_right_str=sm.substr(index+1);
string pre_left_str=sp.substr(1, index);
string pre_right_str=sp.substr(index+1);
root->lchild = Creat(pre_left_str, in_left_str); //遞歸建立左子樹
root->rchild = Creat(pre_right_str, in_right_str); //遞歸建立右子樹
}
return root;
}
template <class T>
BiNode<T>* BiTree <T>::Creat()
{ BiNode<T>* root;
char ch;
cout<<"Input a char: ";
cin>>ch;
if (ch=='#') root=NULL;
else {
root=new BiNode<T>;
root->data=ch;
root-> lchild=Creat();
root-> rchild=Creat();
}
return root;
}
/*
*前置條件:二叉樹已經存在
*輸 入:無
*功 能:釋放二叉樹的存儲空間,析構函數調用
*輸 出:無
*後置條件:二叉樹不存在
*/
template<class T>
void BiTree<T>::Release(BiNode<T>* root)
{
if (root != NULL){
Release(root->lchild); //釋放左子樹
Release(root->rchild); //釋放右子樹
delete root;
}
}
template<class T>
void BiTree<T>::PreOrder0(BiNode<T> *root)
{//前序遍歷二叉樹非遞歸
const int MaxStackSize=100;
BiNode<T> *S[MaxStackSize];
int top= -1; // 構造空棧,採用順序棧,並假定不會發生上溢
while (root!=NULL||top!= -1)
{
while (root!= NULL)
{
cout<<root->data;
S[++top]=root;;
root=root->lchild;
}
if (top!= -1) {
root=S[top--];
root=root->rchild;
}
}
}
template<class T>
void BiTree<T>::InOrder0(BiNode<T> *root)
{//中序遍歷二叉樹非遞歸
const int MaxStackSize=100;
BiNode<T> *S[MaxStackSize];
int top= -1; // 構造空棧,採用順序棧,並假定不會發生上溢
while (root!=NULL||top!= -1)
{
while (root!= NULL)
{
S[++top]=root;
root=root->lchild;
}
if (top!= -1) {
root=S[top--];cout<<root->data;
root=root->rchild;
}
}
}
template<class T>
void BiTree<T>::PostOrder0(BiNode<T> *root)
{//二叉樹後序遍歷非遞歸 2次入棧
const int MaxStackSize=100;
BiNodeTag<T> S[MaxStackSize];
BiNodeTag<T> p;
int top= -1; // 構造空棧,採用順序棧,並假定不會發生上溢
while (root!=NULL||top!= -1)
{
while (root!= NULL)
{
p.pt=root;p.tag='L';
S[++top]=p;
root=root->lchild;
}
if (top!= -1) {
p=S[top--];
if(p.tag=='L'){p.tag='R';S[++top]=p;root=p.pt->rchild;}
else if(p.tag=='R'){cout<<p.pt->data;//root=NULL;
}
}
}
}
template<class T>
void BiTree<T>::PostOrder1(BiNode<T> *root)//後序遍歷二叉樹非遞歸1,只進一次棧
{
//二叉樹後序遍歷非遞歸 一次入棧:
//後序遍歷在中序的雙層循環的基礎上需要加入一個記錄記錄上一次出棧的節點。步驟如下:
//1、如果棧頂元素非空且左孩子存在,將左孩子入棧,重複該過程。若不存在則進入第2步(該過程和中序遍歷一致)
//2、判斷上一次出棧節點是否當前節點的右孩子,或者當前節點是否存在右孩子,滿足任一條件,將當前節點輸出,並出棧。否則將右節點壓棧。跳至第1步
const int MaxStackSize=100;
BiNode<T> *S[MaxStackSize];
int top= -1; // 構造空棧,採用順序棧,並假定不會發生上溢
if(root == NULL) return;
S[++top]=root;
BiNode<T>* lastpop = NULL;
while(top!= -1)
{
while(S[top]->lchild != NULL)
{
top++;
S[top]=S[top-1]->lchild;
}
while(top!= -1)
{
if(lastpop == S[top]->rchild || S[top]->rchild == NULL)
{//判斷上次彈出的結點是不是當前結點的右孩子,或者當前節點沒有右孩子,因爲訪問次序是“左-右-中”。
cout<<S[top]->data;
lastpop = S[top--];
}
else if(S[top]->rchild != NULL)
{
top++;
S[top]=S[top-1]->rchild;
break;
}
}
}
}
template <class T>
void Count(BiNode<T> *root,int &n) //n爲全局量並已初始化爲0
{//求二叉樹結點個數
if (root) {
Count(root->lchild,n);
n++;
Count(root->rchild,n);
}
}
template <class T>
int CountNodes(BiNode<T> *root){//求二叉樹結點個數
int n=0;
Count(root,n);
return n;
}
template <class T>
int num_of_nodes(BiNode<T> *t)//求二叉樹結點個數
{
if(t == NULL)return 0;
int nl=num_of_nodes(t->lchild);
int nr=num_of_nodes(t->rchild);
return 1+nl+nr;
}
template <class T>
void PreOrderleaf(BiNode<T> *root)//前序遍歷順序輸出二叉樹葉子結點
{
if (root) {
if (!root->lchild && !root->rchild)
cout<<root->data;
PreOrderleaf(root->lchild);
PreOrderleaf(root->rchild);
}
}
template<class T>
void InOrder0leaf(BiNode<T> *root)
{ //非遞歸中序遍歷順序輸出二叉樹葉子結點
const int MaxStackSize=100;
BiNode<T> *S[MaxStackSize];
int top= -1; // 構造空棧,採用順序棧,並假定不會發生上溢
while (root!=NULL||top!= -1)
{
while (root!= NULL)
{
S[++top]=root;;
root=root->lchild;
}
if (top!= -1) {
root=S[top--];
if(!root->rchild && !root->lchild) cout<<root->data;
root=root->rchild;
}
}
}
template <class T>
int Depth(BiNode<T> *root)
{//求二叉樹的高度
if (root==NULL) return 0;
else {
int hl=Depth(root->lchild);
int hr=Depth(root ->rchild);
return hl>hr?hl+1:hr+1;
}
}
template <class T>
int CountDC(BiNode<T> *root)
//計算二叉樹中有所有葉子結點的和。
{
if (root==NULL) return 0;
else{
if (root->lchild==NULL&& root->rchild==NULL)
return (int)(root->data);
else
return (CountDC(root->lchild)+CountDC(root->rchild));
}
}
// 哈夫曼樹的結點結構
struct element
{
int weight; // 權值域
int lchild, rchild, parent; // 該結點的左、右、雙親結點在數組中的下標
};
// 選取權值最小的兩個結點
void selectMin(element a[],int n, int &s1, int &s2)
{
for (int i = 0; i < n; i++)
{
if (a[i].parent == -1)// 初始化s1,s1的雙親爲-1
{
s1 = i;
break;
}
}
for (int i = 0; i < n; i++)// s1爲權值最小的下標
{
if (a[i].parent == -1 && a[s1].weight > a[i].weight)
s1 = i;
}
for (int j = 0; j < n; j++)
{
if (a[j].parent == -1&&j!=s1)// 初始化s2,s2的雙親爲-1
{
s2 = j;
break;
}
}
for (int j = 0; j < n; j++)// s2爲另一個權值最小的結點
{
if (a[j].parent == -1 && a[s2].weight > a[j].weight&&j != s1)
s2 = j;
}
}
// 哈夫曼算法
// n個葉子結點的權值保存在數組w中
void HuffmanTree(element huftree[], int w[], int n)
{
for (int i = 0; i < 2*n-1; i++) // 初始化,所有結點均沒有雙親和孩子
{
huftree[i].parent = -1;
huftree[i].lchild = -1;
huftree[i].rchild = -1;
}
for (int i = 0; i < n; i++) // 構造只有根節點的n棵二叉樹
{
huftree[i].weight = w[i];
}
for (int k = n; k < 2 * n - 1; k++) // n-1次合併
{
int i1, i2;
selectMin(huftree, k, i1, i2); // 查找權值最小的倆個根節點,下標爲i1,i2
// 將i1,i2合併,且i1和i2的雙親爲k
huftree[i1].parent = k;
huftree[i2].parent = k;
huftree[k].lchild = i1;
huftree[k].rchild = i2;
huftree[k].weight = huftree[i1].weight + huftree[i2].weight;
}
}
// 輸出哈夫曼樹
void print(element hT[],int n)
{
cout << "index weight parent lChild rChild" << endl;
cout << left; // 左對齊輸出
for (int i = 0; i < n; ++i)
{
cout << setw(5) << i << " ";
cout << setw(6) << hT[i].weight << " ";
cout << setw(6) << hT[i].parent << " ";
cout << setw(6) << hT[i].lchild << " ";
cout << setw(6) << hT[i].rchild << endl;
}
}
int main()
{ BiNode<char>* root;
BiTree<char> bt; //創建一棵二叉樹
root = bt.Getroot( ); //獲取指向根結點的指針
cout<<"------前序遍歷------ "<<endl;
bt.PreOrder(root);
cout<<endl;
bt.PreOrder0(root);
cout<<endl;
cout<<"------中序遍歷------ "<<endl;
bt.InOrder(root);
cout<<endl;
bt.InOrder0(root);
cout<<endl;
cout<<"------後序遍歷------ "<<endl;
bt.PostOrder(root);
cout<<endl;
bt.PostOrder0(root);
cout<<endl;
cout<<"------層序遍歷------ "<<endl;
bt.LevelOrder(root);
cout<<endl;
cout<<"Number of nodes="<<CountNodes(root)<<endl;
cout<<"Number of nodes="<<num_of_nodes(root)<<endl;
cout<<"Leaf-nodes are ";
PreOrderleaf(root);
cout<<endl<<"Leaf-nodes are ";
InOrder0leaf(root);
cout<<endl<<"Depth="<<Depth(root)<<endl;
BiTree<char> bt1("ABD#EI##F##CG#H####"); //創建一棵二叉樹
//BiNode<string>* root; //獲取指向根結點的指針
root = bt1.Getroot( );
cout<<"------前序遍歷------ "<<endl;
bt1.PreOrder(root);
cout<<endl;
bt1.PreOrder0(root);
cout<<endl;
cout<<"------中序遍歷------ "<<endl;
bt1.InOrder(root);
cout<<endl;
bt1.InOrder0(root);
cout<<endl;
cout<<"------後序遍歷------ "<<endl;
bt1.PostOrder(root);
cout<<endl;
bt1.PostOrder0(root);
cout<<endl;
cout<<"------層序遍歷------ "<<endl;
bt1.LevelOrder(root);
cout<<endl;
/*n=0;
Count(root);
cout<<"Number of nodes="<<n<<endl;*/
cout<<"Number of nodes="<<CountNodes(root)<<endl;
cout<<"Leaf-nodes are ";
PreOrderleaf(root);
cout<<endl<<"Leaf-nodes are ";
InOrder0leaf(root);
cout<<endl<<"Depth="<<Depth(root)<<endl;
cout<<CountDC(root)<<endl;
// BiTree<char> bt2("DBEAFC","ABDECF"); //創建一棵二叉樹
BiTree<char> bt2("abdcef","dbacfe"); //創建一棵二叉樹樹
root = bt2.Getroot( ); //獲取指向根結點的指針
cout<<"------前序遍歷------ "<<endl;
bt2.PreOrder(root); cout<<endl;
bt2.PreOrder0(root); cout<<endl;
cout<<"------中序遍歷------ "<<endl;
bt2.InOrder(root); cout<<endl;
bt2.InOrder0(root); cout<<endl;
cout<<"------後序遍歷------ "<<endl;
bt2.PostOrder(root);cout<<endl;
bt2.PostOrder0(root);cout<<endl;
bt2.PostOrder1(root);cout<<endl;
cout<<endl;
cout<<"------層序遍歷------ "<<endl;
bt2.LevelOrder(root); cout<<endl;
cout<<CountDC(root)<<endl;
int x[] = { 5,29,7,8,14,23,3,11 }; // 權值集合
element *hufftree=new element[2*8-1]; // 動態創建數組
HuffmanTree(hufftree, x, 8);
print(hufftree,15);
return 0;
}