【數據結構&算法】三:樹與二叉樹(先序、中序、後序)

二叉樹

滿二叉樹和完全二叉樹

  在一棵二叉樹中,如果所有的分支節點都有左孩子和右孩子,並且葉子節點都集中在二叉樹的最下一層,則這樣的二叉樹被稱爲滿二叉樹。   

       如果一棵深度爲k有n個節點的二叉樹進行編號後,各結點的編號與深度爲k的滿二叉樹中相同位置山的結點的編號軍相投,那麼這棵二叉樹就是一顆完全二叉樹

 

二叉樹的性質

  1. 總分支數=總結點數-1(這條結論對任何樹都適用,不止是二叉樹) 證明:在二叉樹中除根節點之外,每一個結點都有唯一的一個分支指向它,由此可證。
  2. 非空二叉樹上葉子節點數等於雙分支節點數+1 證明:由上一條性質可證。設二叉樹葉子節點數爲n0,單分支節點數爲n1,雙分支節點數爲n2,則總結點數n0+n1+n2總分支數2n2+n1。由上一條性質可得,n0+n1+n2-1=2n2+n1。 化簡得:n0=n2+1。(注意,這種證明方法常常被用到
  3. 二叉樹的第i層上最多有2i-1(i>=1)個節點。
  4. 高度爲k的二叉樹最多有2k-1(K>=1)個節點。換句話說滿二叉樹中前k層的結點個數爲2k-1。 證明:等比數列求和問題。
  5. 有n個階段的完全二叉樹,對各節點從上到下,從左到右依次編號(編號範圍1~n),則節點之間有如下關係。 若i爲某節點a的編號,則: 如果i!=1,則雙親節點的編號爲i/2向下取整。 如果2i<=n,則左孩子的編號爲2i;如果2i>n,則a無左孩子。 如果2i+1<=n,則右孩子的編號爲2i+1;如果2i+1>n,則a無右孩子。

 

二叉樹的數據結構

  二叉樹也有順序存儲結構和鏈式存儲結構。順序存儲結構是用數組存儲,下標遵循上面第5條性質,注意下標從1開始。鏈式存儲結構是最常用的存儲二叉樹的結構,如下圖所示。  

二叉樹鏈式存儲結構

其中data表示節點數據域,用與存儲對應的數據元素;lchild和rchild分別表示左指針域和右指針域,分別用於存儲左孩子結點和右孩子結點的位置。定義如下:

typedef struct BTNode
{
	char data;
	struct BTNode *lchild;
	struct BTNode *rchild;
}BTNode

 

二叉樹的算法

  二叉樹的算法主要是遍歷算法,包括

深度遍歷(先序遍歷,中序遍歷,後序遍歷)

廣度遍歷(層次遍歷)。這也是解大多數二叉樹題目的關鍵。   

        三種遍歷(先序遍歷中序遍歷後序遍歷

        ps:這裏不再贅述,直接書上介紹粘貼,字有點醜,湊合看吧哈哈~~

 

 

void PreOrderTraverse(BiTree T) //先序遍歷
{
	if(T!=NULL)
	{
		cout<<T->data<<" ";
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}

void InOrderTraverse(BiTree T)  //中序遍歷
{
	if(T!=NULL)
	{
		InOrderTraverse(T->lchild);
		cout<<T->data<<" ";
		InOrderTraverse(T->rchild);
	}
}

void PostOrderTraverse(BiTree T)   //後序遍歷
{
	if(T!=NULL)
	{
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		cout<<T->data<<" ";
	}
}

 

層次遍歷的僞代碼如下:

根節點入隊
while(隊不空)
{
	節點出隊,並訪問
	if(左子樹不爲空)
		左子樹入隊
	if(右子樹不爲空)
		右子樹入隊
}

  c++代碼如下:   

void LevelOrderTraverse()
{
	int front=0,rear=0;   //定義循環隊列
	BiTNode *que[Maxsize];
	front=rear;
	BiTNode *q;
	if(T!=NULL)          //如果傳過來的樹不爲空
	{
		rear=(rear+1)%Maxsize;
		que[rear]=T;                //根節點入隊
		while (front!=rear)    //隊列不爲空
		{
			front=(front+1)%Maxsize;
			q=que[front];        //隊頭出隊
			cout<<q->data<<" ";    //訪問隊頭
			if (q->lchild!=NULL)       //如果左子樹不空,則左子根入隊
			{
				rear=(rear+1)%Maxsize;
				que[rear]=q->lchild;
			}
			if (q->rchild!=NULL)       //如果右子樹不空,則右子根入隊
			{
				rear=(rear+1)%Maxsize;
				que[rear]=q->rchild;
			}	
		}
	}
}

  這4個算法,就像模板一樣,大多數的二叉樹題目只要會套這個模板就能解決,因此它非常重要。

       二叉樹操作類:

class BinaryTreeOperator   //  二叉樹操作類
{
public:	
	BiTree T;
	BinaryTreeOperator()
	{
		InitBiTree();
	}
	~BinaryTreeOperator()
	{
		DestroyBitree(T);
	}
	void InitBiTree();   //初始化函數
	BiTree CreatBitree(char *str1,char*str2,int i,int j,int k,int l);  //根據先序和後序遍歷結果建立二叉樹
	void DestroyBitree(BiTree T);  //銷燬二叉樹函數
	void PreOrderTraverse(BiTree T);   //遞歸先序遍歷
	void InOrderTraverse(BiTree T);	  //遞歸中序遍歷
	void PostOrderTraverse(BiTree T);    //遞歸後序遍歷
	void NOPreOrder();   //非遞歸先序遍歷
	void NOInOrder();	  //非遞歸中序遍歷
	void NOPostOrder();    //非遞歸後序遍歷
	void LevelOrderTraverse();  //層次遍歷
	void display(BiTree T);    //按二叉樹形態遍歷輸出 
	int BiTreeDepth(BiTree T);    //求二叉樹的深度
	void computelayer();   //標記二叉樹的層數
	int lush();
	void CountLeaf(BiTree T,int &num);   //數葉子
	void Exchange(BiTree T);    //交換左右子樹
	void JudgeTree();    //判斷一棵是否爲完全二叉樹
};

其他參考:http://www.jinrongtong5.com/article/9#

 

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