1. 程式人生 > >鏈式二叉樹 先序、中序、後序 遍歷(遞迴、非遞迴)

鏈式二叉樹 先序、中序、後序 遍歷(遞迴、非遞迴)

參考部落格click here!

鏈式二叉樹儲存結構:

typedef int DataType;

typedef struct BiNode {
	DataType data;
	struct BiNode *lc, *rc;		// 左右子節點指標
	int depth;
} BiNode, *BiTree;

初始化:

void rootInit(BiTree &root)
{
	root = NULL;
	assert(!root);			// 檢查root是否合法
	return;
}

先序遍歷: 根左右

遞迴先序遍歷遵循條件:
先訪問根節點, 然後訪問左子節點, 最後訪問右子節點。(根左右)
二叉樹為空則停止遞迴

void PreOrder(BiTree &root)			// 遞迴先序遍歷
{
	if(root == NULL)
		return;
	cout << root->data << " ";
	PreOrder(root->lc);
	PreOrder(root->rc);
}

非遞迴版本的先序遍歷:

1.若根節點為空(空樹,不需要遍歷),直接返回;

2.否則,將根節點入棧;

3.判斷棧是否為空,不為空進入迴圈;

4.取棧頂結點並訪問該節點,同時將該節點出棧;

5.若該節點的右子樹不為空,將右孩子結點入棧;

6.若該節點的左子樹不為空,將左孩子節點入棧;

7.直到棧為空,跳出迴圈,完成了先序遍歷

void PreOrder2(BiTree &root)		// 非遞迴先序遍歷
{
	stack<BiTree> s;	// 定義一個棧
	while( !s.empty()) s.pop();	// 清空
	if(root != NULL)
		s.push(root);
	BiTree tmp;			// 臨時
	while( !s.empty())			// 棧不為空
	{
		tmp = s.top();			// 獲得棧頂元素
		s.pop();
		cout << tmp->data << " ";
		if(tmp->lc != NULL)		// 先序遍歷,必須先判斷右子樹
			s.push(tmp->rc);
		if(tmp->rc != NULL)		// 判斷右子樹
			s.push(tmp->lc);

	}
	cout << endl;
	return;
}

中序遍歷:左根右

遞迴中序遍歷遵循條件:    若二叉樹為空,直接返回;

1.遍歷二叉樹的左子樹
2.訪問根節點
3.遍歷二叉樹的右子樹

void MidOrder(BiTree &root)		// 中序遍歷 遞迴
{
	if(root == NULL)
		return;
	MidOrder(root->lc);		// 先左
	cout << root->data << " ";	// 然後根
	MidOrder(root->rc);		// 最後右
}

非遞迴中序遍歷:

1.若樹為空,直接返回;否則令tmp=root,進入迴圈(跳出條件為棧為空 或 tmp==NULL)

2.迴圈的將tmp節點的所有左子樹入棧

3.取棧頂結點為tmp,訪問該節點並出棧

4.令tmp=tmp的右孩子,進入下一次迴圈

void MidOrder2(BiTree &root)	// 中序遍歷 非遞迴
{
	stack<BiTree> s;
	while( !s.empty()) s.pop();

	BiTree tmp = root;
	while( !s.empty() || tmp != NULL)
	{
		while(tmp != NULL)		//	中序遍歷,先向左邊找, 左邊沒有就輸出根
		{
			s.push(tmp);
			tmp = tmp->lc;
		}
		tmp = s.top();
		cout << tmp->data << " ";	// 然後根
		tmp = tmp->rc;				// 向右
		s.pop();
	}
	cout << endl;
}

後續遍歷:左右根

遞迴後序遍歷

void PostOrder(BiTree &root)	// 後序遍歷
{
	if(root == NULL)
		return;
	PostOrder(root->lc);		// left
	PostOrder(root->rc);		// right
	cout << root->data << " ";	// root
}

非遞迴後序遍歷:

1.若樹為空,直接返回;否則令tmp= root,進入迴圈(條件為棧非空或tmp!=NULL)

2.迴圈的將所有左子樹入棧;

3.去棧頂結點,若該節點沒有右子樹或者右子樹已經訪問過了,則訪問該節點並出棧;

4.否則,令tmp為該節點的右子樹,進入下一層迴圈。

void PostOrder2(BiTree &root)	// 非遞迴後序遍歷
{
	stack<BiTree> s;
	while( !s.empty()) s.pop();

	BiTree tmp = root;
	BiTree pre = NULL; 			// 記錄先前剛訪問過的結點
	BiTree top;					// 用於臨時儲存棧頂結點
	while( !s.empty() || tmp != NULL)
	{
		while(tmp != NULL)		// 先一直向左
		{
			s.push(tmp);
			tmp = tmp->lc;
		}
		top = s.top();
		if(top->rc == NULL || top->rc == pre)	// 如果右子節點為空或者已經訪問過
		{	// 如果沒有右子節點或者已經訪問過就輸出當前子樹的根節點,並出棧
			cout << top->data << " ";
			pre = top;		// 用於從右子節點回溯的時候判斷右子節點是否已經訪問過
			s.pop();
		}
		else
			tmp = top->rc;

	}
}

完整程式碼:

#include <iostream>
#include <assert.h>
#include <stack>
using namespace std;
typedef int DataType;

typedef struct BiNode {
	DataType data;
	struct BiNode *lc, *rc;		// 左右子節點指標
	int depth;
} BiNode, *BiTree;

void rootInit(BiTree &root)
{
	root = NULL;
	assert(!root);			// 檢查root是否合法
	return;
}

/* 先序遍歷 根左右 */
void PreOrder(BiTree &root)			// 遞迴先序遍歷
{
	if(root == NULL)
		return;
	cout << root->data << " ";
	PreOrder(root->lc);
	preOrder(root->rc);
}
void PreOrder2(BiTree &root)		// 非遞迴先序遍歷
{
	stack<BiTree> s;	// 定義一個棧
	while( !s.empty()) s.pop();	// 清空
	if(root != NULL)
		s.push(root);
	BiTree tmp;			// 臨時
	while( !s.empty())			// 棧不為空
	{
		tmp = s.top();			// 獲得棧頂元素
		s.pop();
		cout << tmp->data << " ";
		if(tmp->lc != NULL)		// 先序遍歷,必須先判斷右子樹
			s.push(tmp->rc);
		if(tmp->rc != NULL)		// 判斷右子樹
			s.push(tmp->lc);

	}
	cout << endl;
	return;
}

/* 中序遍歷 左根右 */
void MidOrder(BiTree &root)		// 中序遍歷 遞迴
{
	if(root == NULL)
		return;
	MidOrder(root->lc);		// 先左
	cout << root->data << " ";	// 然後根
	MidOrder(root->rc);		// 最後右
}
void MidOrder2(BiTree &root)	// 中序遍歷 非遞迴
{
	stack<BiTree> s;
	while( !s.empty()) s.pop();

	BiTree tmp = root;
	while( !s.empty() || tmp != NULL)
	{
		while(tmp != NULL)		//	中序遍歷,先向左邊找, 左邊沒有就輸出根
		{
			s.push(tmp);
			tmp = tmp->lc;
		}
		tmp = s.top();
		cout << tmp->data << " ";	// 然後根
		tmp = tmp->rc;				// 向右
		s.pop();
	}
	cout << endl;
}

/* 後序遍歷 左右根 */
void PostOrder(BiTree &root)	// 後序遍歷
{
	if(root == NULL)
		return;
	PostOrder(root->lc);		// left
	PostOrder(root->rc);		// right
	cout << root->data << " ";	// root
}
void PostOrder2(BiTree &root)	// 非遞迴後序遍歷
{
	stack<BiTree> s;
	while( !s.empty()) s.pop();

	BiTree tmp = root;
	BiTree pre = NULL; 			// 記錄先前剛訪問過的結點
	BiTree top;					// 用於臨時儲存棧頂結點
	while( !s.empty() || tmp != NULL)
	{
		while(tmp != NULL)		// 先一直向左
		{
			s.push(tmp);
			tmp = tmp->lc;
		}
		top = s.top();
		if(top->rc == NULL || top->rc == pre)	// 如果右子節點為空或者已經訪問過
		{	// 如果沒有右子節點或者已經訪問過就輸出當前子樹的根節點,並出棧
			cout << top->data << " ";
			pre = top;		// 用於從右子節點回溯的時候判斷右子節點是否已經訪問過
			s.pop();
		}
		else
			tmp = top->rc;

	}
}

int main()
{







	return 0;
}