1. 程式人生 > >非遞迴實現二叉樹遍歷(附c++完整程式碼)

非遞迴實現二叉樹遍歷(附c++完整程式碼)

先序、中序和後序遍歷過程:遍歷過程中經過結點的路線一樣,只是訪問各結點的時機不同。
在這裡插入圖片描述

從圖中可以看到,前序遍歷在第一次遇見元素時輸出,中序遍歷在第二次遇見元素時輸出,後序遍歷在第三次遇見元素時輸出。

非遞迴演算法實現的基本思路:使用堆疊

一、前序遍歷

1、遞迴實現

遍歷過程為:

  1. 訪問根結點;
  2. 先序遍歷其左子樹;
  3. 先序遍歷其右子樹。
void ProOrderTraverse(BiTree tree)
{
	if (tree == NULL)
		return;
	cout << tree->data << " ";
	ProOrderTraverse(tree->
lchild); ProOrderTraverse(tree->rchild); }

2、非遞迴實現

void ProOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	BiTree p = pRoot;
	stack<BiTree>s;

	while (p != NULL || !s.empty())
	{
		while (p != NULL)
		{
			s.push(p);
			cout << p->data << " ";
			p = p->lchild;
		}
		if
(!s.empty()) { p = s.top(); s.pop(); p = p->rchild; } } }

二、中序遍歷

1、遞迴實現

遍歷過程為:

  1. 中序遍歷其左子樹;
  2. 訪問根結點;
  3. 中序遍歷其右子樹。
void midOrderTraverse(BiTree tree)
{
	if (tree == NULL)
		return;
	midOrderTraverse(tree->lchild);
	cout << tree->data << " ";
	midOrderTraverse(tree->
rchild); }

2、非遞迴實現

  1. 遇到一個結點,就把它壓棧,並去遍歷它的左子樹;
  2. 當左子樹遍歷結束後,從棧頂彈出這個結點並訪問它;
  3. 然後按其右指標再去中序遍歷該結點的右子樹。
void midOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	BiTree p = pRoot;
	stack<BiTree>s;
	while (p != NULL || !s.empty())
	{
		while (p!=NULL)
		{
			s.push(p);
			p = p->lchild;
		}
		if (!s.empty())
		{
			p = s.top();
			cout << p->data << " ";		//第二次遇見的時候輸出
			s.pop();
			p = p->rchild;
		}
	}
}

三、後序遍歷

1、遞迴實現

遍歷過程為:

  1. 後序遍歷其左子樹;
  2. 後序遍歷其右子樹;
  3. 訪問根結點。
void postOrderTraverse(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	postOrderTraverse(pRoot->lchild);
	postOrderTraverse(pRoot->rchild);
	cout << pRoot->data<<" ";
}

2、非遞迴實現

第一種思路:對於任一結點P,將其入棧,然後沿其左子樹一直往下搜尋,直到搜尋到沒有左孩子的結點,此時該結點出現在棧頂,但是此時不能將其出棧並訪問, 因此其右孩子還為被訪問。所以接下來按照相同的規則對其右子樹進行相同的處理,當訪問完其右孩子時,該結點又出現在棧頂,此時可以將其出棧並訪問。這樣就 保證了正確的訪問順序。可以看出,在這個過程中,每個結點都兩次出現在棧頂,只有在第二次出現在棧頂時,才能訪問它。因此需要多設定一個變數標識該結點是 否是第一次出現在棧頂。

typedef struct Node
{
	BiTree btnode;
	bool isfirst;
}Node,*node;

void postOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	stack<node>s;
	BiTree p = pRoot;
	node tmp;
	while (p!=NULL || !s.empty())
	{
		while (p != NULL)			//沿左子樹一直往下搜尋,直至出現沒有左子樹的結點
		{
			node btn = (node)malloc(sizeof(Node));
			btn->btnode = p;
			btn->isfirst = true;
			s.push(btn);
			p = p->lchild;
		}
		if (!s.empty())
		{
			tmp = s.top();
			s.pop();
			if (tmp->isfirst == true)	//第一次出現在棧頂
			{
				tmp->isfirst = false;
				s.push(tmp);
				p = tmp->btnode->rchild;
			}
			else				//第二次出現在棧頂
			{
				cout << tmp->btnode->data<<" ";
				p = NULL;
			}
		}
	}
}

第二種思路:要保證根結點在左孩子和右孩子訪問之後才能訪問,因此對於任一結點P,先將其入棧。如果P不存在左孩子和右孩子,則可以直接訪問它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被訪問過了,則同樣可以直接訪問該結點。若非上述兩種情況,則將P的右孩子和左孩子依次入棧,這樣就保證了 每次取棧頂元素的時候,左孩子在右孩子前面被訪問,左孩子和右孩子都在根結點前面被訪問。

void postorder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	stack<BiTree>s;
	BiTree cur = pRoot, pre = NULL;
	s.push(pRoot);
	while (!s.empty())
	{
		cur = s.top();
		if ((cur->lchild == NULL&&cur->rchild == NULL) ||
			((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
		{
			cout << cur->data << " ";
			s.pop();
			pre = cur;
		}
		else
		{
			if (cur->rchild != NULL)
				s.push(cur->rchild);
			if (cur->lchild != NULL)
				s.push(cur->lchild);
		}
	}
}

四、c++完整程式碼

#include<iostream>
#include<stdlib.h>
#include<stack>
using namespace std;
#define len 15						//定義一個長度

typedef int ElemType;

typedef struct BiTNode
{
	ElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

typedef struct Node
{
	BiTree btnode;
	bool isfirst;
}Node,*node;

//向下遍歷,找到節點s應該插入的位置,節點有重複時,忽略這個節點
void SearchTreeNode(BiTree &root, BiTree &s)	//注意:使用引用傳遞
{
	if (root == NULL)
		return;
	if (s->data > root->data)
	{
		if (root->rchild == NULL)
		{
			root->rchild = s;
			return;
		}
		SearchTreeNode(root->rchild, s);//s值大於根節點值,未到達葉子節點,繼續向右孩子遍歷
	}

	else if (s->data < root->data)
	{
		if (root->lchild == NULL)
		{
			root->lchild = s;
			return;
		}
		SearchTreeNode(root->lchild, s);//s值小於根節點值,未到達葉子節點,繼續向左孩子遍歷
	}
}

//插入一個節點,樹為空,插入節點即為根節點,否則找合適的位置插入
void InsertNode(BiTree &tree, BiTree &s)		//注意:使用引用傳遞
{
	if (tree == NULL)
		tree = s;
	else
		SearchTreeNode(tree, s);
}

//二叉排序樹建立,每次增加一個結點,插到現有的二叉樹上去
void CreateOrderBinaryTree(BiTree &tree, int *a)
{
	for (int i = 0; i < len; i++)
	{
		BiTree s = (BiTree)malloc(sizeof(BiTNode));
		s->data = a[i];
		s->lchild = NULL;
		s->rchild = NULL;
		InsertNode(tree, s);
	}
}
//前序遍歷
void ProOrderTraverse(BiTree tree)
{
	if (tree == NULL)
		return;
	cout << tree->data << " ";
	ProOrderTraverse(tree->lchild);
	ProOrderTraverse(tree->rchild);
}
//非遞迴前序遍歷
void ProOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	BiTree p = pRoot;
	stack<BiTree>s;

	while (p != NULL || !s.empty())
	{
		while (p != NULL)
		{
			s.push(p);
			cout << p->data << " ";		//第一次遇見的時候輸出
			p = p->lchild;
		}
		if (!s.empty())
		{
			p = s.top();
			s.pop();
			p = p->rchild;
		}
	}
}

//中序遍歷
void midOrderTraverse(BiTree tree)
{
	if (tree == NULL)
		return;
	midOrderTraverse(tree->lchild);
	cout << tree->data << " ";
	midOrderTraverse(tree->rchild);
}

//非遞迴中序遍歷
void midOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	BiTree p = pRoot;
	stack<BiTree>s;
	while (p != NULL || !s.empty())
	{
		while (p!=NULL)
		{
			s.push(p);
			p = p->lchild;
		}
		if (!s.empty())
		{
			p = s.top();
			cout << p->data << " ";		//第二次遇見的時候輸出
			s.pop();
			p = p->rchild;
		}
	}
}

//後序遍歷
void postOrderTraverse(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	postOrderTraverse(pRoot->lchild);
	postOrderTraverse(pRoot->rchild);
	cout << pRoot->data<<" ";
}

//非遞迴實現後續遍歷
void postOrder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	stack<node>s;
	BiTree p = pRoot;
	node tmp;
	while (p!=NULL || !s.empty())
	{
		while (p != NULL)		//沿左子樹一直往下搜尋,直至出現沒有左子樹的結點
		{
			node btn = (node)malloc(sizeof(Node));
			btn->btnode = p;
			btn->isfirst = true;
			s.push(btn);
			p = p->lchild;
		}
		if (!s.empty())
		{
			tmp = s.top();
			s.pop();
			if (tmp->isfirst == true)			//第一次出現在棧頂
			{
				tmp->isfirst = false;
				s.push(tmp);
				p = tmp->btnode->rchild;
			}
			else						//第二次出現在棧頂
			{
				cout << tmp->btnode->data<<" ";
				p = NULL;
			}
		}
	}
}

//非遞迴實現後續遍歷
void postorder(BiTree pRoot)
{
	if (pRoot == NULL)
		return;
	stack<BiTree>s;
	BiTree cur = pRoot, pre = NULL;
	s.push(pRoot);
	while (!s.empty())
	{
		cur = s.top();
		if ((cur->lchild == NULL&&cur->rchild == NULL) ||
			((pre == cur->lchild || pre == cur->rchild) && pre != NULL))
		{
			cout << cur->data << " ";
			s.pop();
			pre = cur;
		}
		else
		{
			if (cur->rchild != NULL)
				s.push(cur->rchild);
			if (cur->lchild != NULL)
				s.push(cur->lchild);
		}
	}
}

int main()
{
	int a[len] = { 62, 88, 58, 47, 35, 73, 51, 99, 37, 93, 23, 27, 45, 21, 12 };

	BiTree tree = NULL;
	//建立一個二叉樹,並中序遍歷
	CreateOrderBinaryTree(tree, a);

	cout << "前序遍歷" << endl;
	ProOrderTraverse(tree);
	cout << endl;
	ProOrder(tree);
	cout << endl<<endl;

	cout << "中序遍歷" << endl;
	midOrderTraverse(tree);
	cout << endl;
	midOrder(tree);
	cout << endl<<endl;

	cout << "後序遍歷" << endl;
	postOrderTraverse(tree);
	cout << endl;
	postOrder(tree);
	cout << endl;
	postorder(tree);
	cout << endl<<endl;

	return 0;
}