一、二叉樹中其他的操作
- 統計樹中結點的數目
(左子樹中節點的數目+右子樹中節點的數目+1(根結點))
template<class T>
int BiTree<T>::count(BiNode<T>* root){
int number=0;
if (root==NULL)
number=0;
else
number=count(root->lchild)+count(root->rchild)+1;
return number;
}
2.統計樹中葉子結點的數目
(左子樹中葉子節點的數目+右子樹中葉子節點的數目)
template<class T>
int BiTree<T>::leafcount(BiNode<T>* root){
int number=0;
if (root==NULL)
number=0;
else if(root->lchild==NULL && root->rchild==NULL)
number=1;
else
number=leafcount(root->lchild)+leafcount(root->rchild);
return number;
}
3.
計算葉子的高度
Max(左子樹的高度,右子樹的高度)+1
template<typename T>
int BiTree<T>::cal_height(BiTreeNode<T> * root){
int lheight=0,rheight=0;
if (root==0) return 0;
lheight=cal_height(root->lchild);
rheight=cal_height(root->rchild);
if (lheight>rheight) return lheight+1;
else return rheight+1;
}
4.
計算二叉樹的寬度(基於層次遍歷實現)
struct q_element{ BiNode * root; int level;};
int BiTree::Width(){
queue< struct q_element > q;
int num[100]={0,1};
q_element s,child;
BiNode *root;
root=this->root;
if(root==NULL)
return 0;
s.root=root;
s.level=1;
q.push(s);
while(!q.empty()) {
s=q.front();
if(s.root->lchild){
num[s.level+1]++;
child.root=s.root->lchild;
child.level=s.level+1;
q.push(child);
}
if(s.root->rchild) {
num[s.level+1]++;
child.root=s.root->rchild;
child.level=s.level+1;
q.push(child);
}
q.pop();
}
int max=0,i=1;
while(num[i]>0){
if(max<num[i])
max=num[i];
i++;
}
return max;
}
5.
判斷一棵樹是否爲完全二叉樹(基於層次遍歷,在每一層找是否每一個結點都有左兒子和右兒子,能遍歷完所有結點的即爲完全二叉樹)
template<class T>
bool BiTree<T>::Is_Wanquan(BiNode<T> *root){
queue<BiNode<T>*> q;
BiNode <T>* pointer;
bool is_leaf=false;
if(!root)
return false;
q.push(root);
while(!q.empty()) {
pointer=q.front(); q.pop();
if(pointer->rchild!=NULL && pointer->lchild==NULL)
return false;
else if(pointer->rchild==NULL && pointer->lchild!=NULL )
if(is_leaf)
return false;
else //如果是完全二叉樹,則,該結點之後的結點應爲葉子節點
is_leaf=true;
else if(pointer->rchild==NULL && pointer->lchild==NULL )
is_leaf=true;
if(pointer->lchild!=NULL)
q.push(pointer->lchild);
if(pointer->rchild!=NULL)
q.push(pointer->rchild);
}
return true;
}
二、三叉鏈表
template<class T>
struct Node
{
T data;
Node<T> * lchild, *rchild,*parent;
};
template <class T>
BiNode<T> * BiTree<T>::Creat(BiNode<T> * &root ,BiNode<T> *parent){
T ch;
cout<<"請輸入創建一棵二叉樹的結點數據"<<endl;
cin>>ch;
if (ch=="#") root = NULL;
else{
root = new BiNode<T>; //生成一個結點
root->data=ch;
root->parent=parent;
Creat(root->lchild,root ); //遞歸建立左子樹
Creat(root->rchild,root); //遞歸建立右子樹
}
return root;
}
三、樹、森林和二叉樹的轉換
1、樹轉化成二叉樹(將除了最左邊的一個孩子的其他孩子(左孩子的兄弟)轉化爲這個孩子的右孩子)
樹:兄弟關係---->二叉樹:雙親和右孩子
樹:雙親和長子---->二叉樹:雙親和左孩子
PS:樹的前序遍歷等價於二叉樹的前序遍歷
樹的後序遍歷等價於二叉樹的中序遍歷
2、森林轉化爲二叉樹
⑴ 將森林中的每棵樹轉換成二叉樹;
⑵ 從第二棵二叉樹開始,依次把後一棵二叉樹的根結點作爲前一棵二叉樹根結點的右孩子,當所有二叉樹連起來後,此時所得到的二叉樹就是由森林轉換得到的二叉樹。
森林的遍歷方法有兩種:前序(根)遍歷和後序(根)遍歷
PS:前序遍歷森林即爲前序遍歷森林中的每一棵樹。
後序遍歷森林即爲後序遍歷森林中的每一棵樹。
四、最優二叉樹-哈夫曼樹
特點:(1)權值越大的葉子結點越靠近根結點,而權值越小的葉子結點越遠離根結點。
(2)只有度爲0(葉子結點)和度爲2(分支結點)的結點,不存在度爲1的結點.
struct element
{ int weight;
int lchild, rchild, parent;
};
void HuffmanTree(element huffTree[ ], int w[ ], int n ) {//將數組huffTree初始化
for (i=0; i<2*n-1; i++) {
huffTree [i].parent= -1;
huffTree [i].lchild= -1;
huffTree [i].rchild= -1;
}
for (i=0; i<n; i++) 將前n個元素賦權值
huffTree [i].weight=w[i];
for (k=n; k<2*n-1; k++) {進行k-1次合併
Select(huffTree, &i1, &i2); //Select函數爲選取所有元素中最小的兩個元素的函數
huffTree[k].weight=huffTree[i1].weight+huffTree[i2].weight;
huffTree[i1].parent=k; //將兩個元素通過parent指針合併成一棵子樹
huffTree[i2].parent=k;
huffTree[k].lchild=i1;
huffTree[k].rchild=i2;
}
}
哈夫曼編碼:
前綴編碼:一組編碼中任意一個編碼都不是其他任何一個編碼的前綴(保證解碼時不會有多種可能性)
五、線索二叉樹
線索列表
結點結構
enum flag {Child, Thread}; //標識是真正的孩子還是前驅、後繼
template <class T>
struct ThrNode
{
T data;
ThrNode<T> *lchild, *rchild;
flag ltag, rtag;
};
建立帶有標誌位的二叉鏈表
template <class T>ThrNode<T>* InThrBiTree<T>::Creat( ){
ThrNode<T> *root;
T ch;
cout<<"請輸入創建一棵二叉樹的結點數據"<<endl;
cin>>ch;
if (ch=="#") root = NULL;
else{
root=new ThrNode<T>;
root->data = ch;
root->ltag = Child; root->rtag = Child;//先將左右結點的標記都打上child
root->lchild = Creat( );
root->rchild = Creat( );
}
return root;
}
中序線索化二叉樹(遞歸)
template <class T> void ThrBiTree<T>::ThrBiTree (ThrNode<T>*root) {
if (root==NULL) return; //遞歸出口
ThrBiTree(root->lchild);
if (!root->lchild){ //對root的左指針進行處理
root->ltag = Thread;
root->lchild = pre; //設置pre的前驅線索
}
if (!root->rchild) root->rtag = Thread;
if(pre != NULL){
if (pre->rtag==Thread) pre->rchild = root;
}
pre = root;
ThrBiTree(root->rchild);
}
PS:中序線索化根結點時不能得到root->rchild的前驅線索