樹的四種遍歷方式c++

樹常用的遍歷方式有四種,分別爲前序遍歷,中序遍歷,後序遍歷和層次遍歷,下面的代碼依次實現了它們的遞歸以及非遞歸方法。

// tree.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//

#include "pch.h"
#include <iostream>
#include<stack>
#include<queue>

using namespace std;

typedef struct Node
{
	char data;
	struct Node *lchild, *rchild;
}Node;

//通過先序的方式創建樹,#表示空節點
/*
                   A
               B      C
             D   E   F  #
           #  # # # #  # 
創建上面的樹應輸入應爲  ABD##E##CF###
前序遍歷:ABDECF
中序遍歷:DBEAFC
後序遍歷:DEBFCA
層次遍歷:ABCDEF
*/
void creatTree(Node* &root)
{
	char data;
	cin >> data;
	if (data == '#')
		root = NULL;
	else
	{
		root = new Node;
		root->data = data;
		creatTree(root->lchild);
		creatTree(root->rchild);
	}

}


//打印一個節點的數據
void visit(Node* node)
{
	if(node!=NULL)
		cout << node->data;
}

//遞歸-前序遍歷,先訪問跟節點,然後訪問左節點,最後訪問右節點,每一個節點都要準守這樣的規則
void preTraversal(Node* root)
{
	//訪問跟節點
	if (root != NULL)
	{
		visit(root);
		preTraversal(root->lchild);
		preTraversal(root->rchild);
	}

}

//遞歸-中序遍歷,先訪問跟左節點,然後訪問中節點,最後訪問右節點,每一個節點都要準守這樣的規則
void midTraversal(Node* root)
{
	if (root != NULL)
	{
		midTraversal(root->lchild);
		visit(root);
		midTraversal(root->rchild);
	}
}

//遞歸-後序遍歷,先訪問左節點,然後訪問右節點,最後訪問根節點,每一個節點都要準守這樣的規則
void postTraversal(Node* root)
{
	if (root != NULL)
	{
		postTraversal(root->lchild);
		postTraversal(root->rchild);
		visit(root);
	}
}

//非遞歸-前序遍歷
/*
思想:用棧來實現。首先訪問根節點,然後將根節點入棧,接着訪問當前節點的左節點,然後入棧,當左節點訪問完後,
出棧,並依次訪問右節點
*/
void un_preTraversal(Node* root)
{
	stack<Node*> stack;
	//當前節點
	Node* p = root;
	while (p != NULL || stack.size() != 0)
	{
		if (p != NULL)
		{
			visit(p);//訪問p之前一定要保證p不爲空
			stack.push(p);
			p = p->lchild;
		}
		else
		{
			p = stack.top();
			stack.pop();
			p = p->rchild;
		}

	}

}

//非遞歸-中序遍歷
/*
思想:用棧來實現。從根節點開始依次遍歷當前節點的左節點,並依次入棧,當左節點遍歷完成後,獲取
棧頂元素並出棧,然後訪問該節點,並依次遍歷其右節點
*/
void un_midTraversal(Node* root)
{
	stack<Node*> stack;
	Node* p = root;
	while (p != NULL || stack.size() != 0)
	{
		if (p != NULL)
		{
			stack.push(p);
			p = p->lchild;
		}
		else
		{
			p = stack.top();
			stack.pop();
			visit(p);
			p = p->rchild;
		}
	}
}

//非遞歸-後序遍歷
/*
思想:用棧來實現。先根節點開始依次遍歷左節點,已經遍歷過了的標記爲'l',然後依次遍歷右節點,遍歷過的標記爲'r',
只有當標記爲'r'時才能訪問該節點。
*/
//定義一個有標記的結構體
typedef struct TNode
{
	Node* node;//樹的節點的指針
	char tag;//標記
}TNode;


void un_postTraversal(Node* root)
{
	//當前節點
	Node *p = root;
	TNode *n;
	stack<TNode*> stack;
	while (p != NULL || stack.empty() == false)
	{
		//遍歷左節點並標記
		while (p != NULL)
		{
			n = new TNode;
			n->node = p;
			n->tag = 'l';
			stack.push(n);
			p = p->lchild;
		}

		//出棧
		n = stack.top();
		stack.pop();
		
		//遍歷當前節點的右子樹
		if (n->tag == 'l')
		{
			n->tag = 'r';
			//再次入棧
			stack.push(n);
			//此時p==NULL,一定要給p當前的節點
			p = n->node;
			p = p->rchild;
		}
		//左右子樹遍歷完成後訪問該節點
		else
		{
			visit(n->node);
			//並把p置空防止
			p = NULL;
		}
	}
}

//樹的層次遍歷
//思想:使用隊列queue。先將根節點入隊列,循環判斷當前隊列不爲空時,將頭元素出隊列並訪問頭元素,然後在將它的左節點和右節點入隊列
void levelTraversal(Node* root)
{
	queue<Node*> q;
	Node* p = root;
	q.push(p);
	while (q.empty() == false)
	{
		p = q.front();
		q.pop();
		visit(p);
		if (p->lchild != NULL)
			q.push(p->lchild);
		if (p->rchild != NULL)
			q.push(p->rchild);
	}
}

int main()
{
	//創建上面的樹應輸入應爲  ABD##E##CF###

	Node* root;
	creatTree(root);
	cout << "遞歸-前序遍歷:";
	preTraversal(root);
	cout << endl;

	cout << "遞歸-中序遍歷:";
	midTraversal(root);
	cout << endl;

	cout << "遞歸-後序遍歷:";
	postTraversal(root);
	cout << endl;

	cout << "非遞歸-前序遍歷:";
	un_preTraversal(root);
	cout << endl;

	cout << "非遞歸-中序遍歷:";
	un_midTraversal(root);
	cout << endl;

	cout << "非遞歸-後序遍歷:";
	un_postTraversal(root);
	cout << endl;

	cout << "層次遍歷:";
	levelTraversal(root);
	cout << endl;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章