遞歸法和非遞歸法遍歷二叉樹

遍歷二叉樹

  • 遍歷定義:順着某一條搜索路徑巡防二叉樹中的結點,使得每個結點均被訪問一次,而且僅被訪問一次(又稱周遊)。
  • 遍歷目的:得到樹中所有結點得一個線性排列。
  • 遍歷用途:它是樹結構插入、刪除、修改、查找和排序運算得前提,是二叉樹一切運算得基礎和核心。
  • 遍歷方法:
    在這裏插入圖片描述
    依次遍歷二叉樹中的三個組成部分,便是遍歷了整個二叉樹
    假設:L:遍歷左子樹 D:訪問根結點 R:遍歷右子樹
    則遍歷整個二叉樹方案共有:
    DLR、LDR、LRD、DRL、RDL、RLD六種。

1.遍歷二叉樹遞歸算法描述

若規定先左後右,則只有前三種情況:
DLR ——先(根)序遍歷
LDR——中(根)序遍歷
LRD——後(根)序遍歷
在這裏插入圖片描述

先序遍歷二叉樹的操作定義

  • 若二叉樹爲空,則空操作;否則:
    1.訪問根結點(D);
    2.先序遍歷左子樹(L);
    3.先序遍歷右子樹(R)。
Status PreOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;  //空二叉樹
    else{
         cout << T->data;  //訪問根結點 
	     PreOrderTraverse(T->lchild); //先序遍歷左子樹 
	     PreOrderTraverse(T->rchild); //先序遍歷右子樹
	    } 
}	

在這裏插入圖片描述

中序遍歷二叉樹的操作定義

  • 若二叉樹爲空,則空操作;否則
    1.中序遍歷左子樹(L);
    2.訪問根結點(D);
    3.中序遍歷右子樹(R)。
Status InOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;
    else{
	     InOrderTraverse(T->lchild); //中序遍歷左子樹 
	     cout << T->data;  //訪問根結點 
	     InOrderTraverse(T->rchild); //中序遍歷右子樹
	    } 
}

在這裏插入圖片描述

後序遍歷二叉樹的操作定義

  • 若二叉樹爲空,則空操作;否則
    1.後序遍歷左子樹;
    2.後序遍歷右子樹;
    3.訪問根結點。
Status PostOrderTraverse(BiTree T)
{
    if(T==NULL) return OK;
    else{
	     PostOrderTraverse(T->lchild); //後序遍歷左子樹 
	     PostOrderTraverse(T->rchild); //後序遍歷右子樹
	     cout << T->data;  //訪問根結點
	    } 
}	

在這裏插入圖片描述

遍歷算法的分析

  • 如果去掉輸出語句,從遞歸的角度看,三種算法是完全相同的,或說這三種算法的訪問路徑是相同的,只是訪問結點的時機不同。
    從虛線的出發點到終點的路徑上,每個結點經過3次。
    在這裏插入圖片描述
    在這裏插入圖片描述
  • 時間效率:O(n) //每個結點只訪問一次
  • 空間效率:O(n) //棧佔用的最大輔助空間

2.中序非遞歸算法描述

基本思想
1.建立一個
2.結點進棧,遍歷左子樹
3.結點出棧,輸出根結點,遍歷右子樹

【算法步驟】
①初始化一個空棧 S,指針 p 指向根結點
②申請一個結點空間 q,用來存放棧頂彈出的元素
③當 p 非空或者棧 S 非空時,循環執行以下操作:

如果 p 非空,則將 p 進棧,p指向該結點的左孩子
如果 p 爲空,則彈出棧頂元素並訪問,將p指向該結點的右孩子
【算法描述】

Status InOrderTraverse(BiTree T)
{
	BiTree p; InitStack(S); p=T;
	while(p || !StackEmpty(S))
	{
		if(p) { Push(S,p); p = p->lchild; }
		else  { Pop(S,q); cout << q->data; //Pop(S,q),將棧頂元素彈出,並使q指向該元素 
	           p = q->rchild; }	
	} // while
	return OK;  
}	

3.層次遍歷算法

對於一顆二叉樹,從根結點開始,按從上到下,從左到右的順序訪問每一個結點。(每個結點僅訪問一次)
算法設計思路:使用一個隊列
I. 將根結點進隊;
II.隊不空時循環:從隊列中出列一個結點*p,訪問它:
①若它有左孩子結點,將左孩子結點進隊
②若它有右孩子結點,將右孩子結點進隊

使用隊列類型定義如下:

typedef struct{
    BTNode data[MaxSize];  //存放隊中元素
    int front, rear;       //隊頭和隊尾指針
}SqQueue;                  //順序循環隊列類型    

二叉樹層次遍歷算法:

void LevelOrder(BTNode *b)
{
	BTNode *p; SqQueue *qu;
	InitQueue(qu);    //初始化隊列 
	enQueue(qu,b);    //根結點指針進入隊列 
	while(!QueueEmpty(qu)) //隊不爲空,則循環 
	{
		deQueue(qu,p);     //出隊結點p 
		cout << p->data;
		if(p->lchild!=NULL) enQueue(qu,p->lchild);
		                    //有左孩子時將其進隊 
		if(p->rchild!=NULL) enQueue(qu,p->rchild);
	}                       //有右孩子時將其進隊 	
}

4.根據遍歷序列確定二叉樹

  • 若二叉樹中各結點的值均不相同,則二叉樹結點的先序序列、中序序列和後序序列都是唯一的。
  • 由二叉樹的先序序列和中序序列,或由二叉樹的後序序列和中序序列可以確定唯一一個二叉樹。

在這裏插入圖片描述

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