1. 程式人生 > >資料結構-二叉樹遍歷

資料結構-二叉樹遍歷

這篇博文主要是研究二叉樹遍歷的遞迴與非遞迴演算法,有興趣的小夥伴可以瞭解下!

二叉樹的遞迴遍歷(深度優先遍歷)

先來張圖,看看各結點遍歷時的情況:

二叉樹深度優先遍歷總結(分別為第一次,第二次,第三次進入某個結點):

  1. 先序遍歷:先訪問根結點,然後先序遍歷左子樹,最後先序遍歷右子樹;根->左->右
  2. 中序遍歷:先中序遍歷左子樹,然後訪問根結點,最後中序遍歷右子樹;左->根->右
  3. 後續遍歷:先後序遍歷左子樹,然後後序遍歷右子樹,最後訪問根結點;左->右->根

遞迴遍歷內部有系統棧,其作用:

  • 1.保護現場(類似存檔)
  • 2.恢復現場(類似讀檔)

 

遞迴遍歷程式碼比較簡單,先、中、後序遍歷遞迴程式碼基本相似,總程式碼:

void r(BTNode *p)
{
	if (p != NULL)
	{
		//第一次進入-先序
		r(p->lchild);
		//第二次進入-中序
		r(p->rchild);
		//第三次進入-後序
	}
}

先序遍歷遞迴函式:

void r(BTNode *p)
{
	if (p != NULL)
	{
		visit(p);
		r(p->lChild);
		r(p->rChild);
	}
}

 

二叉樹的非遞迴遍歷(深度優先遍歷)

須知:需要自定製輔助棧

1.先序遍歷非遞迴:

1).利用輔助棧將根節點入棧,出棧操作,訪問該節點,將其右、左孩子分別入棧(每次訪問節點後,對其左、右孩子需要做一個檢測,為空的孩子無需入棧)
2).左孩子出棧,訪問該節點,將其右、左孩子分別入棧,多次操作!
3).直至棧空為止(出棧是在迴圈之內執行,即使棧空也會執行右左孩子入棧操作)

void preorderNonrecursion(BTNode *bt)
{
	if (bt != NULL)								//根節點是否為空
	{
		BTNode *Stack[maxSize];
		int top = -1;							//建立棧
		BTNode *p = NULL;						//遍歷指標
		Stack[++top] = bt;						//節點入棧
		while(top != -1)						//棧不空時迴圈
		{	
			p = Stack[top--];					//出棧一個元素
			Visit(p);							//訪問
			if(p->rChild != NULL)				//右孩子不為空就入棧
				Stack[++top] = p->rChild;
			if(p->lChild != NULL)				//左孩子不為空就入棧
				Stack[++top] = p->lChild;	
		}
	}
}

2.後序遍歷非遞迴:

// 先序(根左右),而後序(左右根),將後序逆轉為逆後序(根右左),逆後序的左右交換即可成為前序(根左右)
// 在這我們可以使用逆後序(根右左),把逆後序的結果壓入一個新棧,出棧就得到後序遍歷序列

1).將根節點入輔助棧(棧1),出棧操作,將出棧後的該元素入逆序棧(棧2),將其左、右孩子分別入輔助棧(每次對其左、右孩子需要做一個檢測,為空的孩子無需入棧);
2).右孩子出輔助棧(棧1),將出棧後的該元素入逆序棧(棧2),將其左、右孩子分別入輔助棧(棧1),多次操作;
3).直至輔助棧空為止,出棧是在迴圈之內執行,即使棧空也會執行左右孩子入棧操作;
4).逆序棧(棧2)中元素逐個出棧並訪問

void postorderNonrecursion(BTNode *bt)
{
	if (bt != NULL)								//根節點不為空
	{
		BTNode *Stack1[maxSize];int top1= -1;	//建立棧1(輔助遍歷的棧)
		BTNode *Stack2[maxSize];int top2= -1;	//建立棧2(結果逆序的棧)					
		BTNode *p = NULL;						//遍歷指標
		Stack1[++top1] = bt;					//節點入棧1
		while(top1 != -1)						//棧不空時迴圈
		{	
			p = Stack1[top1--];					//棧1出棧一個元素
			Stack2[++top2] = p;					//出棧元素入棧2							
			if(p->lChild != NULL)				//左孩子不為空就入棧
				Stack[++top] = p->lChild;
			if(p->rChild != NULL)				//右孩子不為空就入棧
				Stack[++top] = p->rChild;				
		}
		while(top2 != -1)
		{
			p = Stack2[top2--];					//棧2元素逐個出棧
			Visit(p);							//訪問
		}
	}
}

3.中序遍歷非遞迴程式碼

1).從根節點開始,一直左走,並把途徑的左孩子節點入棧;
2).遇到左孩子為空時,棧頂元素出棧,訪問該節點,p指向該節點的右孩子;
3).直到棧空或者P為NULL則遍歷結束

void inorderNonrecursion(BTNode *bt)
{
	if(bt != NULL)								//樹不空
	{
		BTNode *Stack[maxSize];int top = -1;	//建立棧							
		BTNode *p = NULL;						//遍歷指標
		p = bt;									//節點入棧1
		while(top1 != -1 || p != NULL)			//棧不空或者p不空
		{	
			while(p != NULL)
			{
				Stack[++top] = p;				//入棧
				p = p->lChild;					//左走
			}										
			if(top != -1)						
			{
				p = Stack[top--];				//出棧
				Visit(p);						//訪問該節點
				p = p->rChild;					//右走
			}			
		}		
	}
}