1. 程式人生 > >二叉樹遍歷非遞迴寫法

二叉樹遍歷非遞迴寫法

來源:http://www.cnblogs.com/BaroC/p/5188545.html

遍歷的非遞迴實現是用棧來實現的,因為棧能提供先入後出。而對於層序遍歷,由於需要遵循層的順序,使用佇列。

1.先序遍歷(中左右)

初始化:根節點入棧。

迴圈:出棧一個節點,訪問這個節點,然後把這個節點的右子樹,左子樹入棧

(由於棧先入後出,所以最後的順序還是中-》左-》右)

Push(T,s);
while(!Empty(s)){
	Tree temp = Pop(s);
	visit(temp);
	Push(temp->Right,s);
	Push(temp->Left,s);
}

2.後序遍歷(左右中)

雙棧實現

初始化:根節點入棧

迴圈:出棧一個節點,把這個節點的右子樹入棧1,然後把這個節點的左子樹入棧1,把根節點放入棧2

放入棧2的順序是根-》右-》左

再訪問一次就是左右中了


完成迴圈以後,訪問順序在棧1中的順序是對的

迴圈2:訪問這個棧

<pre name="code" class="python">Push(T,S1)
while(!Empty(S1)){
	Tree temp = Pop(S1);
	Push(temp->Left,S1);
	Push(temp->Right,S1);
	Push(temp,S2);
}
while(!Empty(S2)){
	Tree temp = Pop(S2);
	visite(temp);
}


3.中序遍歷(左中右)

中序遍歷稍微複雜,使用一個指標p指向下一個待訪問的節點,p初始化為根節點。在每次迴圈中執行以下操作:

  • 如果p非空,則把p入棧,p變為p的左兒子。
  • 如果p為空,說明已經向左走到盡頭了,彈出當前棧頂元素,進行訪問,並把p更新為其右兒子。

也就是說,其實這種做法是先把根節點的所有左子節點全部入棧。這時候就要防止左子節點的重複訪問。

下面的程式碼是錯的,因為會形成迴圈訪問,

Push(T,S1)
p = T;
while(!Empty(S1)){
	if(P->Left){
		P=P->Left;
		Push(P,S1);
	}
	else{
		visit(P);
		if(P->right){
			P=P->right;
			Push(P,S1);
		}
		else{
			P=Pop(S1);
		}
	}

}

void inorder2(Node *root)//非遞迴中序遍歷
{
	stack<Node *> stk;
	Node *p = root;
	while (p != NULL || !stk.empty())
	{
		if (p != NULL)
			stk.push(p), p = p->left;
		else
		{
			p = stk.top(); stk.pop();
			printf("%d ", p->val);
			p = p->right;
		}
	}
}
(上面的程式碼每次都做到了如果有左子節點,一定要訪問到底的要求)