在看慕課上面浙大數據結構時很巧合的想到的寫法,感謝浙大陳越、何欽銘老師:
一個二叉樹的遍歷分前中後序的遍歷,這裏前中後序是如何遍歷的就不多說了。
先給大家看這張圖:
按照讀出來的順序是前序遍歷,正好是第一次經過該節點
按照讀出來的順序是中序遍歷,正好是第二次經過該節點
按照讀出來的順序是後序遍歷,正好是第三次經過該節點
那麼我們的出來一個結論:按照第1、2、3次經過該節點讀出來的順序就是二叉樹的 前、中、後 遍歷了,且每個節點被經過了3次
那麼我們可以用一個棧存放這些路徑上的節點,另一個棧存放對應位置的節點是第幾次經過,那麼不就能實現前中後序的非遞歸的遍歷了嘛:
typedef struct Tree
{
char data;
struct Tree *lchild;
struct Tree *rchild;
} Tree, *Index_Tree;
/**
對於一個二叉樹,整個遞歸遍歷過程每個節點經過了3次;
那麼實現非遞歸遍歷時可以:
申請一個棧A用來存貯節點,
另外申請一個棧B用來存貯對應節點位置經過了幾次
先把根節點入棧A,並把1入棧B
A棧不爲空就一直循環:
當第一次訪問一個節點時,先訪問它的左子樹:
if 爲空
B棧頂元素置爲2, 因爲左子樹爲空,說明再次訪問到了當前節點;
else
左子樹入棧A,並1入棧B 因爲第一次訪問到左子樹
當第二次訪問到一個節點時,訪問它的右子樹;
if 爲空
B棧頂元素置3 因爲右子樹爲空,說明又返回到了當前節點;
else
將右子樹入棧A,並1入棧B 因爲右子樹第一次被訪問到
當第三次訪問到一個節點時
讓它出棧, 即A、B棧頂元素出棧
並且 在上面的基礎上,B棧頂元素+1 因爲又再次訪問到該元素了
**/
void Stack_Pri_Order(Index_Tree T, int x) ///x爲1時前序遍歷,x爲2時中序遍歷, x爲3時後序遍歷
{
if(!T) ///二叉樹不存在返回
return ;
Index_Tree p;
stack<Index_Tree> node;
stack<int> flag;
node.push(T);
flag.push(1);
while(!node.empty())
{
if(flag.top() == 1) ///第一次訪問該節點
{
p = node.top();
if(x == 1)
printf("%c", p->data);
if(!p->lchild)
{
flag.pop();
flag.push(2);
}
else
{
node.push(p->lchild);
flag.push(1);
}
}
else if(flag.top() == 2) ///第二次訪問該節點
{
p = node.top();
if(x == 2)
printf("%c", p->data);
if(!p->rchild)
{
flag.pop();
flag.push(3);
}
else
{
node.push(p->rchild);
flag.push(1);
}
}
else ///第三次訪問該節點
{
p = node.top();
if(x == 3)
printf("%c", p->data);
node.pop();
flag.pop();
if(!flag.empty()) ///如果根節點沒有出來,就要讓現在的棧頂元素+1
{
int a = flag.top();
flag.pop();
flag.push(++a);
}
}
}
return ;
}