二叉树
一个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; }