二叉树操作

问题0:      二叉树的非递归遍历方法

问题1:  判断一颗二叉树是否为二叉查找树.

问题2:  判断两个二叉树是否相同

问题3:      判断一棵树是否为平衡树

问题4:      寻找二叉树的最大和最短简单路径长度

问题5:      二叉树上简单路径的长度问题

解答0:

  [0.1]前序.使用栈,访问节点后先压入右儿子,再压入左儿子即可.

 1 vector<int> preorderTraversal(TreeNode *root){
 2     stack<TreeNode*> st;
 3     st.push(root);
 4     vector<int> res;
 5
 6     TreeNode *curr;
 7     while(!st.empty()){
 8         curr = st.top();
 9         st.pop();
10
11         if(curr){
12             res.push_back(curr->val);
13             st.push(curr->right);
14             st.push(curr->left);
15         }
16     }
17
18     return res;
19 }

  [0.2]中序遍历.使用一个栈,将访问过的节点压入栈中.

 1 vector<int> inorderTraversal(TreeNode *root){
 2     stack<TreeNode*> st;
 3     vector<int> res;
 4
 5     TreeNode *curr=root,*top;
 6     while(!st.empty() || curr){
 7         if(curr){
 8             st.push(curr);
 9             curr = curr->left;
10         }else{
11             curr = st.top();
12             st.pop();
13             res.push_back(curr->val);
14             curr = curr->right;
15         }
16     }
17
18     return res;
19 }

  [0.3]

  方法1.后序遍历.访问左儿子前记录本节点,当再次取出节点时,存在其右儿子有没有被访问过的问题.通过记录前驱节点来辅助判断(前驱节点只在特定地点才更新).

 1     vector<int> postorderTraversal(TreeNode *root) {
 2         stack<TreeNode*> st;
 3         vector<int> res;
 4
 5         TreeNode *curr=root,*prev=root,*top;
 6         while(!st.empty() || curr){
 7             if(curr){
 8                 st.push(curr);
 9                 curr = curr->left;
10             }else{
11                 curr = st.top();
12
13                 if(prev==curr->right || curr->right==NULL){
14                     st.pop();
15
16                     res.push_back(curr->val);
17                     prev = curr;
18                     curr = NULL;
19                 }else{
20                     curr = curr->right;
21                 }
22             }
23         }
24         return res;
25     }

  方法2:使用两个栈,一个记录TreeNode*,另一个记录这个节点所对应的剩余访问次数.

       当剩余访问次数为2时,将剩余次数减少为1,并访问其左儿子;

     当剩余访问次数为1时,将剩余次数减少为0,并访问其右儿子;

       当剩余访问次数为0时,访问本节点.

  [0.4]层次遍历. 使用队列.

解答1:

  [1.1]首先中序遍历记录节点,然后判断整个记录是否递增.

 1     void inorder(TreeNode *root, vector<int>& v){
 2         if(root){
 3             inorder(root->left,v);
 4             v.push_back(root->val);
 5             inorder(root->right,v);
 6         }
 7     }
 8
 9     bool isAscend(vector<int>& v){
10         int len = v.size();
11         int i=0;
12         while(i<len-1){
13             if(v[i] >= v[i+1])
14                 return false;
15             i++;
16         }
17         return true;
18     }
19
20     bool isValidBST(TreeNode *root) {
21         vector<int> v;
22         inorder(root,v);
23
24         return isAscend(v);
25     }

   [1.2].通过观察可以发现, 方法[1.1]的比较过程就是将每个节点与其前驱节点的值作比较.那么这个比较操作能放在深搜的过程中完成吗?

 1     bool isValidBST(TreeNode *root) {
 2         TreeNode *curr = root,*prev = NULL;
 3         stack<TreeNode*> st;
 4
 5         while(!st.empty() || curr){
 6             if(curr){
 7                 st.push(curr);
 8                 curr = curr->left;
 9             }else{
10                 curr = st.top();
11                 st.pop();
12                 if(prev){
13                     if(prev->val >= curr->val)
14                         return false;
15                 }
16                 prev = curr;
17                 curr = curr->right;
18             }
19         }
20
21         return true;
22     }

  [1.3]使用子树中节点的左右边界来辅助进行判断.

 1     bool err;
 2
 3     pair<int, int> dfs(TreeNode *t){
 4         pair<int, int> l, r;
 5         int lbound = t->val, rbound = t->val; // 节点t的子树中节点的左右权值边界
 6         if (t->left){
 7             l = dfs(t->left);
 8             if (l.second >= t->val) err = true;
 9             lbound = l.first;//左边界为左子树的左边界
10         }
11         if (t->right){
12             r = dfs(t->right);
13             if (r.first <= t->val) err = true;
14             rbound = r.second;//右边界为右子树的右边界
15         }
16         return make_pair(lbound, rbound);
17     }
18
19     bool isValidBST(TreeNode *root) {
20         if (root == NULL) return true;
21         err = false;
22         dfs(root);
23         return !err;
24     }

解答2:

  [2.1]可通过同步的遍历来解决.

1 bool isSameTree(TreeNode *p,TreeNode *q){
2     if(p==NULL && q==NULL)
3         return true;
4     return (p && q && p->val==q->val && isSameTree(p->left,q->left) && isSameTree(p->right,q->right));
5 }

解答3:

  [3.1]递归方法

 1     int check(TreeNode *root,bool& flag){
 2         int l = 0,r = 0;
 3         if(flag && root && root->left)
 4             l = check(root->left,flag) + 1;
 5         if(flag && root && root->right)
 6             r = check(root->right,flag) + 1;
 7         if(flag)
 8             flag = (abs(l-r)<=1);
 9         return l>r?l:r;
10     }
11
12     bool isBalanced(TreeNode *root){
13         bool flag = true;
14         check(root,flag);
15         return flag;
16     }

  [3.2]迭代方法

解答4: 

 1 int maxDepth(TreeNode *root){
 2         if(root==NULL)
 3             return 0;
 4         return max(maxDepth(root->left),maxDepth(root->right)) + 1;
 5 }
 6
 7 int minDepth(TreeNode *root){
 8     if(root==NULL)
 9         return 0;
10     if(root->left==NULL && root->right==NULL)
11         return 1;
12     if(root->left==NULL)
13         return minDepth(root->right)+1;
14     else if(root->right==NULL)
15         return minDepth(root->left)+1;
16     else
17         return min(minDepth(root->left),minDepth(root->right))+1;
18 }

解答5:

  检测特定长度的存在性.

 1 bool hasPathSum(TreeNode *root,int sum){
 2     if(root==NULL)
 3         return false;
 4     if(root->left==NULL && root->right==NULL)
 5         return sum==root->val;
 6     if(root->left && hasPathSum(root->left,sum-root->val))
 7         return true;
 8     if(root->right && hasPathSum(root->right,sum-root->val))
 9         return true;
10     return false;
11 }    

  记录特定长度的路径

 1 void  dfs(TreeNode *root,int sum,vector<int> path,vector<vector<int> >& res){
 2     if(root==NULL){
 3         return ;
 4     }
 5     if(root->left==NULL&&root->right==NULL){
 6         if(sum==root->val){
 7             path.push_back(root->val);
 8             res.push_back(path);
 9         }
10         return;
11     }
12     path.push_back(root->val);
13     dfs(root->left,sum-root->val,path,res);
14     dfs(root->right,sum-root->val,path,res);
15     path.pop_back();
16 }
17
18 vector<vector<int> > pathSum(TreeNode *root, int sum) {
19     vector<vector<int> > res;
20     vector<int> path;
21     dfs(root,sum,path,res);
22     return res;
23 }

  

参考



  lycc的github代码

时间: 2024-10-22 11:29:42

二叉树操作的相关文章

二叉树操作复习

2017-08-29 11:46:37 writer:pprp 已经写了二叉树好几次了,但是还是有很多细节没有考虑完全 还有好多东西都没有考虑到,以后还是要写这个代码,把应该考虑的细节都考虑清楚 代码及讲解如下:(都测试过了,应该没问题,如果有问题请留言) /* @theme:树的建立和遍历 @writer:pprp @start:10:00 @end:11:47 @declare:我建立的这个树好像跟教科书上的树方向反了一下, 但是不影响理解,教科书上的是大的在右边,小的在左边,我的恰好反了过

POJ 1577 Falling Leaves 二叉树操作

Description Figure 1 Figure 1 shows a graphical representation of a binary tree of letters. People familiar with binary trees can skip over the definitions of a binary tree of letters, leaves of a binary tree, and a binary search tree of letters, and

二叉树操作总结

对于二叉树,有前序.中序.后序三种遍历方法,由于树的定义本身就是递归定义的,故采用递归方法实现三种遍历简洁易懂.若采用非递归访问,则需要使用栈来模拟递归的实现.三种遍历的非递归算法中,前序和后序较容易,而后序相对较难.   前序遍历 递归 非递归 树的遍历 中序遍历 递归 非递归 后序遍历 递归 非递归   层次遍历     计算树高        计算结点数       前序遍历[访问顺序:根结点-左孩子-右孩子] a> 前序遍历递归实现 1 void PreOrderRecursively(

【c语言】数据结构(二叉树操作)

  1 #include<stdio.h> 2 #include<stdlib.h> 3 typedef struct BITree{ 4 char data; 5 BITree *lchild; 6 BITree *rchild; 7 }BITree,*BiTree; 8 typedef struct Queue{ 9 BiTree data; 10 Queue *next; 11 }Queue; 12 BITree *pop(Queue *p) 13 { 14 Queue *q

c语言(二叉树的操作)

#include "stdio.h" #include "malloc.h" #include "stdlib.h" typedef struct BTNode { int data; struct BTNode *Lchild,*Rchild; }BTree; //初始化 BTree * Ini_BTNode() { BTree *bt ; int a; bt=(BTree *)malloc(sizeof(BTree)); printf(&qu

二叉树的基本运算

//二叉树的初始化操作.二叉树的初始化需要将指向二叉树的根结点指针置为空: void InitBitTree(BiTree *T)//二叉树的初始化操作 { *T=NULL; } //二叉树的销毁操作.如果二叉树存在,将二叉树存储空间释放: void DestroyBitTree(BiTree *T)//销毁二叉树操作 { if(*T)//如果是非空二叉树 { if((*T)->lchild) DestroyBitTree(&((*T)->lchild)); if((*T)->r

NOJ1019-计算二叉树的高度和结点数

输入 二叉树的先序遍历序列,用#代表空树或空子树. 输出 共五行 前三行依次输出先序.中序和后序遍历序列, 第四行输出二叉树的高度, 第五行依次输出二叉树总结点数目.叶子结点数目.度为1的结点数目. 样例输入 A B # D # # C E # # F # # 样例输出 PreOrder: A B D C E FInOrder: B D A E C FPostOrder: D B E F C A36 3 1 题目很简单,基本的二叉树操作.需要注意的是输入结点之间有空格,而且输出结点时也有空格,行

【转载】二叉树的基本概念和实现

原文:二叉树的基本概念和实现 继续是<数据结构算法与应用:C++语言描述>的笔记,这是第八章二叉树和其他树的内容,本节内容介绍树的定义以及二叉树的代码实现. 树 树t是一个非空的有限元素的集合,其中一个元素为根,余下的元素组成t的子树. 在画一棵树时,每个元素都代表一个节点.树根在上面,其子树画在下面.如下图所示,其中,Ann,Mary,John是Joe的 孩子(children) ,而Joe是他们的 父母(parent).有相同父母的孩子是 兄弟(sibling) .Ann,Mary,Joh

_DataStructure_C_Impl:二叉树的二叉链表存储结构

// _DataStructure_C_Impl: #include<stdio.h> #include<stdlib.h> #define MaxSize 100 typedef char DataType; typedef struct Node{ //二叉链表存储结构类型定义 DataType data; //数据域 struct Node *lchild; //指向左孩子结点 struct Node *rchild; //指向右孩子结点 }*BiTree,BitNode;