二叉树全家福 -- 构建二叉树、递归与非递归(先序中序后序)遍历、层次遍历以及层次遍历逐层实现、各节点数加一、查找节点、插入节点、翻转二叉树等

BTree.h文件: 

#pragma once
#include<iostream>
#include<vector>
using namespace std;
//定义二叉树每个节点的结构体
struct TreeNode
{
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x) :val(x), left(NULL), right(NULL){}//初始化列表
};
class Tree {
private:
	TreeNode* root;//令根节点私有化,为了让它不轻易改变
public:
	TreeNode* buildTree(vector<int>& arr);//构建二叉搜索树
	TreeNode* preTree(TreeNode* root);//先序遍历-递归
	TreeNode* inTree(TreeNode* root);//中序遍历-递归
	TreeNode* postTree(TreeNode* root);//后序遍历-递归
	void preTree1(TreeNode* root);//先序遍历-非递归
	void inTree1(TreeNode* root);//中序遍历-非递归
	void postTree1(TreeNode* root);//后序遍历-非递归
	void layOrder(TreeNode* root);//层次遍历
	void layOrder1(TreeNode* root);//层次遍历-逐层展现
    TreeNode* add1Tree(TreeNode* root);//把二叉树中的每个节点的val+1
    bool findANode(TreeNode* root, int target);//查找一个数
    TreeNode* insertANode(TreeNode* root,int target);//插入一个数
	bool judgeTwoTree(TreeNode* root1, TreeNode* root2);//判断两个数是否相同
    TreeNode* reverseTree(TreeNode* root);//翻转二叉树
	TreeNode* getroot();//获得根节点
};

BTree.cpp文件:

#include"BTree.h"
#include<stack>
#include<queue>
using namespace std;
//构建二叉搜索树
TreeNode* Tree::buildTree(vector<int>& arr) {
	int n = arr.size();
	if (n == 0) {
		return NULL;
	}
	root = new TreeNode(arr[0]);
	for (int i = 1; i < n; i++) {
		TreeNode * node = root;
		TreeNode * newnode = new TreeNode(arr[i]);
		while (node != NULL) {
			//判断当前要放入的数在二叉树中的位置,比根节点大放在右子树中,否则放在左子树中
			if (arr[i] < node->val) {
				//为空则放入,否则接着向下遍历
				if (node->left == NULL) {
					node->left = newnode;
					break;
				}
				node = node->left;
			}
			if (arr[i] > node->val) {
				if (node->right == NULL){
					node->right = newnode;
					break;
				}
				node = node->right;
			}
		}
	}
	return root;
}
//递归-先序遍历
TreeNode* Tree::preTree(TreeNode* root) {
	if (root == NULL) {
		return NULL;
	}
	cout << root->val << "  ";//根
	preTree(root->left);//左
	preTree(root->right);//右
	return root;
}
//递归-中序遍历
TreeNode* Tree::inTree(TreeNode* root) {
	if (root == NULL) {
		return NULL;
	}
	inTree(root->left);//左
	cout << root->val << "  ";//根
	inTree(root->right);//右
	return root;
}
//递归-后序遍历 
TreeNode* Tree::postTree(TreeNode* root) {
	if (root == NULL) {
		return NULL;
	}
	postTree(root->left);//左
	postTree(root->right);//右
	cout << root->val << "  ";//根
	return root;
}
//非递归-先序遍历
①先遍历节点,把根节点及其左孩子,左孩子的左孩子全部放入栈中并输出,
②然后再判断栈是否为空,如果栈不为空,则依次抛出栈顶元素,令node=它的右孩子
说明:这样的目的是先将左子树中所有的根节点,包括最后的叶子节点,全部先输出,并存在栈中
③然后依次遍历栈中这些节点是否有右孩子,如果有则令它的右孩子进栈,再把右孩子看作一个子树,重复①② 
void Tree::preTree1(TreeNode* root) {
//判断根节点是否为空
	if (root == NULL)
		return;
	stack<TreeNode*> s;
//定义一个node为了不改变root的值
	TreeNode * node = root;
	while (node!=NULL||!s.empty()) {
//先遍历节点,把根节点及其左孩子,左孩子的左孩子全部放入栈中并输出,直到node为空结束
		while (node!=NULL)
		{
			s.push(node);
			cout << node->val << "  ";
			node = node->left;
		}
//判断栈是否为空,如果栈不为空,则依次抛出栈顶元素,令node=它的右孩子
		//然后右孩子再去执行while循环
		if (!s.empty())
		{
			node = s.top();
			s.pop();
			node = node->right;
		}
	}
}

//非递归-中序遍历
①先将根节点,及其左孩子,及其左孩子的左孩子全部放入栈中,直到node节点为空
②依次令node赋为栈顶元素并输出,然后将栈顶元素抛出,然后遍历node的右孩子
void Tree::inTree1(TreeNode* root) {
	if (root == NULL)
		return;
	stack<TreeNode*> s;
	TreeNode * node = root;
	while (node != NULL || !s.empty()) {
//将根节点,及其左孩子,及其左孩子的左孩子全部放入栈中,直到node节点为空
		while (node != NULL)
		{
			s.push(node);
			node = node->left;
		}
//依次令node赋为栈顶元素并输出,然后将栈顶元素抛出,然后遍历node的右孩子
		if (!s.empty())
		{
			node = s.top();
			s.pop();
			cout << node->val << "  ";
			node = node->right;
		}
	}
}

//非递归-后序遍历
①将根节点入栈,并创建一个pre代表节点的左或右孩子,先令pre=NULL
②如果某节点左/右孩子不为空,并且pre不是它的左/右孩子,如存在左、右孩子,先将右孩子入栈,然后再将左孩子入栈
③如果某节点左右孩子均为空,即叶子节点,则将其输出,并令pre=此节点
④如果某节点左/右孩子不为空,但是pre=它的左/右孩子,并且pre!=NULL,则将此节点输出,并令pre=此节点
void Tree::postTree1(TreeNode* root) {
	if (root == NULL)
		return;
	stack<TreeNode*> s;
	TreeNode* cur = root;
	TreeNode* pre = NULL;  //pre代表节点的左或右孩子
	s.push(root);  //根节点入栈
	while (!s.empty())
	{
		cur = s.top();
//如果某节点左右孩子均为空,即叶子节点,则将其输出,并令pre=此节点
//如果某节点左/右孩子不为空,但是pre=它的左/右孩子,并且pre!=NULL,则将此节点输	出,并令pre=此节点
		if ((cur->left == NULL&&cur->right == NULL) ||
			((pre == cur->left || pre == cur->right) && pre != NULL))
		{
			cout << cur->val << "  ";
			s.pop();
			pre = cur;
		}
//如果某节点左/右孩子不为空,并且pre不是它的左/右孩子,如存在左、右孩子,先将右孩子入栈,然后再将左孩子入栈
		else
		{
			if (cur->right != NULL)
				s.push(cur->right);
			if (cur->left != NULL)
				s.push(cur->left);
		}
	}
}
//层次遍历
void Tree::layOrder(TreeNode* root) {
	queue<TreeNode*> que;
	que.push(root);
	while (!que.empty())
	{
		TreeNode* cur = que.front();
		que.pop();
		cout << cur->val << "  ";
		if (cur->left) {
			que.push(cur->left);
		}
		if (cur->right) {
			que.push(cur->right);
		}
	}
}

//层次遍历-逐层展现
void Tree::layOrder1(TreeNode* root) {
	queue<TreeNode*> que;
	que.push(root);
	TreeNode* last = root;//所遍历当前行的最右节点
	TreeNode* nlast = NULL;//所遍历当前行的下一行的最右节点
	while (!que.empty())
	{
		TreeNode* cur = que.front();
		que.pop();
		cout << cur->val << "  ";
		if (cur->left) {
			que.push(cur->left);
			nlast = cur->left;
		}
		if (cur->right) {
			que.push(cur->right);
			nlast = cur->right;
		}
		if (cur == last) {
			cout << endl;
			last = nlast;
		}
	}
}
//把二叉树中每个节点的val+1
思路:用先序递归遍历二叉树,然后将之前先序遍历输出节点值的语句变成节点值加一的语句
TreeNode* Tree::add1Tree(TreeNode* root) {
	if (root == NULL) {
		return NULL;
	}
	root->val += 1;
	add1Tree(root->left);
	add1Tree(root->right);
	return root;
}
//查找一个数,是否在二叉搜索树中存在
思路:递归结束的条件有两个,一个是这个数不存在,返回false,一个是存在,返回true,
如果根结点的数大于目标数,就向左查找,如果根结点的数小于目标数,就向右查找
bool Tree::findANode(TreeNode* root,int target) {
	if (root == NULL) {
		return false;
	}
	if (root->val == target) {
		return true;
	}
	if (root->val > target) {
		bool is = findANode(root->left, target);
		return is;
	}
	if (root->val < target) {
		bool is = findANode(root->right, target);
		return is;
	}
	return NULL;
}
//插入一个数
思路:递归结束条件就是root为空,也就是目标数需要插入的位置,
同样,如果根结点的数大于目标数,就向左查找,如果根结点的数小于目标数,就向右查找
TreeNode* Tree::insertANode(TreeNode* root, int target) {
	if (root == NULL) {
		return new TreeNode(target);
	}
	if (root->val > target) {
		root->left = insertANode(root->left, target);
	}
	if (root->val < target) {
		root->right = insertANode(root->right, target);
	}
	return root;
}
//判断两个树是否相同
思路:选择先序遍历,因为先序遍历是从根节点开始进行比较的,如果根节点都不相同,就没有继续比较的意义了
bool Tree::judgeTwoTree(TreeNode* root1, TreeNode* root2) {
	if (root1 == NULL&&root2 == NULL) {
		return true;
	}
	if ((root1 == NULL&&root2 != NULL) || (root1 != NULL&&root2 == NULL)) {
		return false;
	}
	if (root1->val != root2->val) {
		return false;
	}
	bool flag = judgeTwoTree(root1->left, root2->left) && judgeTwoTree(root2->right, root2->right);
	return flag;
}
//翻转二叉树
思路:递归结束条件是当根节点为空,因为根节点为空,代表着都已经遍历完了,每次只翻转根节点的左右两个孩子,除了左右两个孩子节点翻转了,孩子结点的孩子节点还是保持不动的,等待下一次的翻转
TreeNode* Tree::reverseTree(TreeNode* root) {
	if (root == NULL) {
		return NULL;
	}
	TreeNode* temp = root->left;
	root->left = root->right;
	root->right = temp;
	reverseTree(root->left);
	reverseTree(root->right);
	return root;
}
//获得根节点
TreeNode* Tree::getroot() {
	return root;
}

main.cpp文件:

#include<unordered_map>
#include<vector>
#include<iostream>
#include<string.h>
#include"BTree.h"
using namespace std;

int main() {
	Tree t;
	vector<int> arr = { 5,3,4,7,2,6,8,1 };
	t.buildTree(arr);
	TreeNode* root=t.getroot();
	cout << "先序遍历-递归:" << endl;
	t.preTree(root);
	cout << endl;
	cout << "中序遍历-递归:" << endl;
	t.inTree(root);
	cout << endl;
	cout << "后序遍历-递归:" << endl;
	t.postTree(root);
	cout << endl;
	cout << "先序遍历-非递归:" << endl;
	t.preTree1(root);
	cout << endl;
	cout << "中序遍历-非递归:" << endl;
	t.inTree1(root);
	cout << endl;
	cout << "后序遍历-非递归:" << endl;
	t.postTree1(root);
	cout << endl;
	cout << "层次遍历:" << endl;
	t.layOrder(root);
	cout << endl;
	cout << "层次遍历-逐层展现:" << endl;
	t.layOrder1(root);
	return 0;
}

部分截图,仅供参考

此截图显示的效果是我自己按照上述代码重新编写的

能显示截图结果的项目源码:

链接:https://pan.baidu.com/s/1hbNUW64OVY9EIZjGDprQvw 
提取码:nz3e

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值