1. 程式人生 > >二叉樹的先序遍歷-遞迴和非遞迴演算法

二叉樹的先序遍歷-遞迴和非遞迴演算法

需要實踐先序遍歷,我們先建立二叉樹。這裡採用先序序列建立二叉樹,不為別的,因為簡單。

typedef int ElemType;
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild, *rchild;
}*BiTree, BiTNode;

void CreateBiTreePreOrder(BiTree &T){
	ElemType data;
	cin>>data;
	if(data==-1){
		T=NULL;
	}else{
		T = new BiTNode();//(BiTree)malloc(sizeof(BiTNode));
	}
	if(!T){
		return;
	}else{
		T->data = data;
		CreateBiTreePreOrder(T->lchild);
		CreateBiTreePreOrder(T->rchild);
	}
}

下面是對先序遍歷的實現:

① 首先是最簡單的先序遞迴演算法

     遞迴的思想就是將需要重複的步驟分離出來,反覆呼叫,而且下一次的呼叫需要用到上一次呼叫的結果。(可以理解為有依賴關係存在)

//遞迴的先序遍歷
void PreOrder(BiTree T){
	if(T){
		cout<<T->data<<" ";
		PreOrder(T->lchild);
		PreOrder(T->rchild);//這裡的壓棧,只是為了再一次呼叫上面的函式
	}
}

 ②下面來對遞迴演算法進行非遞迴實現

 方法一:模擬遞迴演算法的操作過程。

按照先序的思想,可以轉化為迴圈控制。

  • 入棧前,先輸出本節點資訊;
  • 先左子樹一次入棧,直到沒有左子樹的結點為止;
  • 出棧棧頂元素,然後,找到右子樹,繼續①②操作,直到棧為空 結點為空。

 在遍歷的過程中,進棧、出棧可能會出現棧空的情況,但這時候遍歷還沒有結束, 故而採用雙重判斷。

//先序遍歷非遞迴演算法
void PreOrder(BiTree bt){
	//需要用到棧,這裡簡單寫作一個數組來用, 最好用鏈棧,定義好入棧、出棧的操作介面 
	BiTree T = bt;
	BiTree ptr[20]; 
	int top = -1;
	while(T || top!=-1){
		//按照上面的遍歷,先輸出資料,然後左子樹入棧
		while(T){
			cout<<T->data<<" ";
			ptr[++top]=T;
			T=T->lchild; 
		} 
		if(top!=-1){
			T = ptr[top--];
			T = T->rchild;
		} 
	} 
}

方法二:分析先序遍歷的特點。

 

充分考慮先序遍歷的特點

  • 1入棧。
  • 1出棧(棧頂元素出棧),輸出棧頂元素1,並將1的左右孩子節點入棧;其中右孩子4先入棧,然後左孩子2入棧。(因為,對左邊孩子的訪問先序遍歷先於右孩子,後入棧的先訪問)。
  • 2出棧(棧頂元素出棧),輸出棧頂元素2,並將2的左右孩子節點入棧,同理5先入棧,3後入棧。
  • 3出棧(棧頂元素出棧),輸出棧頂元素33為葉子結點,無孩子,本次無入棧。
  • 5出棧(棧頂元素出棧),輸出棧頂元素5
  • 4出棧(最後的棧頂元素出棧),此時 棧空,遍歷完畢。
void PreOrder(BiTree bt){
	BiTree ptr[20];
	int top = -1;
	BiTree pt = bt;
	ptr[++top] = pt;
	while(top!=-1){
		pt = ptr[top--];//每次棧頂元素出棧
		cout<<pt->data<<" ";//輸出
		if(pt->rchild) 
			ptr[++top] = pt->rchild;
		if(pt->lchild) 
			ptr[++top] = pt->lchild; 
	}
}

 -----------------------------------------分割線------------------------------------------------------------

測試截圖:

 

作者:無涯明月

發文時間:2018-11-16