樹 學習總結

1.引入的概念:
結點:指樹中的一個元素;
結點的度:指結點擁有的子樹的個數,二叉樹的度不大於2;
樹的度:指樹中的最大結點度數;
葉子:度爲0的結點,也稱爲終端結點;
高度:葉子節點的高度爲1,根節點高度最高;
層:根在第一層,以此類推;

2.樹的存儲結構:
(1)雙親表示法:以雙親作爲索引的關鍵詞的一種存儲方式
每個結點只有一個雙親,所以選擇順序存儲佔主要以一組連續空間存儲樹的結點,同時在每個結點中,附設一個指示其雙親結點位置的指針域
(2)孩子表示法:類似於單鏈表的存儲方式,指針域內的元素個數有子樹個數決定。
(3)孩子兄弟表示法:任意一棵樹,他的結點的第一個孩子如果存在就是唯一結點,他的右兄弟如果存在,也是唯一的,因此,可以設置兩個指針,分別指向該結點的第一個孩子和該結點的右兄弟
3.特殊的二叉樹
二叉樹的定義:由一個結點和兩顆互不相交、分別稱爲這個根的左子樹和右子樹的二叉樹構成(遞歸定義)
(1)二叉樹的性質:
1:二叉樹的第i層上至多有2^(i-1)個結點
2:深度爲k的二叉樹,至多有2^k-1個結點
3:在一棵二叉樹中,如果葉子結點數爲n0,度爲2的結點數爲n2,則有: n0=n2+1
4:具有n個結點的完全二叉樹的深度爲 log2n +1
5:對一棵具有n個結點的完全二叉樹中從1開始按層序編號,則對於任意的序號爲i(1≤i≤n)的結點有:
(1)如果i>1, 則結點i的雙親結點的序號爲 i/2;如果i=1, 則結點i是根結點,無雙親
(2)如果2i≤n, 則結點i的左孩子的序號爲2i; 如果2i>n,則結點i無左孩子。
(3)如果2i+1≤n, 則結點i的右孩子的序號爲2i+1;如果2i+1>n,則結點 i無右孩子。
(2)滿二叉樹:葉子節點一定要在最後一層,並且所有非葉子節點都存在左孩子和右孩子;
(3)最特別的二叉樹:完全二叉樹:從左到右、從上到下構建的二叉樹;
二叉樹的遍歷(遞歸):
1:先序遍歷:根->左子樹->右子樹(先序)
2:中序遍歷:左子樹->根->右子樹(中序)
3:後序遍歷:左子樹->右子樹->根(後序)
這三種遍歷方法只是訪問結點的時機不同,訪問結點的路徑都是一樣的,時間和空間複雜度皆爲O(n)
4:層序遍歷:逐層訪問
代碼實現:

#include <iostream>
using namespace std;
template<typename T>
struct BiNode
{
	T data;
	BiNode<T>*lchild;
	BiNode<T>*rchild;
};
template<typename T>
class BiTree
{
	private:
	BiNode<T>*root;
	BiNode<T>*Creat();
	void Release(BiNode<T>*bt);
	void PreOrder(BiNode<T>*bt);
	void InOrder(BiNode<T>*bt);
	void PostOrder(BiNode<T>*bt);
	public:
	BiTree(){
		root = Creat();

	}
	~BiTree(){
		Release(root);

	}
	void PreOrder(){
		PreOrder(root);

	}
	void InOrder(){
		InOrder(root);

	}
	void PostOrder(){
		PostOrder(root);

	}
};
template<typename T>
BiNode<T>*BiTree<T>::Creat()//創建一個二叉樹
{
	BiNode<T>*bt;
	char ch;
	cin>>ch;
	if(ch=='#')
		bt = NULL;
	else
	{
		bt = new BiNode<T>;
		bt->data = ch;
		bt->lchild = Creat();
		bt->rchild = Creat();
	}
	return bt;
}
template<typename T>
void BiTree<T>::PreOrder(BiNode<T>*bt)//前序遍歷
{
	if(bt==NULL)
		return;
	else
	{
		cout<<bt->data;
		PreOrder(bt->lchild);
		PreOrder(bt->rchild);
	}
}
template<typename T>
void BiTree<T>::InOrder(BiNode<T>*bt)//中序遍歷
{
	if(bt==NULL)
		return;
	else
	{
	    InOrder(bt->lchild);
		cout<<bt->data;
		InOrder(bt->rchild);
	}
}
template<typename T>
void BiTree<T>::PostOrder(BiNode<T>*bt)//後序遍歷
{
	if(bt==NULL)
		return;
	else
	{
	    PostOrder(bt->lchild);
		PostOrder(bt->rchild);
		cout<<bt->data;
	}
}

前序遍歷的非遞歸實現:
1.棧s初始化(空棧);
2.循環直到root爲空且棧s爲空
 2.1 當root不空時循環
  2.1.1 輸出root->data;
 2.1.2 將指針root的值保存到棧中;
 2.1.3 繼續遍歷root的左子樹(root=root->lchild)
 2.2 如果棧s不空,則
  2.2.1 將棧頂元素彈出至root(root=s.pop());
  2.2.2 準備遍歷root的右子樹(root=root->rchild);

template <class T>
void BiTree::PreOrder(BiNode<T> *root) {
  SeqStack<BiNode<T> *>  s;
     while (root!=NULL | | !s.empty()) {
         while (root!= NULL)  {
             cout<<root->data;
             s.push(root);
             root=root->lchild;  
         }
         if (!s.empty()) { 
             root=s.pop();
             root=root->rchild;  
         }
     }
}

中序遍歷的非遞歸實現
1.棧s初始化(空棧);
2.循環直到root爲空且棧s爲空
 2.1 當root不空時循環
2.1.1 將指針root的值保存到棧中;
 2.1.2 繼續遍歷root的左子樹(root=root->lchild)
 2.2 如果棧s不空,則
  2.2.1 將棧頂元素彈出至root(root=s.pop());
   2.2.2 輸出root->data;
  2.2.3 準備遍歷root的右子樹(root=root->rchild);

template <class T>
void BiTree::InOrderwithoutD (BiNode<T> *root)
{
  stack< BiNode<T> * > aStack;
}
while(!aStack.empty()||root) {
while(root){
  aStack.push(root);
  root=root->lchild; 	 
}
  	  if(!aStack.empty()){
		      root=aStack.top();				
		      aStack.pop(); 
                 cout<<root->data;
                 root=root->rchild; 
	   }
  }
} 

後序遍歷的非遞歸實現:
1.定義一個棧;從根節點出發開始遍歷,p=root,如果,root==NULL, 不進行遍歷;
2.無條件進行下面的工作
(1)如果指針不空,指針打上left標記,並將指針進棧,執行(2);否則,執行(3)
(2)p->lchild,重複(1)
(3)棧頂元素出棧P
(4)查看P的標誌,如果標誌爲right,進行下面的工作,否則,執行(5)
a.訪問當前節點P
b.如果棧空 ,算法結束;
c.否則,棧頂元素出棧,轉(4)
(5)修改P的標誌,讓P重新入棧,p=P->rchild,執行2

#include <stack>
Using namespace std;
template<class T>
void BiTree<T>::PostOrderWithoutRecusion(BiTreeNode<T>* root){
	StackElement<T> element;
	stack<StackElement<T > > aStack;//棧申明
	BiTreeNode<T>* pointer;
	if(root==NULL)
		return;//空樹即返回
}
else    
pointer=root;				
while(true){
	  while(pointer!=NULL){//進入左子樹
		element.pointer=pointer;
		element.tag=Left; //沿左子樹方向向下周遊
		aStack.push(element);
		pointer=pointer->lchild; 	
}
ement=aStack.pop();
pointer=element.pointer; 
while(element.tag==Right){
        cout<<pointer->data;
        if(aStack.empty())  return;
	    else{
	       element=aStack.pop();
		   pointer=element.pointer;
	  	}//end else
} //endwhile
element.tag=Right; 
aStack.push(element);
pointer=pointer->rchild(); 
}//end while

(5)Huffman編碼
Huffman是一種前綴編碼;Huffman編碼是建立在Huffman樹的基礎上進行的,因此爲了進行Huffman編碼,必須先構建Huffman樹;樹的路徑長度是每個葉節點到根節點的路徑之和;帶權路徑長度是(每個葉節點的路徑長度*wi)之和;Huffman樹是最小帶權路徑長度的二叉樹;
構造Huffman樹的過程:
(1)將各個節點按照權重從小到大排序;
(2)取最小權重的兩個節點,並新建一個父節點作爲這兩個節點的雙親,雙親節點的權重爲子節點權重之和,再將此父節點放入原來的隊列;
(3)重複(2)的步驟,直到隊列中只有一個節點,此節點爲根節點;

發佈了44 篇原創文章 · 獲贊 1 · 訪問量 3111
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章