二叉树
一个100行的代码调试都可能会让程序员遇到很多挫折,所以,面对挫折,我们永远不能低头。
这段时间在代码随想录里学习了二叉树相关知识,并整理成c++代码(采用类的方式定义二叉树)
想掌握二叉树概念,可参考青岛大学王卓老师的课程、51CTO学院的鲍老师课程、代码随想录以及其他博客,建议详细阅读代码随想录,五星推荐
本次学习的内容包含如下功能,算是对二叉树学习的一个功能总结,对自己学习过程的一个交代
阅读前必知必会:
本程序命名方式定义如下:
1、类名:以大写字母开头,每个单词首字母大写,无下划线
2、函数名:以小写字母开头,每个单词首字母大写,无下划线
3、变量名:
普通变量:变量名一律小写,单词间以下划线相连
类的成员变量:以m_开头,变量名一律小写,单词间以下划线相连
全局变量:没有特殊要求,尽量少用,可以加上前缀g_以与局部变量区分
二叉树部分代码未来需要重构,将部分遍历方式整合在一个函数里,通过形参指定执行某个遍历方式,减少代码的重复性
功能:
* 递归中序遍历
* 递归后序遍历
* 迭代前序遍历
* 迭代中序遍历
* 迭代后续遍历
* 层序遍历
* 递归反转二叉树
* 层序遍历反转二叉树
* 深度遍历反转二叉树
* 判断是否对称二叉树
未来计划:
* 追加测试用例
* 继续追加二叉树的功能函数
* 将代码封装成静态库和动态库
*
代码如下:
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<string>
#include<algorithm>
using namespace std;
enum SelectTravesal
{
PreRecur,
InRecur,
PostRecur,
PreIter,
InIter,
PostIter,
levelIter
};
/**
* @brief 定义树的节点
* @param m_val vector
* @param m_left 该节点的左指针域,用来指向其左孩子节点
* @param m_right 该节点的右指针域,用来指向其右孩子节点
* @note 为编写代码方便,成员变量的访问权限都设置为public,严格来说应该设置为private
* 当声明为private时,需要声明相应的友元类或友元方法,并提供相应的get set方法, 读者可自行修改锻炼c++基本功
* @author weihf
*/
class TreeNode
{
public:
int m_val;
TreeNode* m_left;
TreeNode* m_right;
public:
TreeNode(int x) : m_val(x), m_left(NULL), m_right(NULL)
{}
};
/**
* @brief 定义一颗二叉树树,其构造函数用来初始化一颗二叉树(使用数组来构造二棵树)
* @param m_root 二叉树的根节点
* @note 为编写代码方便,成员变量的访问权限都设置为public,严格来说应该设置为private
* 当声明为private时,需要声明相应的友元类或友元方法,并提供相应的get set方法, 读者可自行修改锻炼c++基本功
* @method
* recurPreTraversal 递归前序遍历
* 递归中序遍历
* 递归后序遍历
* 迭代前序遍历
* 迭代中序遍历
* 迭代后续遍历
* 层序遍历
* 递归反转二叉树
* 层序遍历反转二叉树
* 深度遍历反转二叉树
* 判断是否对称二叉树
* @author weihf
*/
class Tree
{
public:
TreeNode* m_root;
public:
Tree(const vector<int> &vec);
// ~Tree();
public:
void recurPreTraversal(TreeNode* node, vector<int> &result); // 递归前序遍历
void recurInTraversal(TreeNode* node, vector<int> &result); // 递归中序遍历
void recurPostTraversal(TreeNode* node, vector<int> &result); // 递归后序遍历
void preorderTraversal(TreeNode* node, vector<int> &result); // 迭代前序遍历
void inorderTraversal(TreeNode* node, vector<int> &result); // 迭代中序遍历
void postorderTraversal(TreeNode* node, vector<int> &result); // 迭代后续遍历
void uniTravesal(TreeNode* node, vector<int> &result); // 统一迭代遍历 包含三种写法:中左右 左中右 左右中
void levelTravesal(TreeNode* node, vector<int> &result); // 迭代层序遍历
public:
void recurReverseTree(TreeNode* node); // 递归反转二叉树,包含三种写法:中左右 左中右 左右中。这里采用的是左右中,也可以采用中左右,但不能采用左中右遍历,否则会导致原本的左孩子节点反转两次(可以改写成左中左)
void levelReverseTree(TreeNode* node); // 层序遍历反转二叉树
void depthReverseTree(TreeNode* node); // 深度遍历反转二叉树 采用的方法是普通前序遍历,也可以采用统一迭代遍历:中左右 左中右 左右中(后续再补充 todo)
public:
bool isSymmetricalTree(TreeNode* node); // 递归判断是否对称二叉树
bool isSymmetricalTreeQueue(TreeNode* node); // 使用队列判断是否是对称二叉树
bool isSymmetricalTreeStack(TreeNode* node); // 使用栈判断是否是对称二叉树
bool isSameTree(TreeNode* p, TreeNode* q); // 判断两个树是不是相同
bool isSubtree(TreeNode* root, TreeNode* subRoot); // 判断subroot是不是子树
public:
int getTreeDepth(); // 迭代求本二叉树的深度
int recurGetTreeDepth(); // 递归求本二叉树的深度 二叉树深度:到根节点的最大距离 中左右
int recurGetTreeHeight(); // 递归求本二叉树的高度 二叉树高度:到最远叶子节点的最大距离 左右中
};
/**
* @brief Construct a new Tree:: Tree object
* @param vec 用来构造二叉树的数组
* @note 如果父节点的数组下标是i,那么它的左孩子下标就是i * 2 + 1,右孩子下标就是 i * 2 + 2。
*/
Tree::Tree(const vector<int> &vec)
{
vector<TreeNode*> vecTree (vec.size(), NULL);
// 把输入数值数组,先转化为二叉树节点数组
for (int i = 0; i < vec.size(); i++) {
TreeNode* node = NULL;
if (vec[i] != -1) node = new TreeNode(vec[i]); // 用 -1 表示null
vecTree[i] = node;
if (i == 0) m_root = node;
}
// 遍历一遍,根据规则左右孩子赋值就可以了
// 注意这里 结束规则是 i * 2 + 2 < vec.size(),避免空指针
for (int i = 0; i * 2 + 1 < vec.size(); i++) {
if (vecTree[i] != NULL) {
// 线性存储转连式存储关键逻辑
vecTree[i]->m_left = vecTree[i * 2 + 1];
if(i * 2 + 2 < vec.size())
vecTree[i]->m_right = vecTree[i * 2 + 2];
}
}
}
void Tree::recurPreTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
result.push_back(node->m_val);
recurPreTraversal(node->m_left, result);
recurPreTraversal(node->m_right, result);
}
void Tree::recurInTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
recurInTraversal(node->m_left, result);
result.push_back(node->m_val);
recurInTraversal(node->m_right, result);
}
void Tree::recurPostTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
recurPostTraversal(node->m_left, result);
recurPostTraversal(node->m_right, result);
result.push_back(node->m_val);
}
void Tree::preorderTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
stack<TreeNode*> st;
st.push(node);
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
result.push_back(cur->m_val);
if(cur->m_right)
{
st.push(cur->m_right);
}
if(cur->m_left)
{
st.push(cur->m_left);
}
}
}
void Tree::inorderTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
stack<TreeNode*> st;
TreeNode* cur = node;
while(cur != NULL || !st.empty())
{
if(cur != NULL)
{
st.push(cur);
cur = cur->m_left;
}
else
{
cur = st.top();
result.push_back(cur->m_val);
st.pop();
cur = cur->m_right;
}
}
}
void Tree::postorderTraversal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
stack<TreeNode*> st;
st.push(node);
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
result.push_back(cur->m_val);
if(cur->m_left)
st.push(cur->m_left);
if(cur->m_right)
st.push(cur->m_right);
}
reverse(result.begin(), result.end());
}
void Tree::uniTravesal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
stack<TreeNode*> st;
st.push(node);
// 前序遍历
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if(cur != NULL)
{
if(cur->m_right)
st.push(cur->m_right); // 右
if(cur->m_left)
st.push(cur->m_left); // 左
st.push(cur); // 中
st.push(NULL);
}
else
{
result.push_back(st.top()->m_val);
st.pop();
}
}
/*
// 中序遍历
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if(cur != NULL)
{
if(cur->m_right)
st.push(cur->m_right); // 右
st.push(cur); // 中
st.push(NULL);
if(cur->m_left)
st.push(cur->m_left); // 左
}
else
{
result.push_back(st.top()->m_val);
st.pop();
}
}
*/
/*
// 后序遍历
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
if(cur != NULL)
{
st.push(cur); // 中
st.push(NULL);
if(cur->m_right)
st.push(cur->m_right); // 右
if(cur->m_left)
st.push(cur->m_left); // 左
}
else
{
result.push_back(st.top()->m_val);
st.pop();
}
}
*/
}
void Tree::levelTravesal(TreeNode* node, vector<int> &result)
{
if(node == NULL)
return;
queue<TreeNode*> que;
que.push(node);
while(!que.empty())
{
TreeNode* cur = que.front();
que.pop();
result.push_back(cur->m_val);
if(cur->m_left)
que.push(cur->m_left);
if(cur->m_right)
que.push(cur->m_right);
}
}
void Tree::recurReverseTree(TreeNode* node)
{
if(node == NULL)
return;
recurReverseTree(node->m_left); // 左
recurReverseTree(node->m_right); // 右
swap(node->m_left, node->m_right); // 中
/*
swap(node->m_left, node->m_right); // 中
recurReverseTree(node->m_left); // 左
recurReverseTree(node->m_right); // 右
*/
/*
recurReverseTree(node->m_left); // 左
swap(node->m_left, node->m_right); // 中
recurReverseTree(node->m_left); // 右,其实是左,因为先递归当前节点左子树导致左子树节点全部反转,再swap当前节点的左右子树,
// 导致当前节点已经经过反转的左子树反转成右子树了,当前节点还没反转的右子树变成当前节点的左子树了
// 若此时还反转当前节点的右子树,相当于把原来的左子树又递归反转了一遍,而原来的右子树反而得不到反转
*/
}
void Tree::levelReverseTree(TreeNode* node)
{
if(node == NULL)
return;
queue<TreeNode*> que;
que.push(node);
while(!que.empty())
{
TreeNode* cur = que.front();
que.pop();
swap(cur->m_left, cur->m_right);
if(cur->m_left)
que.push(cur->m_left);
if(cur->m_right)
que.push(cur->m_right);
}
}
void Tree::depthReverseTree(TreeNode* node)
{
if(node == NULL)
return;
stack<TreeNode*> st;
st.push(node);
while(!st.empty())
{
TreeNode* cur = st.top();
st.pop();
swap(cur->m_left, cur->m_right);
if(cur->m_right)
st.push(cur->m_right);
if(cur->m_left)
st.push(cur->m_left);
}
}
bool recurIsSymmetricalTree(TreeNode* left, TreeNode* right)
{
if(left == NULL && right == NULL)
return true;
if(left == NULL && right != NULL)
return false;
if(left != NULL && right == NULL)
return true;
if(left->m_val != right->m_val)
return false;
bool outside = recurIsSymmetricalTree(left->m_left, right->m_right);
bool inside = recurIsSymmetricalTree(left->m_right, right->m_left);
return outside && inside;
}
//左节点的左孩子 = 右节点的右孩子
//左节点的右孩子 = 右节点的左孩子
bool Tree::isSymmetricalTree(TreeNode* node)
{
if(node == NULL)
{
return true;
}
return recurIsSymmetricalTree(node->m_left, node->m_right);
}
bool Tree::isSymmetricalTreeQueue(TreeNode* node)
{
if(node == NULL)
{
return true;
}
queue<TreeNode*> que;
que.push(node->m_left);
que.push(node->m_right);
while(!que.empty())
{
TreeNode* left = que.front();
que.pop();
TreeNode* right = que.front();
que.pop();
if(left == NULL && right == NULL)
{
continue;
}
else if(left == NULL && right != NULL)
{
return false;
}
else if(left != NULL && right == NULL)
{
return false;
}
else if(left->m_val != right->m_val)
{
return false;
}
que.push(left->m_left);
que.push(right->m_right);
que.push(left->m_right);
que.push(right->m_left);
}
return true;
}
bool Tree::isSymmetricalTreeStack(TreeNode* node)
{
if(node == NULL)
{
return true;
}
stack<TreeNode*> st;
st.push(node->m_right);
st.push(node->m_left);
while(!st.empty())
{
TreeNode* left = st.top();
st.pop();
TreeNode* right = st.top();
st.pop();
if(left == NULL && right == NULL)
{
continue;
}
else if(left == NULL && right != NULL)
{
return false;
}
else if(left != NULL && right == NULL)
{
return false;
}
else if(left->m_val != right->m_val)
{
return false;
}
st.push(right->m_right);
st.push(left->m_left);
st.push(right->m_left);
st.push(left->m_right);
}
return true;
}
bool Tree::isSameTree(TreeNode* p, TreeNode* q)
{
stack<TreeNode*> que;
que.push(p);
que.push(q);
while(!que.empty())
{
TreeNode* left = que.top();
que.pop();
TreeNode* right = que.top();
que.pop();
if(left == NULL && right == NULL)
continue;
if(left == NULL && right != NULL)
return false;
if(left != NULL && right == NULL)
return false;
if(left->m_val != right->m_val)
return false;
que.push(left->m_left);
que.push(right->m_left);
que.push(left->m_right);
que.push(right->m_right);
}
return true;
}
bool Tree::isSubtree(TreeNode* root, TreeNode* subRoot)
{
if(root == NULL)
{
if(isSameTree(root, subRoot) == true)
return true;
return false;
}
queue<TreeNode*> que;
que.push(root);
while(!que.empty())
{
TreeNode* node = que.front();
que.pop();
if(isSameTree(node, subRoot) == true)
return true;
if(node->m_left)
{
que.push(node->m_left);
}
if(node->m_right)
{
que.push(node->m_right);
}
}
return false;
}
int Tree::getTreeDepth()
{
if(m_root == NULL)
return 0;
queue<TreeNode*> que;
int result = 0;
que.push(m_root);
while(!que.empty())
{
int size = que.size();
for(int i=0; i<size; i++)
{
TreeNode* node = que.front();
que.pop();
if(node->m_left)
que.push(node->m_left);
if(node->m_right)
que.push(node->m_right);
}
result++;
}
return result;
}
void GetTreeDepthByRecur(TreeNode* node, int &result, int depth)
{
result = depth > result ? depth : result;
if(node->m_left == NULL && node->m_right == NULL)
return;
if(node->m_left)
{
GetTreeDepthByRecur(node->m_left, result, depth++);
}
if(node->m_right)
{
GetTreeDepthByRecur(node->m_right, result, depth++);
}
}
int Tree::recurGetTreeDepth()
{
int result = 0;
if(m_root == NULL)
return result;
GetTreeDepthByRecur(m_root, result, 1);
return result;
}
int GetTreeHeightByRecur(TreeNode* node)
{
if(node == NULL)
return 0;
int left = GetTreeHeightByRecur(node->m_left); // 左
int right = GetTreeHeightByRecur(node->m_right); // 右
int height = max(left, right) + 1; // 中
return height;
}
int Tree::recurGetTreeHeight()
{
return GetTreeHeightByRecur(m_root);
}
void printTravesalTree(vector<int> &vec, const string &s)
{
cout << s << endl;
for(auto v : vec)
{
cout << v << " ";
}
cout << endl;
vec.clear();
}
void isSymmetricalTreePrint(bool flag)
{
if(flag)
cout << "这是一颗对称二叉树"<<endl;
else
cout<< "这不是一颗对称树" <<endl;
}
void isSubTreePrint(bool flag)
{
if(flag)
cout << "这是父子树关系"<<endl;
else
cout<< "这不是父子树关系" <<endl;
}
int main()
{
// vector<int> vec = {30,36,21,36,35,26,15,-1, -1, -1, 33, -1, -1, -1, 8};
// vector<int> vec1 = {4, 2, 7, 1, 3, 6, 9};
vector<int> vec = {1, 2, 2, 3, 4, 4, 3, 5, 6, -1, -1, -1, -1, 6, 5};
vector<int> result;
Tree tree(vec);
Tree tree1(vec);
tree.recurPreTraversal(tree.m_root, result);
printTravesalTree(result, "递归前序遍历结果");
tree.recurInTraversal(tree.m_root, result);
printTravesalTree(result, "递归中序遍历结果");
tree.recurPostTraversal(tree.m_root, result);
printTravesalTree(result, "递归后序遍历结果");
tree.preorderTraversal(tree.m_root, result);
printTravesalTree(result, "迭代前序遍历结果");
tree.inorderTraversal(tree.m_root, result);
printTravesalTree(result, "迭代中序遍历结果");
tree.postorderTraversal(tree.m_root, result);
printTravesalTree(result, "迭代后序遍历结果");
tree.uniTravesal(tree.m_root, result);
printTravesalTree(result, "统一迭代遍历结果");
tree.levelTravesal(tree.m_root, result);
printTravesalTree(result, "层序遍历结果");
tree.recurReverseTree(tree.m_root);
tree.levelTravesal(tree.m_root, result);
printTravesalTree(result, "递归反转二叉树结果");
tree.levelReverseTree(tree.m_root);
tree.levelTravesal(tree.m_root, result);
printTravesalTree(result, "层序遍历反转二叉树结果");
tree.depthReverseTree(tree.m_root);
tree.levelTravesal(tree.m_root, result);
printTravesalTree(result, "深度遍历反转二叉树结果");
isSymmetricalTreePrint(tree.isSymmetricalTree(tree.m_root));
isSymmetricalTreePrint(tree.isSymmetricalTreeQueue(tree.m_root));
isSymmetricalTreePrint(tree.isSymmetricalTreeStack(tree.m_root));
isSubTreePrint(tree.isSameTree(tree.m_root, tree1.m_root));
isSubTreePrint(tree.isSameTree(tree.m_root, tree1.m_root));
cout << tree.getTreeDepth() <<endl;
cout << tree.recurGetTreeDepth() <<endl;
cout << tree.recurGetTreeHeight() <<endl;
return 0;
}

浙公网安备 33010602011771号