數據結構學習:樹的遍歷 前序 中序 後序 層序

樹的遍歷

樹的遍歷(也稱爲樹的搜索),樹的遍歷指的是按照某種規則,不重複地訪問某種樹的所有節點的過程。樹的遍歷不同於鏈表,隊列,棧這些線性數據結構,樹結構有多種不同的遍歷方式,可以分爲:

  • 深度優先遍歷 :前序遍歷/中序遍歷/後序遍歷
  • 廣度優先遍歷
    二者的區別在於
    深度優先搜索先訪問子節點,再訪問父節點,最後是第二個子節點;
    廣度優先搜索先訪問第一個子節點,再訪問第二個子節點,最後訪問父節點;

深度優先遍歷

下面,對下圖所示的二叉樹進行深度優先遍歷,同樣,結果不唯一,將按照前序/中序/後序分別加以區分;
在這裏插入圖片描述

前序遍歷(Pre Order Traversal)

前序遍歷指的是先訪問根,然後再訪問子樹的遍歷方式;

F, B, A, D, C, E, G, I, H.

中序遍歷(In Order Traversal)

  • 先訪問左子樹,然後訪問根,再訪問右子樹;

或者

  • 先訪問右子樹,然後訪問根,再訪問左子樹;

不過,一般按照第一種的方式進行中序遍歷;

A, B, C, D, E, F, G, H, I.

後序遍歷(Post Order Traversal)

先訪問子樹,再訪問根的遍歷方式;

A, C, E, D, B, H, I, G, F.

廣度有限遍歷

層序遍歷(Level Order Traversal)

下圖的遍歷結果 F, B, G, A, D, I, C, E, H.
在這裏插入圖片描述

C++四種遍歷實現

根據下圖所示的二叉樹,分別進行四種遍歷的C++程序的實現,可以預先根據上面遍歷的規則,計算四種遍歷的結果,對比一下程序;
在這裏插入圖片描述

#include <iostream>
#include <vector>
#include <queue>
#define SIZE 50
using namespace std;

class TreeNode {
public:
	TreeNode(int x) : vali(x),valc(0),lchild(nullptr), rchild(nullptr) {}
	TreeNode(char x) : vali(0), valc(x), lchild(nullptr), rchild(nullptr) {}
	TreeNode(const TreeNode& treenode) {
		vali = treenode.vali;
		valc = treenode.valc;
	}
	char valc;
	int vali;
	TreeNode *lchild;
	TreeNode *rchild;

	static void post_order_traversal(TreeNode *root) {
		if (root->lchild != NULL)
			post_order_traversal(root->lchild);
		if (root->rchild != NULL)
			post_order_traversal(root->rchild);
		// Do Something with root
		cout << root->valc << " ";
	}
	static void in_order_traversal(TreeNode *root) {
		if (root->lchild != NULL)
			in_order_traversal(root->lchild);
		// Do Something with root
		cout << root->valc << " ";
		if (root->rchild != NULL)
			in_order_traversal(root->rchild);
	}

	static void pre_order_traversal(TreeNode *root) {
		// Do Something with root
		cout << root->valc << " ";
		if (root->lchild != NULL)
			pre_order_traversal(root->lchild);
		if (root->rchild != NULL)
			pre_order_traversal(root->rchild);
	}
	static void layer_traver(TreeNode *root) {
		int head = 0, tail = 0;
		TreeNode *p[SIZE] = { nullptr };
		TreeNode *tmp;
		if (root != nullptr) {
			p[head] = root;
			tail++;
			// Do Something with p[head]			
		} else {
			return;
		}
		//環形隊列作爲緩衝器
		while (head % SIZE != tail % SIZE) {			
			tmp = p[head % SIZE];
			// Do Something with p[head]			
			cout << tmp->valc << " ";
			if (tmp->lchild != NULL) { // left
				p[tail++ % SIZE] = tmp->lchild;				
			}
			if (tmp->rchild != NULL) { // right
				p[tail++ % SIZE] = tmp->rchild;				
			}
			head++;
		}
		return;
	}	
	
	static void layer_traver_stl(TreeNode *root) {
		queue<TreeNode*> node_list;
		TreeNode *tmp;
		if (root != nullptr) {
			node_list.push(root);
			// Do Something with p[head]			
		}
		else {
			return;
		}
		while (node_list.size()) {		
			tmp = node_list.front();
			node_list.pop();
			cout << tmp->valc << " ";
			if (tmp->lchild != NULL) { // left
				node_list.push(tmp->lchild);
			}
			if (tmp->rchild != NULL) { // right
				node_list.push(tmp->rchild);
			}
		}
		return;
	}
};

int main() {
	TreeNode root('A');

	TreeNode node1('B');
	TreeNode node2('C');
	TreeNode node3('D');
	TreeNode node4('E');
	TreeNode node5('F');
	TreeNode node6('G');
	TreeNode node7('H');
	TreeNode node8('I');
	TreeNode node9('J');
	TreeNode node10('K');
	
	root.lchild = &node1;
	node1.lchild = &node3;
	node1.rchild = &node4;
	node3.lchild = &node7;
	node3.rchild = &node8;
	node4.lchild = &node9;
	root.rchild = &node2;
	node2.lchild = &node5;
	node2.rchild = &node6;
	node6.lchild = &node10;

	cout << "\n前序遍歷:";
	TreeNode::pre_order_traversal(&root);
	cout << "\n中序遍歷:";
	TreeNode::in_order_traversal(&root);
	cout << "\n後序遍歷:";
	TreeNode::post_order_traversal(&root);
	cout << "\n層序遍歷01:";
	TreeNode::layer_traver(&root);
	cout << "\n層序遍歷02:";
	TreeNode::layer_traver_stl(&root);
	getchar();
	return 0;
}

程序最終運行結果如下:
在這裏插入圖片描述

二叉樹遍歷的其他例子

下面額外在網絡上收集了多個二叉樹,可以對照着練習一下,這樣就可以搞懂前序/中序/後序遍歷的方式,結合代碼,理解具體的實現;
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

參考

樹的遍歷

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