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