Binary-Tree
本篇文章为shaoyuanhangyes.github.io/二叉树
的重置版本
更新了部分代码 更改了排版 舍弃了冗杂的赘述内容 利用STL容器进行了更新
二叉树
![二叉树example](B.png)
二叉树结构体
1 2 3 4 5 6
| struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x):val(x),left(NULL),right(NULL) {} };
|
二叉树的创建
采用的是更为直观的层序遍历的方式 将二叉树和对应数组序号的元素一一填入
1 2 3 4 5 6 7 8 9 10
| TreeNode* createTree(const vector<int> &nums,int len,int index){ TreeNode *root=NULL; if(index<len&&nums[index]!=-1){ root = new TreeNode(nums[index]); root->left = createTree(nums,len,2*index+1); root->right= createTree(nums,len,2*index+2); } return root; }
|
二叉树的遍历
二叉树的遍历中 层序遍历属于广度优先(BFS) 前中后序遍历都属于深度优先(DFS)
层序遍历
利用队列进行迭代
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> res; if(!root) return res; queue<TreeNode* > Tree; Tree.push(root); while(!Tree.empty()){ vector<int> temp; int len=Tree.size(); while(len--){ TreeNode *pNode=Tree.front(); Tree.pop(); temp.push_back(pNode->val); if(pNode->left) Tree.push(pNode->left); if(pNode->right) Tree.push(pNode->right); } res.push_back(temp); } return res; }
|
打印二维数组的代码为
1 2 3 4 5 6 7 8 9 10
| void PrintMartrix(vector<vector<int>>& res){ for(int i=0;i<res.size();++i){ cout<<"["; for(int j=0;j<res[i].size();++j){ cout<<" "<<res[i][j]<<" "; } cout<<"]"<<endl; } }
|
先序遍历
遍历顺序为 根 左 右
1 2 3 4 5 6 7
| void preOrder(TreeNode *root){ if(!root) return; cout<<root->val<<" "; preOrder(root->left); preOrder(root->right); }
|
中序遍历
遍历顺序为 左 根 右
1 2 3 4 5 6 7
| void inOrder(TreeNode *root){ if(!root) return; inOrder(root->left); cout<<root->val<<" "; inOrder(root->right); }
|
后序遍历
遍历顺序为 左 右 根
1 2 3 4 5 6 7
| void postOrder(TreeNode *root){ if(!root) return; postOrder(root->left); postOrder(root->right); cout<<root->val<<" "; }
|
全部代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include <iostream> #include <vector> #include <queue> using namespace std; struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x):val(x),left(NULL),right(NULL) {} };
TreeNode* createTree(const vector<int> &nums,int len,int index){ TreeNode *root=NULL; if(index<len&&nums[index]!=-1){ root = new TreeNode(nums[index]); root->left = createTree(nums,len,2*index+1); root->right= createTree(nums,len,2*index+2); } return root; }
void PrintMartrix(vector<vector<int>>& res){ for(int i=0;i<res.size();++i){ cout<<"["; for(int j=0;j<res[i].size();++j){ cout<<" "<<res[i][j]<<" "; } cout<<"]"<<endl; } }
vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> res; if(!root) return res; queue<TreeNode* > Tree; Tree.push(root); while(!Tree.empty()){ vector<int> temp; int len=Tree.size(); while(len--){ TreeNode *pNode=Tree.front(); Tree.pop(); temp.push_back(pNode->val); if(pNode->left) Tree.push(pNode->left); if(pNode->right) Tree.push(pNode->right); } res.push_back(temp); } return res; }
void preOrder(TreeNode *root){ if(!root) return; cout<<root->val<<" "; preOrder(root->left); preOrder(root->right); }
void inOrder(TreeNode *root){ if(!root) return; inOrder(root->left); cout<<root->val<<" "; inOrder(root->right); }
void postOrder(TreeNode *root){ if(!root) return; postOrder(root->left); postOrder(root->right); cout<<root->val<<" "; }
int main(){ vector<int> nums={0,1,2,3,4,5,6,7,8,-1,10}; int len=nums.size(); TreeNode *root=createTree(nums,len,0); cout<<"层序遍历的二维数组序列为: "<<endl; vector<vector<int>> res=levelOrder(root); PrintMartrix(res); cout<<endl<<"先序遍历序列为: "; preOrder(root); cout<<endl<<"中序遍历序列为: "; inOrder(root); cout<<endl<<"后序遍历序列为: "; postOrder(root); return 0; }
|
程序输出结果为
1 2 3 4 5 6 7 8 9 10 11
| 层序遍历的二维数组序列为: [ 0 ] [ 1 2 ] [ 3 4 5 6 ] [ 7 8 10 ]
先序遍历序列为: 0 1 3 7 8 4 10 2 5 6 中序遍历序列为: 7 3 8 1 4 10 0 5 2 6 后序遍历序列为: 7 8 3 10 4 1 5 6 2 0 Process finished with exit code 0
|
二叉树进阶
更多进阶的算法以及刷题解答见shaoyuanhangyes/LeetCode/树
二叉树刷题C++模版
1 2 3 4 5 6 7 8 9
|
struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x):val(x),left(NULL),right(NULL) {} };
|
创建二叉树
因为二叉树是非线性结构 不易于直接表示 因此采取顺序存储的思想 按照数组的序号对这个数组以层序遍历的方式创建二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| TreeNode* createTree(const vector<int> &nums,int len,int index){ TreeNode *root=NULL; if(index<len&&nums[index]!=-1){ root = new TreeNode(nums[index]); root->left = createTree(nums,len,2*index+1); root->right= createTree(nums,len,2*index+2); } return root; } int main(){ vector<int> nums={0,1,2,3,4,5,6,7,8,-1,10}; int len=nums.size(); TreeNode *root=createTree(nums,len,0); return 0; }
|
创建后的二叉树为
1 2 3 4 5 6 7 8 9
| 0 / \ 1 2 / \ / \ 3 4 5 6 / \ \ 7 8 10
|
二叉树的遍历们
前序遍历
前序遍历(先序遍历) 遍历的次序为 根 左 右
1 2 3 4 5 6 7 8 9 10 11
| 0 / \ 1 2 / \ / \ 3 4 5 6 / \ \ 7 8 10 为例子
前序遍历的序列为 [0 1 3 7 8 4 10 2 5 6]
|
前序遍历序列的第一个节点一定是二叉树的根节点
前序遍历递归代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| vector<int> res; vector<int> preorderTraversal(TreeNode* root) { if(root!=NULL){ res.push_back(root->val); preorderTraversal(root->left); preorderTraversal(root->right); } return res; } int main(){ vector<int> nums={0,1,2,3,4,5,6,7,8,-1,10}; int len=nums.size(); TreeNode *root=createTree(nums,len,0); cout<<"先序遍历的序列为:"<<endl vector<int> preOrder=preOrderTraversal(root); for(auto x:preOrder) cout<<x<<" "; return 0; }
|
前序遍历迭代代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| vector<int> preorderTraversal(TreeNode* root) { vector<int> res; stack<TreeNode* > st; TreeNode* node=root; while(!st.empty()||node){ while(node){ st.push(node); res.push_back(node->val); node=node->left; } node=st.top(); st.pop(); node=node->right; } return res; } int main(){ vector<int> nums={0,1,2,3,4,5,6,7,8,-1,10}; int len=nums.size(); TreeNode *root=createTree(nums,len,0); cout<<"先序遍历的序列为:"<<endl vector<int> preOrder=preOrderTraversal(root); for(auto x:preOrder) cout<<x<<" "; return 0; }
|
中序遍历
中序遍历 遍历的次序为 左 根 右
1 2 3 4 5 6 7 8 9 10 11
| 0 / \ 1 2 / \ / \ 3 4 5 6 / \ \ 7 8 10 为例子
中序遍历的序列为 [7 3 8 1 4 10 0 5 2 6]
|
通过前序遍历确定了二叉树的根节点后 在中序遍历序列中 根节点的左半部分都是根节点的左子树 根节点的右半部分都是根节点的右子树
BST 二叉搜索树 又名二叉排序树 二叉查找树 的中序序列一定是按从小到大的顺序排列的
中序遍历递归代码
1 2 3 4 5 6 7 8 9 10 11 12 13
| vector<int> res; vector<int> inorderTraversal(TreeNode* root) { if(root!=NULL){ inorderTraversal(root->left); res.push_back(root->val); inorderTraversal(root->right); } return res; }
|
中序遍历迭代代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| vector<int> inorderTraversal(TreeNode* root) { vector<int> res; stack<TreeNode *> st; TreeNode *node=root; while(!st.empty()||node){ while(node){ st.push(node); node=node->left; } node=st.top(); st.pop(); res.push_back(node->val); node=node->right; } return res; }
|
后序遍历
后序遍历 遍历的次序为 左 右 根
1 2 3 4 5 6 7 8 9 10 11
| 0 / \ 1 2 / \ / \ 3 4 5 6 / \ \ 7 8 10 为例子
后序遍历的序列为 [7 8 3 10 4 1 5 6 2 0]
|
后序遍历序列的最后一个节点一定是根节点
后序遍历递归代码
1 2 3 4 5 6 7 8 9 10 11
| vector<int> res; vector<int> postorderTraversal(TreeNode* root){ if(root!=NULL){ postorderTraversal(root->left); postorderTraversal(root->right); res.push_back(root->val); } return res; }
|
后序遍历迭代代码
第一种解法 标记位
prev记录已经输出到res数组中的上一个节点 防止出现某一节点有右孩子 右孩子输出后 根据栈回到右孩子的父节点 然后又判断是否有右孩子的死循环 当判断到node->right==prev成立 即父节点的右孩子上一次被访问过 就输出这个父节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| vector<int> postorderTraversal(TreeNode* root){ vector<int> res; stack<TreeNode* > st; TreeNode* node=root; TreeNode* prev=NULL; while(!st.empty()||node){ while(node){ st.push(node); node=node->left; } node=st.top(); if(node->right==NULL||node->right==prev){ res.push_back(node->val); st.pop(); prev=node; node=NULL; } else node=node->right; } return res; }
|
第二种解法 反转
根据前序遍历的思想 将遍历序列规则转换为 根 右 左
序列输出到数组后 将整个数组反转过来 就变成了左 右 根
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| vector<int> preorderTraversal(TreeNode* root) { vector<int> res; stack<TreeNode* > st; TreeNode* node=root; while(!st.empty()||node){ while(node){ st.push(node); res.push_back(node->val); node=node->right; } node=st.top(); st.pop(); node=node->left; } reverse(res.begin(),res.end()); return res; }
|
层序遍历
层序遍历 每一层元素 按从左到右的顺序逐层输出
1 2 3 4 5 6 7 8 9 10
| 0 / \ 1 2 / \ / \ 3 4 5 6 / \ \ 7 8 10 为例子
层序遍历的序列为 [0 1 2 3 4 5 6 7 8 10]
|
层序遍历迭代算法
利用队列进行迭代 返回二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| vector<vector<int>> levelOrder(TreeNode* root) { vector<vector<int>> res; if(!root) return res; queue<TreeNode* > Tree; Tree.push(root); while(!Tree.empty()){ vector<int> temp; int len=Tree.size(); while(len--){ TreeNode *pNode=Tree.front(); Tree.pop(); temp.push_back(pNode->val); if(pNode->left) Tree.push(pNode->left); if(pNode->right) Tree.push(pNode->right); } res.push_back(temp); } return res; }
|
打印二维数组的方法
1 2 3 4 5 6 7 8 9 10 11
| void PrintMartrix(vector<vector<int>>& res){ for(int i=0;i<res.size();++i){ cout<<"["; for(int j=0;j<res[i].size();++j){ cout<<" "<<res[i][j]<<" "; } cout<<"]"<<endl; } }
|
Binary Search Tree
二叉搜索树 又被翻译为二叉排序树 二叉查找树
特点具体为 每个节点的值 大于其任意左侧子节点的值 小于其任意右侧子节点的值
BST插入
给定二叉搜索树(BST)的根节点和要插入树中的值 将值插入二叉搜索树 返回插入后二叉搜索树的根节点 保证原始二叉搜索树中不存在新值
注意 可能存在多种有效的插入方式 只要树在插入后仍保持为二叉搜索树即可 你可以返回任意有效的结果
示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 例如,
给定二叉搜索树:
4 / \ 2 7 / \ 1 3
和 插入的值: 5 你可以返回这个二叉搜索树:
4 / \ 2 7 / \ / 1 3 5 或者这个树也是有效的:
5 / \ 2 7 / \ 1 3 \ 4
|
递归解法
1 2 3 4 5 6 7 8 9 10
| class Solution { public: TreeNode* insertIntoBST(TreeNode* root, int val) { if(root==NULL) return new TreeNode(val); if(val<root->val) root->left=insertIntoBST(root->left,val); if(val>root->val) root->right=insertIntoBST(root->right,val); return root; } };
|
复杂度分析
- 时间复杂度: O(H) H为Tree的高度 平均情况 最坏情况O(N)
- 空间复杂度: 平均情况下O(H) 最坏情况O(N) 是在递归过程中堆栈使用的空间
复杂度中最坏的情况
就是二叉树高度为二叉树节点数量的时候 即
要插入的元素需要遍历到最深才能插入
迭代解法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| TreeNode* insertIntoBST(TreeNode* root,int val){ TreeNode* node=root; while(node!=NULL){ if(val>node->val){ if(node->right==NULL){ node->right=new TreeNode(val); return root; } else node=node->right; } else{ if(node->left==NULL){ node->left=new TreeNode(val); return root; } else node=node->left; } } return new TreeNode(val); }
|
复杂度分析
- 时间复杂度: O(H) H为Tree的高度 平均情况 最坏情况O(N)
- 空间复杂度: O(1)