1. 程式人生 > >二、(3)二叉樹的後序遍歷(遞迴實現、迭代實現)

二、(3)二叉樹的後序遍歷(遞迴實現、迭代實現)

二叉樹本來是分層結構,但若施加某種約束(如遍歷),則可以轉變成線性結構。

二叉樹的遍歷方法主要有:前序遍歷(DLR),中序遍歷(LDR),後序遍歷(LRD),層次遍歷。本文主要介紹二叉樹後序遍歷方法,其中包括了遞迴和迭代兩種實現方式。

後序遍歷:左子樹->右子樹->根節點(根節點在最後面

例如:

                                   

上圖所示的二叉樹的後序遍歷順序為:6 3 4 1 7 5 2 0

本文使用的二叉樹資料結構參見之前部落格:https://blog.csdn.net/qq_18108083/article/details/84727888

(1) 遞迴版本(簡潔易懂,但是遞迴過程會導致函式呼叫棧的頻繁進棧出棧,時間複雜度高,而且每次遞迴均重複定義變數,且儲存現場也需要額外的空間,所以空間複雜度也高)

template<typename T> void binTree<T>::travPost_R(binNode<T>* bn_r, void(*func)(T& bn))
{
	if (!bn_r) return;
	travPost_R(bn_r->lc, func);
	travPost_R(bn_r->rc, func);
	func(bn_r->data);
}

(2) 迭代版本(相對於遞迴版本,其等效的迭代版本具有更小的時間複雜度和空間複雜度,這也是一般演算法推薦迭代版本的原因,但是迭代版本的實現相對更加複雜)

template<typename T> void binTree<T>::gotoHLVFL(stack<binNode<T>*> &s)
{
	while (binNode<T>* bn_i = s.top())
	{
		if (bn_i->lc)
		{
			if (bn_i->rc)
				s.push(bn_i->rc);
			s.push(bn_i->lc);
		}
		else
		{
			s.push(bn_i->rc);
		}
	}
	s.pop();
}

template<typename T> void binTree<T>::travPost_I(binNode<T>* bn_i, void(*func)(T& bn))
{
	stack<binNode<T>*> S;
	if (bn_i)
		S.push(bn_i);
	while (!S.empty())
	{
		if (S.top() != bn_i->parent)
			gotoHLVFL(S);
		bn_i = S.pop();
		func(bn_i->data);
	}
}

執行結果:

  

總結:二叉樹前序遍歷的上述遞迴方式和迭代方式都能實現正確的遍歷,遞迴版本容易理解,但是效率會略低,當然一般也是可以忽略的,而迭代版本效率上會有所提升,相對之下更加難懂,具體選擇哪種根據需要吧。