该文我会用来总结二叉树相关的知识

二叉树如下图:

二叉树的结构

struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

二叉树构造方法

为了测试二叉树的的各种算法,我不得不写一个二叉树的构造方法,我主要是用层次遍历的方式来构造二叉树的。层次遍历在后面会详细说到。

用字符串的方式来输入二叉树的序列,例如:

输入:1 2 3 4 5 6 7 null null null null null 8 null null

以上输入都是字符,最后两个null可省略。

TreeNode *createBinaryTree(vector<string> &arr){TreeNode *head = NULL;if (!arr.at(0).compare("null"))return head;//空树queue<TreeNode *>Q;vector<string>::iterator it = arr.begin();head = new TreeNode(stringToInteger(*it++));//stringToInteger将string转为intTreeNode *p = NULL;Q.push(head);//树根入队//队列不空,且没超过arr的大小(用于arr最后多余的null未列出来的情况,即上面说的可省略的情况)while (!Q.empty() && it != arr.end()){p = Q.front();//取出队首元素
        Q.pop();if (!(*it).compare("null")){//arr序列的下一个为空,则左子树为空p->left = NULL;}else{//否则生成左子树p->left = new TreeNode(stringToInteger(*it));Q.push(p->left);//左子树入队
        }++it;if (it == arr.end())break;//不忘判断arr是否越界if (!(*it).compare("null")){//arr序列的下一个为空,则右子树为空p->right = NULL;}else{//否则生成右子树p->right = new TreeNode(stringToInteger(*it));Q.push(p->right);//右子树入队
        }++it;}return head;
}

用数值的方式来输入二叉树的序列,例如:

输入:1 2 3 4 5 6 7 -1 -1 -1 -1 -1 8

默认树的所有值都是大于0的。

TreeNode *createBinaryTree(const vector<int> &arr){int index = 0;queue<TreeNode *>Q;TreeNode *head = new TreeNode(arr.at(index++));Q.push(head);TreeNode *p = NULL;while (index < arr.size() && !Q.empty()){p = Q.front();Q.pop();if (arr.at(index) >= 0){TreeNode *temp = new TreeNode(arr.at(index));p->left = temp;Q.push(temp);}++index;if (index >= arr.size())break;if (arr.at(index) >= 0){TreeNode *temp = new TreeNode(arr.at(index));p->right = temp;Q.push(temp);}++index;}return head;
}

二叉树遍历方法

前序遍历:1->2->4->5->3->6->8->7

中序遍历:4->2->5->1->8->6->3->7

后序遍历:4->5->2->8->6->7->3->1

层次遍历:1->2->3->4->5->6->7->8

前序递归实现:

vector<int> preorder(TreeNode* root){vector<int> retInt;if (root == NULL)return retInt;//空树retInt.push_back(root->val);//先访问值vector<int> left = preorder(root->left);//进入左子树retInt.insert(retInt.end(), left.begin(), left.end());//复制左子树的访问结果vector<int> right = preorder(root->right);//进入右子树
    retInt.insert(retInt.end(), right.begin(), right.end());return retInt;
}

前序费递归实现:

vector<int> preorder(TreeNode* root){vector<int>retInt;if (root == NULL)return retInt;//空树stack<TreeNode *>s;s.push(root);//树根入栈while (!s.empty()){TreeNode *p = s.top();retInt.push_back(p->val);//先访问值if (p->left != NULL){s.push(p->left);//遍历左子树,左子树入栈
        }else{//左子树为空s.pop();//当前节点出栈while (p->right == NULL && !s.empty()){//寻找非空右子树p = s.top();s.pop();}if (p->right != NULL)s.push(p->right);//右节点入栈
        }}return retInt;
}

中序递归实现:

vector<int> inorder(TreeNode* root){vector<int> retInt;if (root == NULL)return retInt;//空树retInt = inorder(root->left);//遍历左子树retInt.push_back(root->val);//访问当前节点值vector<int> temp = inorder(root->right);//遍历右子树retInt.insert(retInt.end(),temp.begin(),temp.end());//复制右子树的结果return retInt;
}

中序非递归实现:

vector<int> inorder(TreeNode* root){vector<int> retInt;if (root == NULL) return retInt;//空树TreeNode *p = NULL;stack<TreeNode *> s;s.push(root);//树根入栈while (!s.empty()){p = s.top();//获取栈顶元素if (p->left != NULL){s.push(p->left);//其左子树入栈
        }else{//左子树为空时
            s.pop();retInt.push_back(p->val);//访问其节点值while (p->right == NULL && !s.empty()){//寻找非空右子树p = s.top();//若右子树为空,获取新的栈顶元素retInt.push_back(p->val);//访问新元素的值
                s.pop();}if (p->right != NULL)s.push(p->right);//右子树入栈
        }}return retInt;
}

后序的递归实现:

vector<int> postorderTraversal2(TreeNode* root){vector<int> retInt;if (root == NULL)return retInt;//空树retInt = preorderTraversal2(root->left);//进入左子树vector<int> right = preorderTraversal2(root->right);//进入右子树
    retInt.insert(retInt.end(), right.begin(), right.end());retInt.push_back(root->val);//最后访问值return retInt;
}

后序的非递归实现:

下面的方法需要增加数组记录已访问的所有节点,空间时间开销都比较大

bool LeetCode::checkVisitedPost(vector<TreeNode*>& visited, TreeNode* p){for (vector<int>::size_type i = 0; i < visited.size(); i++){if (visited.at(i) == p)return true;}return false;
}

vector<int> LeetCode::postorderTraversal(TreeNode* root){vector<int> retInt;if (root == nullptr)return retInt;//空树stack<TreeNode *>s;vector<TreeNode *>visited;//是否已访问过
    s.push(root);visited.push_back(root);while (!s.empty()){TreeNode* p = s.top();if (p->left && !checkVisitedPost(visited,p->left)){//左节点存在,且未访问过s.push(p->left);visited.push_back(p->left);}else if (p->right && !checkVisitedPost(visited, p->right)){//右节点存在,且未访问过s.push(p->right);visited.push_back(p->right);}else{retInt.push_back(p->val);//访问该节点
            s.pop();}}return retInt;
}

下面的方法避开存储所有的已访问节点,而只存最后访问的右节点;时间空间开销都好很多;

vector<int> LeetCode::postorderTraversal(TreeNode* root){vector<int> retInt;if (root == nullptr)return retInt;//空树stack<TreeNode *>s;TreeNode* visited = nullptr;//记录前面已访问的树节点TreeNode* p = root;//记录当前节点while (p || !s.empty()){//!p保证根节点能入栈while (p){//左子树入栈
            s.push(p);p = p->left;}p = s.top();//获得最后的左节点if (!p->right || p->right == visited){retInt.push_back(p->val);//左右子树都已访问或为空,则访问当前节点visited = p;//记录已访问的右节点
            s.pop();p = nullptr;//置为空,防止重复遍历左子树
        }else p = p->right;}return retInt;
}

层次遍历的非递归实现:

使用队列保存每层的节点,另外为了知道每层的节点数量而增加了num数组。将每一层看做一个等级,每次要将遍历的节点的孩子节点加到对应的等级的数量中去。

vector<vector<int>> levelOrder(TreeNode* root){vector<vector<int>> ret;if (root == NULL)return ret;queue<TreeNode *>Q;Q.push(root);//表示当前的层次vector<int>::size_type level = 0;//当前层次的节点数量vector<int> num;num.push_back(1);while (!Q.empty()){TreeNode *p = Q.front();//判断当前等级对应的数组是否创建if (level < ret.size()){//已创建ret.at(level).push_back(p->val);}else{//未创建vector<int>nodei;nodei.push_back(p->val);ret.push_back(nodei);}Q.pop();--num.at(level);//数量减一if (p->left != NULL){//左子树入队Q.push(p->left);//判断当前等级对应的数量是否存在if (level < num.size() - 1){//已存在num.at(level + 1)++;}else{//不存在num.push_back(1);}}if (p->right != NULL){//右子树入队Q.push(p->right);if (level < num.size() - 1){num.at(level + 1)++;}else{num.push_back(1);}}if (num.at(level) <= 0){//当前层次等级的数量没有了,则进入下一层level++;}}return ret;
}

遍历的应用:

下面按照LeetCode中的题目来说明遍历的一些应用:

94 Binary Tree Inorder Traversal可用中序遍历来检查,二叉搜索树的中序遍历结果是递增的,这个按照上面的遍历算法就能简单解决。

100 Same Tree 判断两颗二叉树是否相同。遍历一遍,比较每个节点就可以了。

bool isSameTree(TreeNode* p, TreeNode* q){if (!p && !q)return true;//空树判断else if (!p || !q)return false;if (p->val != p->val)return false;//值比较return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

101 Symmetric Tree 判断一颗二叉树是否镜像对称。两个指针按照先序遍历,一个按照根、左儿子、右儿子,一个按照根、右儿子、左儿子的顺序遍历,然后比较每个节点就可以了。注意,当遍历到根节点时,就可以停止,不需要遍历完整颗树。

递归的做法:

bool isSymmetric(TreeNode* root){if (!root)return true;return isSymmetricRecur(root->left, root->right);
}bool isSymmetricRecur(TreeNode* left, TreeNode*right){if (!left && !right)return true;else if (!left || !right)return false;if (left->val != right->val)return false;return isSymmetricRecur(left->left, right->right) && isSymmetricRecur(left->right, right->left);
}

非递归的做法:

bool isSymmetric(TreeNode* root){if (!root)return true;TreeNode *p = root->left, *q = root->right;stack<pair<TreeNode *, TreeNode *>>S;while (!S.empty() || p || q){//注意:循环条件是!S.empty() || p || q,因为q、p可能为空if ((!p && q)|| (!q && p))return false;//仅其中一个为空if (p && q){if (p->val != q->val)return false;//值不等,放到里面不用判断p,q是否为空
            S.push({ p, q });p = p->left;q = q->right;}else{p = S.top().first;q = S.top().second;S.pop();if (p == q)break;//树根p = p->right;q = q->left;}}return true;
}

102 Binary Tree Level Order Traversal 输出二叉树的层次遍历的结果,要求每层的结果一个集合。上面层次遍历的算法就是这题的答案。

103 Binary Tree Zigzag Level Order Traversal 按照"之"字形来遍历每层,输出遍历的结果,要求每层的结果一个集合。

层次遍历的算法,注意奇数层(左->右)和偶数层(右->左)的输出方向不一样就可以了。

vector<vector<int>> LeetCode::zigzagLevelOrder(TreeNode* root){vector<vector<int>> ret;if (root == NULL)return ret;queue<TreeNode *>Q;Q.push(root);//表示当前的层次vector<int>::size_type level = 0;//当前层次的节点数量vector<int> num;num.push_back(1);stack<int>s;while (!Q.empty()){TreeNode *p = Q.front();//等级为奇数时,要先入栈if (level % 2){s.push(p->val);}else{//判断当前等级对应的数组是否创建if (level < ret.size()){//已创建ret.at(level).push_back(p->val);}else{//未创建vector<int>nodei;nodei.push_back(p->val);ret.push_back(nodei);}}Q.pop();--num.at(level);//数量减一if (p->left != NULL){//左子树入队Q.push(p->left);//判断当前等级对应的数量是否存在if (level < num.size() - 1){//已存在num.at(level + 1)++;}else{//不存在num.push_back(1);}}if (p->right != NULL){//右子树入队Q.push(p->right);if (level < num.size() - 1){num.at(level + 1)++;}else{num.push_back(1);}}if (num.at(level) <= 0){//当前层次等级的数量没有了,则进入下一层if (level % 2){if (level >= ret.size()){//若没有当前层的节点数组,则建立一个vector<int>nodei;nodei.push_back(s.top());ret.push_back(nodei);s.pop();}while (!s.empty()){//将栈中的元素加入到当前层次的数组中,实现反序
                    ret.at(level).push_back(s.top());s.pop();}}level++;}}return ret;
}

104 Maximum Depth of Binary Tree 求二叉树的深度

递归解法:

int maxDepthRecur(TreeNode* root){if (!root)return 0;return 1 + max(maxDepthRecur(root->left), maxDepthRecur(root->right));
}

非递归解法

int maxDepth(TreeNode* root){if (!root)return 0;int dep = 0, res = 0;TreeNode *p = root;stack<pair<TreeNode *, int>>S;while (!S.empty() || p){if (p){++dep;res = max(res, dep);S.push({ p, dep });p = p->left;}else{p = S.top().first;dep = S.top().second;S.pop();p = p->right;}}return res;
}

105 Construct Binary Tree from Preorder and Inorder Traversal 通过前序和中序序列构造二叉树

106 Construct Binary Tree from Inorder and Postorder Traversal 通过后序和中序序列构造二叉树

上面两题解法参考 http://www.cnblogs.com/yeqluofwupheng/p/7429781.html

107 Binary Tree Level Order Traversal II
110 Balanced Binary Tree
111 Minimum Depth of Binary Tree
112 Path Sum
113 Path Sum II
114 Flatten Binary Tree to Linked List
116 Populating Next Right Pointers in Each Node
117 Populating Next Right Pointers in Each Node II
124 Binary Tree Maximum Path Sum
129 Sum Root to Leaf Numbers
144 Binary Tree Preorder Traversal
145 Binary Tree Postorder Traversal
156 Binary Tree Upside Down
199 Binary Tree Right Side View
222 Count Complete Tree Nodes
226 Invert Binary Tree
236 Lowest Common Ancestor of a Binary Tree
250 Count Univalue Subtrees
257 Binary Tree Paths
297 Serialize and Deserialize Binary Tree
298 Binary Tree Longest Consecutive Sequence
337 House Robber III
366 Find Leaves of Binary Tree
404 Sum of Left Leaves
437 Path Sum III
508 Most Frequent Subtree Sum
513 Find Bottom Left Tree Value
515 Find Largest Value in Each Tree Row
536 Construct Binary Tree from String
543 Diameter of Binary Tree
545 Boundary of Binary Tree
549 Binary Tree Longest Consecutive Sequence II
563 Binary Tree Tilt
572 Subtree of Another Tree
582 Kill Process
606 Construct String from Binary Tree
617 Merge Two Binary Trees
623 Add One Row to Tree
637 Average of Levels in Binary Tree
652 Find Duplicate Subtrees
654 Maximum Binary Tree
655 Print Binary Tree
662 Maximum Width of Binary Tree
663 Equal Tree Partition

LeetCode的Sum Root to Leaf Numbers可用后序遍历来解决。

LeetCode的Binary Tree Right Side View可用后序遍历来解决。

转载于:https://www.cnblogs.com/yeqluofwupheng/p/6661399.html

二叉树总结(二)树的遍历相关推荐

  1. 2017-2018-1 20162316刘诚昊 实验二 树

    20162316刘诚昊 2017-2018-2 <Java程序设计>第二次实验 树 实验链接: 实验二 树-1-实现二叉树 实验二 树-2-中序先序序列构造二叉树 实验二 树-3-决策树 ...

  2. 树、二叉树、二叉搜索树_检查二叉树是否为BST(二叉搜索树)

    树.二叉树.二叉搜索树 Description: 描述: This article describes how to check whether a given tree is BST or not? ...

  3. 数据结构实验二 树和二叉树的实现

    广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼418A)     2019年5月13日 学院 计算机科学与教育软件学院 年级.专业.班 计算机科学与技术172班 姓名 学号 17061 ...

  4. 数据结构 | 第十一章:二叉树和其他树 | 【前序遍历】【中序遍历】【后序遍历】【层次遍历】 | 并查集

    第5-10章:线性结构,元素之间存在线性次序(线性表.数组与矩阵.栈.队列.跳表和散列表 第11-15章:层次结构(二叉树和树.优先队列.竞赛树.搜索树) 文章目录 11.1 树 11.2 二叉树 1 ...

  5. 树的基本概念以及java实现二叉树(二)

    前言 本文是我在学习了树后作的总结文章,接上篇文章,本节大致可以总结为: 二叉树的遍历与实现(递归和非递归) 获取二叉树的高度和度 创建一棵二叉树 其他应用(层序遍历,复制二叉树,判断二叉树是否相等) ...

  6. 什么是m叉树_树、二叉树、二叉搜索树的实现和特性

    ❝ 点赞再看,养成习惯,微信搜一搜[一角钱小助手]关注更多原创技术文章. 回复「文章」获取系列完整文章,本文 org_hejianhui/JavaStudy 已经收录,欢迎Star. ❞ 前言 本篇先 ...

  7. 树/二叉树/森林之间的相互转换 与遍历

    森林就是多棵树的集合,但是森林也可以只有一棵树,二叉树是一种特殊的树,固定的度为2,这是基本前情提要- 树常见的存储方式有三种: (1)双亲表示法 仅用定义一个结点对象,一个数组,代码定义如下: ty ...

  8. 数据结构-实验二  树和二叉树的实现

     广州大学学生实验报告 开课实验室:计算机科学与工程实验(电子楼417)     2018年05月16日 学院 计算机科学与教育软件学院 年级.专业.班 网络161 姓名 卟咚君 学号 1606100 ...

  9. 判断一棵树是否为排序二叉树(二叉搜索树)

    问题:判断一棵树是否为排序二叉树(二叉搜索树) 思路:二叉排序树的中序遍历为一递增的排序,若果不满足这一条件,则,不是二叉树 程序实现: #include <iostream> #incl ...

最新文章

  1. Oozie 任务调度
  2. table { border-collapse:collapse; }
  3. 【学术相关】如何将半页纸论文写到十页?
  4. 一个包含嵌套递归数据结构的对象的排序实现
  5. python字符串字面量有哪四种定义方式_Python学习笔记(四)字符串型
  6. 其他用户登陆到这台计算机,要登录到这台远程计算机,您必需拥有这台计算机上的‘终端服务器用户访问’权限解决方法...
  7. vue请求PHP接口报错provisional headers are shown
  8. yum被锁Another app is currently holding the yum lock; waiting for it to exit...
  9. 0基础怎样理解深度学习的工作原理?做个票价预测工具就懂了
  10. java调用数据库存储过程的接口是_JAVA调用数据库存储过程
  11. html5中怎么实现外边框中嵌入字_Web前端有什么优点?Web前端怎么入门?
  12. delphi 发送网络消息_分布式系统与消息的投递
  13. 凸优化有关的数值线性代数知识 1矩阵结构与算法复杂性
  14. 离线网页 HTML+CSS+DIV
  15. 流形学习t-SNE,LLE,Isomap
  16. 怎么简单使用Xftp6
  17. 百度收录-如何使用API提交
  18. 烟花绽放c语言程序设计摘要,描写烟花绽放的优美句子
  19. iOS开发——设置支持的iOS设备(512m内存以上设备)
  20. excel文档查询服务器,excel服务器数据库查询语句

热门文章

  1. caffe新手常遇到的三个问题
  2. SQL 一个表中可不可以没有主键
  3. 1.搭建JavaEE开发环境
  4. 滴水穿石-07Java开发中常见的错误
  5. (转)linux dumpe2fs命令
  6. Python面向对象基础一
  7. 一个很详细的web.xml讲解(转)
  8. gui编程实践(2)--qq聊天界面 JTextArea多行文本框组件
  9. 反射的妙用-类名方法名做参数进行方法调用实例demo
  10. Enterprise Solution 应用程序开发框架培训