遞歸與非遞歸實現二叉樹的遍歷

主要講解二叉樹的遍歷問題:

     前序遍歷:訪問根結點的操作發生在遍歷其左右子樹之前。

     中序遍歷:訪問根結點的操作發生在遍歷其左右子樹中。

     後序遍歷:訪問根結點的操作發生在遍歷其左右子樹之後。

     層序遍歷:設二叉樹的根結點所在層數爲1,層序遍歷就是從所在二叉樹根結點出發,首先訪問第一層的樹根結點,然後從左到右訪問第2層上的節點,接着是第三層的節點,以此類推,自上而下,自左而右逐層訪問樹的節點的過程就是層序遍歷。

代碼實現:分別採用遞歸和非遞歸的思想實現前中後序遍歷。

     遞歸實現:

# pragma once
#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
	int val;
	struct Node* left;
	struct Node* right;
}	Node;

typedef struct Result{
	Node* node;  //創建好的書的根結點
	int used;    //創建樹的過程中用掉的val個數
}	Result;

//創建二叉樹
//BC##DE#G##F###
//""
Result CreateTree(char preorder[], int size)
{
	if (size <= 0){
		Result result;
		result.node = NULL;
		result.used = 0;
		return result;
	}

	if (preorder[0] == '#'){
		Result result;
		result.node = NULL;
		result.used = 1;
		return result;
	}

	//創建根結點
	Node* root = (Node*)malloc(sizeof(Node));
	root->val = preorder[0];

	//創建左子樹
	Result left = CreateTree(preorder + 1, size - 1);
	//創建右子樹
	Result right = CreateTree(preorder + 1 + left.used, size - 1 - left.used);

	root->left = left.node;
	root->right = right.node;

	Result result;
	result.node = root;
	//1是根用掉的,left.used是左子樹用掉的
	//right.nsed是右子樹用掉的
	result.used = 1 + left.used + right.used;

	return result;
}
//利用遞推的方式寫二叉樹
//前序遍歷二叉樹
void PreorderTraversal(Node* root)
{
	//終止條件
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->val);
	PreorderTraversal(root->left);
	PreorderTraversal(root->right);
}

//中序遍歷二叉樹
void MiddleOrderTraversal(Node* root)
{
	if (root == NULL)
	{
		return;
	}
	MiddleOrderTraversal(root->left);
	printf("%d ", root->val);
	MiddleOrderTraversal(root->right);
}

//後序遍歷二叉樹
void EpilogueTraversal(Node* root)
{
	if (root == NULL)
	{
		return;
	}
	EpilogueTraversal(root->left);
	EpilogueTraversal(root->right);
	printf("%d ", root->val);
}

//結點的個數遞推的思路
int GetNodeCount(Node* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return GetNodeCount(root->left) + GetNodeCount(root->right) + 1;
}

//遍歷的思路
int n = 0;
void GetNodeCount1(Node *root)
{
	if (root == NULL){
		return;
	}

	GetNodeCount1(root->left);
	n++;
	GetNodeCount1(root->right);
}

//葉子結點的個數遞推的思路
int GetLeafSize(Node* root) 
{
	if (root == NULL){
		return 0;
	}

	if (root->left == NULL && root->right == NULL){
		return 1;
	}

	return GetLeafSize(root->left) + GetLeafSize(root->right);
}

//遍歷的思路
int leaf_n = 0;
void GetLeafSize2(Node *root)
{
	if (root == NULL){
		return;
	}

	if (root->left == NULL && root->right == NULL){
		leaf_n++;
	}

	GetLeafSize2(root->left);
	GetLeafSize2(root->right);
}

//第k層結點的個數
int LevelK(Node* root, int k)
{
	if (root == NULL){
		return 0;
	}

	if (k == 1){
		return 1;
	}

	return LevelK(root->left, k - 1) + LevelK(root->right, k - 1);
}

//在樹中查找val的值,樹的val一定不重複
//查找次序,有序判斷根,根不是,去左子樹找,左子樹沒找到,繼續右子樹
//返回包含val的結點地址,沒有找到返回NULL
Node *Find(Node *root, char val)
{
	if (root == NULL){
		return;
	}

	//先判斷根
	if (root->val == val){
		return root;
	}

	//去左子樹找
	Node *r = Find(root->left, val);
	if (r != NULL){
		return r;
	}
	//右子樹找到了返回地址,沒有找到返回NULL
	return Find(root->right, val);
}

//求二叉樹的高度
int GetHeight(Node* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int left = GetHeight(root->left);
	int right = GetHeight(root->right);
	return (left > right ? left : right) + 1;
}

     非遞歸實現:

#include <queue>
#include <stack>
#include <stdio.h>
//層序遍歷

typedef struct Node
{
	int val;
	struct Node* left;
	struct Node* right;
}	Node;

typedef struct Result{
	Node* node;  //創建好的書的根結點
	int used;    //創建樹的過程中用掉的val個數
}	Result;


//層序遍歷二叉樹
void LevelOrderTraversal(Node *root)
{
	if (root == NULL){                                                                                                                                                                                                                                                                                                                                     
		return;                                                                                                                                                                                                                                                                                            
	}

	//來個隊列,隊列中存的數據類型是Node*
	//命名空間
	//模板
	std::queue<Node *> q;

	q.push(root);

	while (!q.empty()){
		Node *node = q.front();   //去隊首結點
		q.pop();       //彈出隊首結點
		printf("%c ", node->val);

		if (node->left != NULL){
			q.push(node->left);
		}

		if (node->right != NULL){
			q.push(node->right);
		}
	}
}

//判斷一棵樹是否是完全二叉樹
bool isCompleteTree(Node *root)
{
	if (root == NULL){
		return true;
	}

	//來個隊列,隊列中存的數據類型是Node*
	//命名空間
	//模板
	std::queue<Node *> q;

	q.push(root);

	while (1){
		Node *node = q.front();  //取隊首結點
		q.pop();
		if (node == NULL){
			//在層序遍歷的過程中遇到空結點
			break;
		}
		q.push(node->left);
		q.push(node->right);
	}

	//檢查剩下結點中有沒有非結點
	while (!q.empty()){
		Node *node = q.front();
		q.pop();
		if (node != NULL){
			return false;
		}
	}

	return true;
}

//前序遍歷非遞歸
void PreorderTraversalNoR(Node *root)
{
	std::stack<Node *> s;   //棧
	Node *cur = root;
	Node *top = NULL;

	while (cur != NULL || !s.empty()){
		//一路向左的過程
		while (cur != NULL){
			printf("%c ", cur->val);
			s.push(cur);
			cur = cur->left;
		}

		//一定是向左遇到NULL
		//利用棧處理剩餘的右子樹
		top = s.top();
		s.pop();
		cur = top->right;
	}
}

//中序遍歷非遞歸
void InorderTraversalNoR(Node *root)
{
	std::stack<Node *> s;
	Node *cur = root;
	Node *top = NULL;

	//一路向左的過程
	while (cur != NULL || !s.empty()){
		//第一次遇到的結點的位置
		s.push(cur);
		cur = cur->left;
	}

	//一定是向左遇到NULL
	//利用棧處理剩餘的右子樹
	top = s.top;
	s.pop();
	//第二次遇到的地方
	printf("%c ", top->val);

	cur = top->right;
}

//後序遍歷非遞歸
void PostorderTraversalNoR(Node *root) 
{
	std::stack<Node *> s;
	Node *cur = root;
	Node *top = NULL;
	Node *last = NULL;

	while (cur != NULL || !s.empty()){
		//一路向左的過程
		while (cur != NULL){
			//第一次遇到的結點的位置
			s.push(cur);
			cur = cur->left;
		}

		//一定是向右遇到NULL
		//利用棧處理剩餘的右子樹
		top = s.top();
		if (top->right == NULL){
			printf("%c ", top->val);
			s.pop();
			last = top;
		}
		else if (top->right == last){
			printf("%c ", top->val);
			s.pop();
			last = top;
		}
		else{
			cur = cur->right;
		}
	}
}

 

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