1. 程式人生 > >樹的先序遍歷、中序遍歷、後序遍歷、層次遍歷的非遞迴演算法

樹的先序遍歷、中序遍歷、後序遍歷、層次遍歷的非遞迴演算法

Written by Robert_Wang in Southwest University of Science And Technology.

這裡提出用非遞迴遍歷的原因是:用遞迴遍歷雖然方便,但是不能遞迴太深,否則會 stack overflow

先序遍歷這裡有兩種遍歷方法

void PreOrder1(Btree*b)
{
	stack<node*>s;
	Btree *p;
	//if (b) s.push(b);
	if (b)
	{
		while (b || !s.empty())
		{
			while (b)
			{
				cout << b->data << " ";
				s.push(b);
				b = b->lchild;
			}
			if (!s.empty())
			{
				p = s.top();
				s.pop();
				if (p->rchild) s.push(p->rchild);
			}
		}
	}
}
void PreOrder2(Btree*b)
{
	stack<Btree*>s;
	Btree *p;
	if (b)
	{
		s.push(b);
		while (!s.empty())
		{
			p = s.top();
			s.pop();
			cout << p->data << " ";
			if (p->rchild) s.push(p->rchild);
			if (p->lchild) s.push(p->lchild);
		}
	}
}

中序遍歷只需要在上面的程式碼的基礎上稍作改動

//中序遍歷的非遞迴遍歷
void InOrder(Btree*b)
{
	Btree*p;
	stack<Btree*>s;
	if (b)
	{
		while (b || !s.empty())
		{
			while (b)
			{
				s.push(b);
				b = b->lchild;
			}
			if (!s.empty())
			{
				p = s.top();
				s.pop();
				cout << p->data << " ";
				if (p->rchild) s.push(p->rchild);
			}
		}
	}
}

後續遍歷就要先走到最左端,再看右兒子是否為空或者已經被訪問過

如果沒有訪問過,轉向右子樹,迴圈退一層,繼續走到最左端,

如果訪問過或者為空,則訪問該根結點元素,退棧一次

//後序遍歷的非遞迴演算法
void PostOrder(Btree*b)
{
	Btree*p,*r;
	stack<Btree*>s;
	p = b;
	bool flag;
	do
	{
		while (p)
		{
			s.push(p);
			p = p->lchild;
		}
		r = NULL;
		flag = true;//flag == true 表示正在處理棧頂結點
		while (!s.empty() && flag)
		{
			p = s.top();
			if (p->rchild == r)//如果右子樹為空或者已經被訪問過
			{
				cout << p->data << " ";
				s.pop();
				r = p;
			}
			else
			{
				p = p->rchild;
				flag = false;
			}
		}

	} while (!s.empty());
}

層次遍歷就是一個BFS演算法

void LevelOrder(Btree*b)
{
	queue<Btree*>q;
	Btree*p;
	if (b)
	{
		q.push(b);
		while (!q.empty())
		{
			p = q.back();
			q.pop();
			cout << p->data << " ";
			if (p->lchild) q.push(p->lchild);
			if (p->rchild) q.push(p->rchild);
		}
	}
}

和在一起就是

#include<iostream>
#include<stack>
#include<queue>
using namespace std;
typedef struct node
{
	int data;
	struct node *lchild;
	struct node *rchild;
}Btree;
//非遞迴演算法
void PreOrder1(Btree*b)
{
	stack<node*>s;
	Btree *p;
	//if (b) s.push(b);
	if (b)
	{
		while (b || !s.empty())
		{
			while (b)
			{
				cout << b->data << " ";
				s.push(b);
				b = b->lchild;
			}
			if (!s.empty())
			{
				p = s.top();
				s.pop();
				if (p->rchild) s.push(p->rchild);
			}
		}
	}
}
void PreOrder2(Btree*b)
{
	stack<Btree*>s;
	Btree *p;
	if (b)
	{
		s.push(b);
		while (!s.empty())
		{
			p = s.top();
			s.pop();
			cout << p->data << " ";
			if (p->rchild) s.push(p->rchild);
			if (p->lchild) s.push(p->lchild);
		}
	}
}
//中序遍歷的非遞迴遍歷
void InOrder(Btree*b)
{
	Btree*p;
	stack<Btree*>s;
	if (b)
	{
		while (b || !s.empty())
		{
			while (b)
			{
				s.push(b);
				b = b->lchild;
			}
			if (!s.empty())
			{
				p = s.top();
				s.pop();
				cout << p->data << " ";
				if (p->rchild) s.push(p->rchild);
			}
		}
	}
}
//後序遍歷的非遞迴演算法
void PostOrder(Btree*b)
void PostOrder(Btree*b)
{
	Btree*p,*r;
	stack<Btree*>s;
	p = b;
	bool flag;
	do
	{
		while (p)
		{
			s.push(p);
			p = p->lchild;
		}
		r = NULL;
		flag = true;//flag == true 表示正在處理棧頂結點
		while (!s.empty() && flag)
		{
			p = s.top();
			if (p->rchild == r)//如果右子樹為空或者已經被訪問過
			{
				cout << p->data << " ";
				s.pop();
				r = p;
			}
			else
			{
				p = p->rchild;
				flag = false;
			}
		}

	} while (!s.empty());
}
//層次遍歷
void LevelOrder(Btree*b)
{
	queue<Btree*>q;
	Btree*p;
	if (b)
	{
		q.push(b);
		while (!q.empty())
		{
			p = q.back();
			q.pop();
			cout << p->data << " ";
			if (p->lchild) q.push(p->lchild);
			if (p->rchild) q.push(p->rchild);
		}
	}
}
void CreateTree(Btree*&b)
{
	b = new Btree;
	b->lchild = b->rchild = NULL;
	int x;
	cin >> x;
	if (x != 0)
	{
		b->data = x;
		CreateTree(b->lchild);
		CreateTree(b->rchild);
	}
	else b = NULL;
}
int main()
{
	Btree*b;
	CreateTree(b);
	cout << "先序遍歷演算法1如下:" << endl;
	PreOrder1(b);
	cout << "先序遍歷演算法2如下:" << endl;
	PreOrder2(b);
	cout << "中序遍歷演算法如下:" << endl;
	InOrder(b);
	cout << "後序遍歷的演算法如下:" << endl;
	PostOrder(b);
	cout << "層次遍歷的演算法如下:" << endl;
	LevelOrder(b);
	return 0;
}