1、二叉树采用链式存储 求先序遍历序列中第k个元素
1 //求先序遍历序列中第k个节点的值 2 int i = 1;//全局变量 记录现在是第几个数 3 int PreOrder_k(TreeNode* root, int k) 4 { 5 if (!root) return 0;//当前节点为空 返回二叉树值不可能存在的一个值 作为标记 6 if (i == k)//如果当前是第k个 则返回第k个的值 7 return root->val; 8 else//当前节点不是第k个 9 { 10 i++;//下一个节点 11 int val_left = PreOrder_k(root->left,k);//往左子树中寻找 12 if (val_left != 0) return val_left;//若在左子树中找到了 则返回 13 else return PreOrder_k(root->right, k);//否则返回右子树找到的值 14 } 15 }
2、对于树中每个元素值为x的结点 删除以他为根的子树 并释放相应的空间
1 //删除树中每个值为x的节点的子树 2 //层次遍历 删除节点值为x的所有子树 再接着层次遍历 3 void Delete_x_child(TreeNode* root,int x) 4 { 5 queue<TreeNode*> que;//队列 6 TreeNode* p; 7 que.push(root);//先将根节点放入队列 8 while (!que.empty())//队列不空 9 { 10 p = que.front();//取出队头结点 11 que.pop();//将队头结点从队列中移除 12 if (p->left)//若p存在左子树 13 { 14 if (p->left->val == x)//若左子树的值为x 15 { 16 Delete_child(p->left);//递归删除左子树及其孩子 17 p->left = NULL; 18 } 19 else 20 que.push(p->left); 21 } 22 23 if (p->right)//若p存在右子树 24 if (p->right->val == x) 25 { 26 Delete_child(p->right); 27 p->right = NULL; 28 } 29 else 30 que.push(p->right); 31 } 32 } 33 //递归删除p的左右节点 并删除p 34 void Delete_child(TreeNode* p) 35 { 36 if (p) 37 { 38 Delete_child(p->left); 39 Delete_child(p->right); 40 free(p); 41 } 42 }
3、查找值为x的节点 打印出值为x的结点所有的祖先
1 //查找值为val1的节点和值为val2的节点 的最近公共祖先节点 2 //后根序遍历 找到一个节点后 将当前的栈暂存到另一个栈 然后再寻找另一个节点 最后两个栈从栈底到栈顶找最后一个相同的节点即为最近公共子节点 3 int Get_Nearest_Ancestor(TreeNode* root, int val1,int val2) 4 { 5 if (!root)return 0; 6 stack<TreeNode*> s; 7 stack<TreeNode*> temp; 8 TreeNode* p = root, * last_visit = NULL; 9 while (p || !s.empty()) 10 { 11 if (p) 12 { 13 s.push(p); 14 p = p->left; 15 } 16 else 17 { 18 p = s.top(); 19 if (p->right && p->right != last_visit) 20 { 21 s.push(p->right); 22 p = p->right->left; 23 } 24 else 25 { 26 s.pop(); 27 if ((p->val == val1|| p->val == val2)&& temp.empty())//找到第一个节点 28 { 29 temp = s;//暂存当前栈 当前栈的内容为第一个节点的所有祖先 30 } 31 else if ((p->val == val1 || p->val == val2) && !temp.empty())//找到第二个节点 32 { 33 break;//跳出while 34 } 35 last_visit = p; 36 p = NULL; 37 } 38 } 39 } 40 vector<TreeNode*> v_s; 41 vector<TreeNode*> v_t; 42 //将栈s 与栈temp中的元素pop出来存在vector中 结点高的在前 低的在后 43 while (!s.empty()) { v_s.insert(v_s.begin(), s.top()); s.pop(); } 44 while (!temp.empty()) { v_t.insert(v_t.begin(), temp.top()); temp.pop(); } 45 int i=0; 46 for (; i < v_s.size()&&i<v_t.size(); i++)//依次向前比较 找到第一个不相同的 即为最近祖先结点 47 if (v_s[i] != v_t[i]) 48 break; 49 if (i == 0) return 0;//若第一个就不相同 则无公共祖先结点 50 return v_s[i-1]->val; 51 }
4、求二叉树的宽度
1 //求二叉树的宽度 2 //层次遍历 标记每层最后一个节点 记录每层的个数 选出结点数最多的一层 3 int getBiTreeWidth(TreeNode* root) 4 { 5 if (!root) return 0; 6 queue<TreeNode*> que; 7 int count = 0; 8 int max = 0; 9 TreeNode* p, * last=root; 10 que.push(root); 11 while (!que.empty()) 12 { 13 count++; 14 p = que.front(); 15 que.pop(); 16 if (p->left)que.push(p->left); 17 if (p->right)que.push(p->right); 18 if (p == last) 19 { 20 if (que.empty()) break; 21 last = que.back(); 22 if (max < count) max = count; 23 count = 0; 24 } 25 } 26 return max; 27 }
5、满二叉树 已知先序序列pre 求后序序列post
1 //满二叉树 已知先序序列pre 求后序序列post 2 //对于满二叉树 先序为NLR 后序为LRN 因为是满二叉树 所以L与R中结点数相同 3 //所以每次只需要将N移动到LR后面 然后再进行递归 直到L和R都为一个元素为止 4 void getPost(vector<int>& pre, int start, int end) 5 { 6 //pre为先序序列 start为第一个记录下标 end为最后一个元素下标 7 int n = pre[start];//先记录根节点N 8 pre.erase(pre.begin() + start);//再将根节点移动到LR之后 9 pre.insert(pre.begin()+end,n); 10 if (end - start + 1 <= 3)return;//如果LR都为1 即当前长度为3时停止递归 11 getPost(pre, start, (end - start) / 2-1);//对L递归 12 getPost(pre, (end - start) / 2, end - 1);//对R递归 13 }
6、将二叉树的叶子结点 从左到右顺序连成一个单链表 用叶子结点的右指针来存放单链表指针 表头指针为head
1 /** 2 ** 将二叉树的叶子结点 从左到右顺序连成一个单链表 用叶子结点的右指针来存放单链表指针 表头指针为head 3 ** 方法:中根序遍历 遇到叶子结点 链起来 4 **/ 5 TreeNode* LinkLeafNode(TreeNode* root) 6 { 7 stack<TreeNode*> s; 8 TreeNode* p = root,*head=NULL,*rear=head; 9 while (p || !s.empty()) 10 { 11 if (p) 12 { 13 s.push(p); 14 p = p->left; 15 } 16 else 17 { 18 p = s.top(); 19 s.pop(); 20 if (!p->left && !p->right)//如果是叶子结点 21 { 22 if (head == NULL) //链表为空 将第一个叶子结点作为head 23 { 24 head = p; 25 rear = head; 26 } 27 else//继续在链表尾部插入叶子结点 28 { 29 rear->right = p; 30 rear = p; 31 } 32 } 33 p = p->right; 34 } 35 } 36 return head; 37 }
1 //递归中根序遍历求叶子结点链表 2 TreeNode* head_4LinkLeafNode2 = NULL, * rear_4LinkLeafNode2 = NULL;//全局变量 head与rear 3 void LinkLeafNode2(TreeNode* root) 4 { 5 //使用中根序遍历 6 if (root) 7 { 8 LinkLeafNode2(root->left); 9 if (!root->left && !root->right)//如果是叶子结点 10 { 11 if (head_4LinkLeafNode2 == NULL) //链表为空 将第一个叶子结点作为head 12 { 13 head_4LinkLeafNode2 = root; 14 rear_4LinkLeafNode2 = head_4LinkLeafNode2; 15 } 16 else//继续在链表尾部插入叶子结点 17 { 18 rear_4LinkLeafNode2->right = root; 19 rear_4LinkLeafNode2 = root; 20 } 21 } 22 LinkLeafNode2(root->right); 23 } 24 }
7、判断两个二叉树是否相似
1 //判断两个二叉树是否相似 2 //相似代表两个二叉树结构相同 1、T1 T2都是空的 ,T1,T2只有根节点 则相似 2、T1、T2 左右子树分别相似 3 //将题目转化为递归 4 5 //标准答案 6 bool BiTreeSimilar(TreeNode* T1, TreeNode* T2) 7 { 8 if (!T1 && !T2)return true;//两树都空 9 else if (!T1 || !T2) return false;//只有一棵树为空 10 else return BiTreeSimilar(T1->left, T2->left) && BiTreeSimilar(T1->right, T2->right);//两树都不空 11 } 12 //自己写的垃圾 13 bool BiTreeLike2(TreeNode* T1, TreeNode* T2) 14 { 15 if ((!T1 && !T2) || (!T1->left && !T1->right && !T2->left && !T2->right))//T1 T2都是空的 ,T1,T2只有根节点 16 return true; 17 //当T1 T2左子树存在右子树不存在 或当T1 T2右子树存在左子树不存在 或当T1 T2左右子树都存在 18 if ((T1->left&&T2->left&& !T1->right && !T2->right)|| (!T1->left && !T2->left && T1->right && T2->right) || (T1->left && T2->left && T1->right && T2->right)) 19 return BiTreeSimilar(T1->left, T2->left) && BiTreeSimilar(T1->right, T2->right); 20 else return false;//当左右子树结构不同 例如T1左子树存在 T2左子树不存在 21 }
8、二叉树的WPL 等于所有二叉树叶子节点的带权路径长度 WPL weighted path length
1 //二叉树的WPL 等于所有二叉树叶子节点的带权路径长度 WPL weighted path length 2 //法1 递归先根序遍历 使用static变量记录wpl 3 int PreOrder_WPL(TreeNode* root, int depth) 4 { 5 static int wpl = 0;//静态变量wpl 递归时只为静态 只会创建一次 6 if (!root) return 0;//为空节点 7 else if (!root->left && !root->right) wpl += root->val * depth;//为叶子节点时 计算wpl 8 else //有子树时 9 { 10 PreOrder_WPL(root->left, depth + 1); 11 PreOrder_WPL(root->right, depth + 1); 12 } 13 return wpl; 14 } 15 //法2 层次遍历 16 int Level_WPL(TreeNode* root) 17 { 18 int wpl = 0; 19 TreeNode* queue[100];//模拟队列 20 TreeNode* p; 21 int rear = -1, front = -1; 22 int depth = 0;//记录深度 23 int last = 0;//标记每层最后一个节点的下标 24 queue[++rear] = root; 25 while (front < rear) 26 { 27 p = queue[++front];//出栈 28 if (p->left)queue[++rear] = p->left; 29 if (p->right)queue[++rear] = p->right; 30 if (!p->left && !p->right)wpl += p->val * depth; 31 if (front == last)//当前节点访问到了这一层的最后一个 32 { 33 last = rear; 34 depth++; 35 } 36 } 37 return wpl; 38 }
9、由二叉树 输出中缀表达式 (2017 408真题)王道127 .20
1 //由二叉树 输出中缀表达式 2 void BtreeToE(TreeNode* root, int depth) 3 { 4 if (!root) return;//节点为空 5 else if (!root->left && !root->right) cout << root->val<<" ";//节点为叶子节点 6 else//非叶子节点 7 { 8 if (depth > 0)cout << " ( ";//若层数大于1 则在遍历左子树前加括号 9 BtreeToE(root->left, depth + 1); 10 cout << root->val << " ";//输出根节点 11 BtreeToE(root->right, depth + 1); 12 if (depth > 0)cout << " ) ";//若层数大于1 则在遍历右子树后加括号 13 } 14 }
10、leetcode 112题 路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 //法1 后根序遍历 遇到叶子节点 把栈中的数全都计算一遍 若等于sum 则返回true 11 class Solution { 12 public: 13 bool hasPathSum(TreeNode* root, int sum) { 14 TreeNode* s[1000]; 15 int all=0; 16 int top=-1; 17 TreeNode* last_visit=NULL; 18 TreeNode* p=root; 19 while(p||top!=-1) 20 { 21 if(p) 22 { 23 s[++top]=p; 24 p=p->left; 25 } 26 else 27 { 28 p=s[top]; 29 if(p->right&&p->right!=last_visit) 30 { 31 s[++top]=p->right; 32 p=p->right->left; 33 } 34 else 35 { 36 if(!p->left&!p->right)//为叶子节点时进行计算 37 { 38 for(int i=0;i<=top;i++) 39 all+=s[i]->val; 40 if(all==sum)return true; 41 else all=0; 42 } 43 last_visit=p; 44 top=top-1; 45 p=NULL; 46 } 47 } 48 } 49 return false; 50 } 51 }; 52 //法2 后根序遍历 边遍历边减去根节点的值 53 class Solution { 54 public: 55 bool hasPathSum(TreeNode* root, int sum) { 56 TreeNode* s[1000]; 57 int all=0; 58 int top=-1; 59 TreeNode* last_visit=NULL; 60 TreeNode* p=root; 61 while(p||top!=-1) 62 { 63 if(p) 64 { 65 s[++top]=p; 66 sum-=p->val; 67 p=p->left; 68 } 69 else 70 { 71 p=s[top]; 72 if(p->right&&p->right!=last_visit) 73 { 74 s[++top]=p->right; 75 sum-=p->right->val; 76 p=p->right->left; 77 } 78 else 79 { 80 if(!p->left&!p->right)//为叶子节点时进行计算 81 { 82 if(sum==0) return true; 83 } 84 last_visit=p; 85 sum+=last_visit->val; 86 top=top-1; 87 p=NULL; 88 } 89 } 90 } 91 return false; 92 } 93 }; 94 //法三 递归 95 class Solution { 96 public: 97 bool hasPathSum(TreeNode* root, int sum) { 98 if(root==NULL) return false;//如果根节点为空 99 else if(!root->left&&!root->right&&sum-root->val==0) return true;//为叶子节点 且当前节点就等于sum 返回true; 100 else return hasPathSum(root->left, sum-root->val)|| hasPathSum(root->right,sum-root->val);//不空且不为叶子节点 101 } 102 };
11、leetcode 第235题二叉搜索树的最近公共祖先
1 //法1 利用队列存储p和q的祖先节点 在找到最近公共祖先 2 class Solution { 3 public: 4 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 5 vector<TreeNode*> v1,v2; 6 TreeNode* point=root; 7 while(point->val!=p->val) 8 { 9 v1.push_back(point); 10 if(point->val>p->val) 11 point=point->left; 12 else 13 point=point->right; 14 } 15 v1.push_back(point); 16 point=root; 17 while(point->val!=q->val) 18 { 19 v2.push_back(point); 20 if(point->val>q->val) 21 point=point->left; 22 else 23 point=point->right; 24 } 25 v2.push_back(point); 26 int i=0; 27 for(;i<v1.size()&&i<v2.size();i++) 28 if(v1[i]!=v2[i]) break; 29 if(i==0) return NULL; 30 else return v1[i-1]; 31 } 32 };
1 //法2 由于二叉搜索树的性质 当p和q分别出现在一个根节点的 左右子树中 则最近公共节点就为这个根节点 2 //递归法 时间复杂度最坏O(N) 空间复杂度最坏O(H) 3 class Solution { 4 public: 5 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 6 if(!root) return NULL; 7 if(root->val>p->val&&root->val>q->val) return lowestCommonAncestor(root->left,p,q);//若p q在root左边 8 else if(root->val<p->val&&root->val<q->val) return lowestCommonAncestor(root->right,p,q);//若p q在root右边 9 else//p q在root两边 10 return root; 11 } 12 };
1 //法3 利用法二的原理进行迭代 2 class Solution { 3 public: 4 TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { 5 if(!root) return NULL; 6 TreeNode* point=root; 7 while(point) 8 { 9 if(point->val>p->val&&point->val>q->val)//若p q在root左边 10 point=point->left; 11 else if(point->val<p->val&&point->val<q->val)//若p q在root右边 12 point=point->right; 13 else//p q在root两边 14 return point; 15 } 16 return NULL; 17 } 18 };
12、leetcode 257题 二叉树的所有路径
给定一个二叉树,返回所有从根节点到叶子节点的路径。
1 //法1 后根序遍历 2 class Solution { 3 public: 4 vector<string> binaryTreePaths(TreeNode* root) { 5 vector<string> result; 6 if(!root) return result; 7 vector<TreeNode*> v; 8 TreeNode* p=root,*last=NULL; 9 while(p||!v.empty()) 10 { 11 if(p) 12 { 13 v.push_back(p); 14 p=p->left; 15 } 16 else 17 { 18 p=v.back(); 19 if(p->right&&last!=p->right) 20 { 21 v.push_back(p->right); 22 p=p->right->left; 23 } 24 else 25 { 26 if(!p->left&&!p->right) 27 { 28 string s=""; 29 for(const auto& it:v) 30 { 31 s+=to_string(it->val); 32 if(it!=v.back()) 33 s+="->"; 34 } 35 result.push_back(s); 36 } 37 v.erase(v.end()-1); 38 last=p; 39 p=NULL; 40 } 41 } 42 } 43 return result; 44 } 45 };
1 //法2 递归 2 class Solution { 3 public: 4 vector<string> binaryTreePaths(TreeNode* root) { 5 vector<string> result; 6 binaryTreePath(root,"",result); 7 return result; 8 } 9 void binaryTreePath(TreeNode* p,string pre_path,vector<string> &result) 10 { 11 if(!p) return; 12 if(!p->left&&!p->right) 13 { 14 pre_path+=to_string(p->val); 15 result.push_back(pre_path); 16 } 17 binaryTreePath(p->left,pre_path+to_string(p->val)+"->",result); 18 binaryTreePath(p->right,pre_path+to_string(p->val)+"->",result); 19 } 20 };