树_数据结构
二叉树基本数据结构
目录
- [相同树](#100.Same Tree)
- [二叉树的层序遍历](#102. Binary Tree Level Order Traversal)
- [数组转换为二分树](#108. Convert Sorted Array to Binary Search Tree)
- [树的非递归遍历](#94Binary Tree Inorder Traversal)
- [树的非递归遍历version2](#Binary Tree with loop)
- [不同的二叉树](#96 Unique Binary Search TreesI)
- [实现不同的二叉树](#95Unique Binary Search Trees II)
- [高度平衡二叉树](#110Balanced Binary Tree)
- [二叉查找树中查找](#700Search in a Binary Search Tree)
- [根据前序和中序遍历生成二叉树](#105.Construct Binary Tree with preorder and inorder traversal)
- [根据中序个后序遍历生成二叉树](#106.Construct Binary tree with inorder and postorder traversal)
- [将二叉树变成一个链表形式二叉树](#114.Flatten Binary tree To Linked List)
- [N个孩子结点用数组表示的树的前序非递归遍历](#589.N-ary Tree PreOrder Traversal)
- [872.叶子结点相同的树](#872.Leaf similar trees)
- [129.所有根结点的路径和](#129.Sum Root to Leaf Numbers)
- [226.反转二叉树](#226.Invert Binary Tree)
线索二叉树:
n个结点的二叉链表 每个结点有左右孩子两个指针域,有2n个指针域 ;n-1条分支线树。
100.Same Tree
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==NULL && q==NULL)
return true;
else if((p==NULL && q!=NULL)||(p!=NULL && q==NULL))
return false;
if(p->val==q->val){
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
return false;
}
};
102. Binary Tree Level Order Traversal
// 二叉树的层序遍历是用数据结构 队列queue 来实现的
// 满足基本的先进先出的的顺序
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// 利用上述的结构定义
// 将结点按层序结构依次打印
// 判断程序结束的语句还是有一点欠缺
void levelOrderTraverse(TreeNode *root){
queue<TreeNode*> q;
if(root)
q.push(root);
while(!q.empty()){
TreeNode front=q.front();
cout<<front->val<<endl;
q.pop();
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
}
}
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> ans;
DFS(root,0,ans);
return ans;
}
private:
void DFS(TreeNode* root,int depth,vector<vector<int>>& ans){
if(!root) return;
while (ans.size()<=depth) ans.push_back({});
ans[depth].push_back(root->val);
DFS(root->left,depth+1,ans);
DFS(root->right,depth+1,ans);
}
};
// 这个是由底向上输出的版本
// 我写了一个swap函数,利用循环将最后一元素pop后,插入到最前面的位置
// 显示的错误是void函数问题
// 这个问题还是模棱两可的,不是很清晰
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> result;
DFS(root,0,result);
reverse(result.begin(),result.end()); //添加一个reverse的内置函数
return result;
}
private:
void DFS(TreeNode *root,int depth,vector<vector<int>>&result){
if(!root)
return;
while(result.size()<=depth){
result.push_back({});
}
result[depth].push_back(root->val);
DFS(root->left,depth+1,result);
DFS(root->right,depth+1,result);
}
};
# 这个是自低向上的输出
# dfs recursively
def levelOrderBottom1(self, root):
res = []
self.dfs(root, 0, res)
return res
def dfs(self, root, level, res):
if root:
if len(res) < level + 1:
res.insert(0, [])
# 保证插入的一定位于头位置
res[-(level+1)].append(root.val)
self.dfs(root.left, level+1, res)
self.dfs(root.right, level+1, res)
108. Convert Sorted Array to Binary Search Tree
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// @param: input a array
// @return treenode root
// divide and conquer classsic
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
return Divide_Array(0,nums.size()-1,nums);
}
TreeNode* Divide_Array(int i,int j,vector<int>& nums){
if(i<0||j>=nums.size()||i>j||i>=nums.size()||j<0){
return NULL;
}
int mid=i+(j-i)/2;
TreeNode* root=new TreeNode(nums[mid]);
root->left=Divide_Array(i,mid-1,nums);
root->right=Divide_Array(mid+1,j,nums);
return root;
}
};
二叉树前序非递归遍历
94Binary Tree Inorder Traversal
#include<stack>
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// need stack data-structure
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
TreeNode *cur=root;
//define a stack ?
stack<TreeNode *> s;
vector<int> ans;
while(cur){
if(cur->left){
s.push(cur);
cur=cur->left;
}
else{
ans.push_back(cur->val);
cur=cur->right;
}
while(!cur && !s.empty()){
cur=s.top();
ans.push_back(cur->val);
s.pop();
cur=cur->right;
}
}
return ans;
}
};
中序遍历先考虑leftnode 左结点是不是存在,再将结点进行进栈。(左根右)
// define the stack data-structure
typedef struct Node{
BTree data;
struct Node *next;
}Node,*pNode;
typedef struct Stack{
pNode pTop;
pNode pBottom;
}Stack,*PSTACK;
// define the tree node data-structure
typedef struct BTNode{
char data;
struct BTNode *pLchild;
struct BTNode *pRchild;
}BTNode,*BTree;
void inorder_traverse(BTree pTree){
PSTACK stack=create_stack();
BTree node_pop;
BTree pcur=pTree;
while(pcur || !is_empty(stack)){
if(pcur->pLchild){
push_stack(stack, pcur);
pcur=pcur->pLchild;
}
else{
printf("%c",pcur->data);
pcur=pcur->pRchild;
}
while(!pcur && !is_empty(stack)){
pcur=get_top(stack);
printf("%c",pcur->data);
pop_stack(stack, &node_pop);
pcur=pcur->pRchild;
}
}
}
后序遍历是现将结点进栈,检查左右结点都是否存在,再考虑将右结点,左结点依次进栈。
// 基础的数据结构实现如中序遍历
void posorder_traverse(BTree pTree){
PSTACK stack=create_stack();
BTree node_pop;
BTree pcur=pTree;
BTree pPre=NULL;
// first need push the first to the stack
push_stack(stack, pTree);
while(!is_empty(stack)){
pcur=get_top(stack);
// detection the node
if((pcur->pLchild==NULL && pcur->pRchild)||(pPre!=NULL &&(pcur->pLchild==pPre ||pcur->pRchild==pPre))){
printf("%c",pcur->data);
pop_stack(stack,&node_pop);
pPre=pcur;
}
else{
// other situtation,mean have left and right child
if(pcur->pRchild!=NULL)
push_stack(stack, pcur->pRchild);
if(pcur->pLchild!=NULL)
push_stack(stack, pcur->pLchild);
}
}
}
Binary Tree with loop-version 2
/*
* Date:nov.5.2018
* @author:Danny
* Program function:implement traverse the tree with loop
*/
#include<cstdlib>
using namespace std;
/*
* Define the TreeNode data structure
*/
struct TreeNode
{
int val;
TreeNode *Lchild;
TreeNode *Rchlid;
};
/*
* 1.PreOrderTraverse
*/
/*
* 遍历顺序:根-左-右
* 现将根结点进行压栈
* 当栈不为空的时候,栈顶元素出栈,并输出栈顶元素的值(根结点)
* 如果右孩子结点存在,进行压栈
* 如果左孩子结点存在,进行压栈
*/
void PreOrderTraverse(TreeNode *root){
if(!root){
cout<<"empty tree !"<<endl;
return ;
}
stack<TreeNode *> stack_node;
stack_node.push(root);
while(!stack_node.empty()){
TreeNode *temp=stack_node.top();
stack_node.pop();
cout<<temp->val<<endl; // 现将根结点进行输出
if(temp->Rchlid){
stack_node.push(temp->Rchlid);
}
if(temp->Lchild){
stack_node.push(temp->Lchild);
}
}
}
/*
* 2.inOrderTraverse
*/
/*
* 遍历顺序:左-根-右
* 初始结点为根结点,如果结点不为空,将当前结点进行压栈
* 将结点替换为结点的左孩子
* 否则输出栈顶的元素
* 当前结点替换为结点的右孩子,出栈
*/
void inOrderTraverse(TreeNode *root){
if(!root){
cout<<"empty tree!"<<endl;
return ;
}
stack<TreeNode *>stack_node;
while(root|| !stack_node.empty()){
if(root){
stack_node.push(root);
root=root->Lchild;
}
else{
TreeNode *cur=stack_node.top();
stack_node.pop();
cout<<cur->val<<endl;
root=cur->Rchlid;
}
}
}
/*
* 3.PostOrderTraverse
*/
/*
* 遍历顺序:左-右-根
* 由两个栈来实现
* 先把根结点压入第一个栈
*/
void PostOrderTraverse(TreeNode *root){
if(!root){
cout<<"empty tree !"<<endl;
return ;
}
stack<TreeNode *>stack1,stack2;
stack1.push(root);
while(!stack1.empty()){
TreeNode *cur=stack1.top();
stack1.pop();
stack2.push(cur);
if(cur->Lchild)
stack1.push(cur-<Lchild);
if(cur->Rchlid)
stack1.push(cur->Rchlid);
}
while(!stack2.empty()){
TreeNode *top=stack2.top();
stack2.pop();
cout<<top->val<<endl;
}
}
96 Unique Binary Search Trees
前序遍历是将根结点进展,在考虑左结点是否存在。(根左右)
class Solution {
public:
int numTrees(int n) {
vector<int> sub_tree(n+1,0);
sub_tree[0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
sub_tree[i]+=sub_tree[j]*sub_tree[i-j-1];
}
}
return sub_tree[n];
// formula derivation error
/*
if(n==0)
return 0;
if(n==1)
return 1;
while(n>=2){
return 2*(numTrees(n-1)+numTrees(n-2));
}
*/
}
};
95Unique Binary Search Trees II
-这个代码是没有看懂的,需要后续继续补充学习
// create :2018.10.12
// @author:dengshuo
class Solution {
private:
vector<TreeNode*> helper(int start, int end){
vector<TreeNode*> res;
if(start > end) {
res.push_back(NULL);
return res;
}
// use two pointer
for(int i = start; i <= end; i++){
vector<TreeNode*> lefts = helper(start, i - 1);
vector<TreeNode*> rights = helper(i + 1, end);
for(int j = 0; j < (int)lefts.size(); j++){
for(int k = 0; k < (int)rights.size(); k++){
TreeNode* root = new TreeNode(i);
root->left = lefts[j];
root->right = rights[k];
res.push_back(root);
}
}
}
return res;
}
public:
vector<TreeNode*> generateTrees(int n) {
if(n == 0) return vector<TreeNode*>(0);
return helper(1,n);
}
};
// Author: Huahua
// Running time: 16 ms
class Solution {
public:
vector<TreeNode*> generateTrees(int n) {
if (n == 0) return {};
const auto& ans = generateTrees(1, n);
cout << ans.size() << endl; // 计算结点数
return ans;
}
private:
vector<TreeNode*> generateTrees(int l, int r) {
if (l > r) return { nullptr };
vector<TreeNode*> ans;
for (int i = l; i <= r; ++i)
for (TreeNode* left : generateTrees(l, i - 1))
for (TreeNode* right : generateTrees(i + 1, r)) {
ans.push_back(new TreeNode(i));
ans.back()->left = left;
ans.back()->right = right;
}
return ans;
}
};
110Balanced Binary Tree
- 实现高度平衡二叉树
- 平衡二叉树:
结点为空或者左右两个子树高度差的绝对值不超过1.
还是使用递归来实现,要注意这个递归实现的顺序流程
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isBalanced(TreeNode* root) {
bool flags=true; //定义一个贯穿运行始终的旗帜变量。如果不定义 对于私有函数无法传递变量
lrdepth(root,flags);
return flags;
}
private:
int lrdepth(TreeNode* root,bool &flags){
if(!root)
return 0;
int l_num=lrdepth(root->left,flags);
int r_num=lrdepth(root->right,flags);
if(abs(l_num-r_num)>1){
flags=false;
}
return 1+max(l_num,r_num);
}
};
700.Search in a Binary Search Tree
class Solution {
public:
TreeNode* searchBST(TreeNode* root, int val) {
if(root==NULL || root->val==val)
return root; //当树为空的时候,返回 [] 不知道为什么这个还是可以运行。
if(val<root->val)
return searchBST(root->left,val);
else{
return searchBST(root->right,val);
}
}
};
105.Construct Binary Tree with preorder and inorder traversal
// 这就是我的思路
// 根据preorder确定当前根结点的位置
// 在根据 根结点在inorder的位置,划分左右子树
// 递归的进行,知道左右子树都为空,或者前序和后序遍历为空截止递归
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(perorder.size()==0 || inorder.size()==0)
return NULL;
int index= //我找不出根结点在中序遍历的位置,无法进行划分
TreeNode *root=preorder[0];
root->left=bulidTree();
root->right=bulidTree();
}
};
//添加辅助函数
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return builTreeHelper(preorder,0,preorder.size(),inorder,0,inorder.size());
}
TreeNode* builTreeHelper(vector<int>& preorder, int sp, int ep, vector<int>& inorder, int si, int ei) {
if (sp == ep) return nullptr;
TreeNode* root = new TreeNode(preorder[sp]);
int dis = find(inorder.begin()+si,inorder.begin()+ei,preorder[sp]) - inorder.begin() - si;
root->left = builTreeHelper(preorder,sp+1,sp+1+dis,inorder,si,si+dis);
root->right = builTreeHelper(preorder,sp+1+dis,ep,inorder,si+dis+1,ei);
return root;
}
// 未通过的代码
// 同样也是使用辅助函数来实现
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size()==0 || inorder.size()==0)
return NULL;
return recursionBulid(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
}
private:
TreeNode *recursionBulid(vector<int>& preorder,int startpreorder,int endpreorder,vector<int>& inorder,int startinorder,int endinorder){
int rootvalue=preorder[startpreorder];
TreeNode *root= new TreeNode(0);
root->val=rootvalue;
root->left=root->right=NULL;
if(startpreorder==endpreorder){
if(startinorder==endinorder)
return root;
}
int root_inorder=startpreorder;
while(root_inorder<=endinorder && inorder[root_inorder]!=rootvalue){
root_inorder++;
}
int root_left_length=root_inorder-startpreorder;
int left_preorder_end=startpreorder+root_left_length;
if(root_left_length>0){
root->left=recursionBulid(preorder,startpreorder+1,left_preorder_end,inorder,startinorder,root_inorder-1);
}
if(root_left_length<endpreorder-startpreorder){
root->right=recursionBulid(preorder,left_preorder_end+1,endpreorder,inorder,root_inorder+1,endinorder);
}
return root;
}
};
106.Construct Binary tree with inorder and postorder traversal
// 按照自己的思路来写的
// Runtime error
// 错可能就错在递归函数的边界值。能够取到,是从什么开始
// 例如 取左值,不取右值。可以对比下面一个代码的区间问题
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// can construct a binary tree
if(inorder.size()==0 || postorder.size()==0){
return nullptr;
}
if(inorder.size()==1 && postorder.size()==1){
TreeNode * root=new TreeNode(postorder[0]);
return root;
}
return recursionBulid(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1);
}
private:
TreeNode *recursionBulid(vector<int>& inorder,int start_in,int end_in,vector<int> &postorder,int start_post,int end_post){
TreeNode *root=new TreeNode(postorder[end_post]);
int root_inorder=start_in;
int root_value=postorder[end_post];
while(root_inorder<end_in && inorder[root_inorder]!=root_value){
root_inorder++;
}
int left_length=root_inorder-start_in;
root->left=recursionBulid(inorder,start_in,root_inorder-1,postorder,start_post,left_length-start_post);
root->right=recursionBulid(inorder,root_inorder+1,end_in,postorder,left_length+1,end_post-1);
return root;
}
};
// 利用vecotr 可以迭代的性质
// 注意便捷的情况
public:
typedef vector<int>::iterator Iter;
TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
// write your code here
if (inorder.size() == 0)
return NULL;
return buildTreeRecur(inorder.begin(), inorder.end(), postorder.begin(),
postorder.end());
}
TreeNode *buildTreeRecur(Iter istart, Iter iend, Iter pstart, Iter pend)
{
if(istart == iend)return NULL;
int rootval = *(pend-1);
Iter iterroot = find(istart, iend, rootval);
TreeNode *res = new TreeNode(rootval);
res->left = buildTreeRecur(istart, iterroot, pstart, pstart+(iterroot-istart));
res->right = buildTreeRecur(iterroot+1, iend, pstart+(iterroot-istart), pend-1);
return res;
}
};
114.Flatten Binary tree To Linked List
// 这是自己写的
// 思路:
// 1.利用前序遍历preorder,遍历所有结点
// 2.构造二叉树,一直添加右子结点
// 这个代码运行时错误的
class Solution {
public:
void flatten(TreeNode* root) {
queue<TreeNode*> q=preOrder(root);
q.pop();
while(!q.empty()){
root->left=NULL;
root->right=q.front();
q.pop();
root=q.front();
}
}
private:
queue<TreeNode*>preOrder(TreeNode *root){
stack<TreeNode *> s;
queue<TreeNode *> q;
s.push(root);
while(!s.empty()){
TreeNode *temp=s.top();
s.pop();
q.push(temp);
if(temp->right){
s.push(temp->right);
}
if(temp->left){
s.push(temp->left);
}
}
return q;
}
};
// 参考别人的代码
// 这个写的真的是很漂亮的代码
// 直接利用二叉树的性质来进行结点相互交换完成排序的实现
// 真的牛皮!!!!!
class Solution {
public:
void flatten(TreeNode *root) {
TreeNode*now = root;
while (now)
{
if(now->left)
{
//Find current node's prenode that links to current node's right subtree
TreeNode* pre = now->left;
while(pre->right)
{
pre = pre->right;
}
pre->right = now->right;
//Use current node's left subtree to replace its right subtree(original right
//subtree is already linked by current node's prenode
now->right = now->left;
now->left = NULL;
}
now = now->right;
}
}
};
589.N-ary Tree PreOrder Traversal
/*
思路清晰:
1.利用栈来实现树的前序遍历
2.对于孩子结点,进行pop_back()进栈
代码正确:
就是root不存在的返回值存在一点小问题
直接返回 定义值(未初始化的值)
*/
// 注意 结点的定义发生了变化
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public:
vector<int> preorder(Node* root) {
vector<int> result;
stack<Node*> s; // 利用栈来实现树的前序遍历
s.push(root);
if(!root)
return result;
while(!s.empty())
{
Node *temp=s.top();
s.pop();
result.push_back(temp->val);
while(!temp->children.empty())。// 返回孩子结点中的所有孩子
{
s.push(temp->children.back()); // 压缩到栈中
temp->children.pop_back();
}
}
return result;
}
};
872.Leaf similar trees
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
// 也可以解决,但是容易出现问题
class Solution {
public:
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
return Leaf(root1)==Leaf(root2)
}
vector<int> preorder(TreeNode *root){
vector<int> leafnode;
if(!root)
return leafnode;
if(!root->left && !root->right){
leafnode.push_back(root->val);
}
preorder(root->left);
preorder(root->right);
return leafnode;
}
};
//
// 最大的不同就在于,将参数放在函数中
// 函数是一个无返回的函数
class Solution {
public:
bool leafSimilar(TreeNode* root1, TreeNode* root2) {
vector<int> leafnode1,leafnode2;
preorder(root1,leafnode1);
preorder(root2,leafnode2);
return leafnode1==leafnode2;
}
void preorder(TreeNode *root,vector<int> &leafnode){
if(!root)
return ;
if(!root->left && !root->right){
leafnode.push_back(root->val);
}
preorder(root->left,leafnode);
preorder(root->right,leafnode);
}
};
129.Sum Root to Leaf Numbers
// 理解错误,没有分开左右子树
// 这个是计算所有结点(前序)的路径和
class Solution {
public:
int sumNumbers(TreeNode* root) {
int sum=0;
preorder(root,sum);
return sum;
}
void preorder(TreeNode *root,int &sum){
if(!root)
return ;
sum=sum*10+root->val;
preorder(root->left,sum);
preorder(root->right,sum);
}
};
// 正确版本
// 就是思考的方向不对
// 1.要分左右子树
// 2.现考虑左右子树都不存在的情况
class Solution {
public:
int sumNumbers(TreeNode* root) {
if(!root)
return 0;
return sumAll(root,0);
}
int sumAll(TreeNode *root,int x){
if(root->left==NULL && root->right==NULL)
return x*10+root->val;
int lrSum=0; // 这个用来计算左右子树的总和
if(root->left!=NULL)
lrSum+=sumAll(root->left,x*10+root->val);
if(root->right!=NULL)
lrSum+=sumAll(root->right,x*10+root->val);
return lrSum;
}
};
226.Invert Binary Tree
// 这道题的思想其实很简单
// 就是最基本的DFS,深度优先遍历
// 先解决一个一个分支,这个思想我还是有点缺乏
// 自己写的
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(!root)
return root;
TreeNode *var=root;
Helper(var);
return root;
}
void Helper(TreeNode *var){
// 再写个结束条件
TreeNode *temp=var->left;
var->left=var->right;
var->right=temp;
Helper(var->left);
Helper(var->right);
}
};
// 这个是正确利用深度优先遍历的代码
class Solution {
public:
TreeNode* invertTree(TreeNode* root) {
if(!root)
return root;
if(!root->left && !root->right)
return root;
TreeNode *temp;
temp=invertTree(root->left);
root->left=invertTree(root->right);
root->right=temp;
return root;
}
};
不要用狭隘的眼光看待不了解的事物,自己没有涉及到的领域不要急于否定.
每天学习一点,努力过好平凡的生活.