數據結構6——二叉樹(2)

一、二叉樹中其他的操作

  1. 統計樹中結點的數目

(左子樹中節點的數目+右子樹中節點的數目+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的前驅線索

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章