二叉樹先序中序後序深度思考及非遞歸算法程序實現

1.先序遍歷(根左右),中序遍歷(左根右)和後序遍歷(左右根)都可以用遞歸實現,類似於DFS,左子樹都在右子樹之前遍歷,不同的是根的遍歷順序。層序遍歷則類似於BFS。
2.中序序列與先序序列、後序序列、層序序列中的任一個結合都能重構二叉樹,但是沒有中序,兩外的任意兩個或三個組合都不能重構二叉樹,因爲只有靠中序才能區分出左右子樹,而其他三種都只是提供根節點的。
3.二叉樹的先序中序後序遍歷。遍歷過程中經過節點的路線都一樣,只是訪問各節點的時機不同。先序是在第一次將節點入棧前訪問,中序則是在節點出棧時訪問。
後序遍歷非遞歸(比較重要):在出棧一個節點後,要先判斷這個結點的左右孩子節點是否都出棧,若都已出棧,才能讓這個節點出棧。從下面的算法中可以看到,要想訪問該節點,必須將該結點的所有祖先節點都壓入棧中後,才能訪問該節點。
也就是說訪問一個節點p時,棧中節點恰好是p結點的所有祖先,從棧底到棧頂再加上p節點,正好是從根節點到p結點的一條路徑。很多算法都會利用到上述特性:如求根節點到某節點的路徑,求兩個節點的最近公共祖先、輸出根結點到所有葉子結點的路徑等。
4.二叉樹的先序中序非遞歸算法
將二叉樹根節點的所有左節點一一進棧,然後出棧一個結點*p,*p沒有左孩子節點或者左孩子節點已經訪問過了,訪問該節點。然後將該結點的右孩子節點入棧,再重複上述操作,直到棧空爲止。

void inorder2(node* root){
	stack<node*> s;//入棧的是結點的地址
	node* p=root;
	//在遍歷的過程中,出棧入棧可能導致棧空,但此時遍歷並未結束所以這裏採用雙重判斷 
	while(p || !s.empty()  ){//當樹不空或者棧不空時循環 
		while(p){
//printf(“%d ”,p->data);  訪問操作在這裏,就是先序遍歷非遞歸。
			s.push(p);//將根節點及所有的左孩子節點入棧,第一次遇到節點
			p=p->lchild ;
		}
		if(!s.empty()){//棧不空時出棧一個節點 
			p=s.top() ;
s.pop() ;//出棧一個節點,該節點沒有左孩子節點或者左孩子節點均已經訪問過了
			//這裏可以訪問,或者做其他操作,是中序遍歷非遞歸
			printf("%d ",p->data ); 
			//
			p=p->rchild ;//將該出棧結點的右孩子入棧  
		} 	   
	} 	
}
二叉樹的後序遍歷非遞歸算法:
//當用堆棧存儲節點時,必須分清返回根節點時,是從左子樹返回的還是右子樹返回的,所以設置一個輔助指針r,r指向最近訪問過的節點。  
void postorder2(node* root){
	stack<node*> s;//入棧的是結點的地址 
	node* p=root;
	node* r=NULL; //輔助指針r,指向最近訪問過的節點 
	while(p || !s.empty()){
		while(p){
			s.push(p);
			s=s->lchild;
		}
		if(!s.empty()){
			p=s.top();//取棧頂元素地址賦給p 
			s.pop();//彈出棧頂節點
			if(p->rchild==r || p->rchild ==NULL ){//右孩子已經訪問或者右孩子不存在,訪問節點
			 printf("%d ",p->data ); 
			 r=p;//r指向被訪問節點
			 p=NULL;//節點置空,該節點的左右孩子節點均已經被訪問	
			}else{//否則,右孩子節點並未入棧,就不能訪問 
				s.push(p);//否則,將彈出該的節點重新壓入棧 
				p=p->rchild ;//繼續遍歷右子樹 
			} 		 
		}	
	}	
}

5.將層序遍歷中的隊列改爲堆棧的話會怎樣?
如果將其改爲堆棧,並且入棧順序改爲先入右子節點再入左子節點,那麼其順序與先序遍歷一樣。
對於二叉樹的操作,很多都關於遍歷,要分別遍歷左節點,右節點,在遍歷左節點時,右節點怎麼辦呢,則需要數據結構來存儲,棧 或者隊列都行。而且先訪問右節點還是左節點,順序不同,要實現的功能也就不同。
6.樹和圖的區別
1.線性表可以是空表,樹可以是空樹,但圖不可以是空圖,圖中至少有一個頂點,可以沒有邊。
2.樹是圖的子集,可以算是一種特殊的圖,樹存在一對多的關係,圖一對多和多對多都可以。
3.樹有一個根節點,但是圖沒有。樹除根節點外每個節點只有一個前驅,而圖沒有這種關係。樹沒有環,圖可以有環。樹n個頂點一定有n-1條邊,但是圖頂點和邊之間沒有確定關係。圖有不連通的情況,樹一定連通
4.樹有明顯的層次性,圖呈現的是網絡性,更復雜的關係。
7.樹的遍歷和圖的遍歷區別
遍歷就是把節點按照一定規則構成線性序列,不同規則構成不同順序的序列而已。
1.樹的遍歷不需要設置vis數組來標記是否訪問過。因爲不管是先序(根左右)中序(左根右)後序(左右根),樹節點之間有明確的父親孩子關係,都一定只會遍歷一次。而圖各節點之間都只有相鄰關係,所以圖的遍歷都需要vis數組來標記節點是否訪問過。
2.樹的遍歷一般以根節點開始,圖的遍歷可以任選節點。圖有不連通的情況,樹沒有。

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