致我们终将忘记的算法(树中天地)

********二叉树的节点定义*********

struct TreeNode{

    int val;

    TreeNode *left;

    TreeNode *right;

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

};

*******二叉树的遍历*****************

1->树的先序遍历

vector<int> preorderTraversal(TreeNode *root){

    vector<int> result;

    const TreeNode *p;

    stack<const TreeNode *> s;

    p=root;

    if(p!=root)  s.push(p);

    while(!s.empty()){

        p=s.top();   s.pop();

        result.push_back(p->val);

        if(p->right!=NULL) s.push(p->right);

        if(p->left!=NULL) s.push(p->left);

    }

    return result;

}

2->树的中序遍历

vector<int>  inorderTraversal(TreeNode *root){

    vector<int>  result;

    const TreeNode *p=root;

   stack<const TreeNode *> s;

    while(!s.empty() || p!=NULL){

         if(p!=NULL){

             s.push(p); p=p->left;

         }else{

            p=s.top(); s.pop();

            result.push_back(p->val);

            p=p->right;

        }

    }

    return result;

}

3->树的后续遍历

vector<int> postorderTraversal(TreeNode *root){

    vector<int> result;

    const TreeNode *p,*q;    //p指向正在访问的节点,q指向刚刚访问过的节点

    stack<const TreeNode *> s;

    p=root;

    do{

        while(p!=NULL){

               s.push(p); p=p->left;

        }

        q=NULL;

         while(!s.empty()){

                p=s.top(); s.pop();

                if(p->right==q){             //右孩子不存在或者已经访问过了,则访问当前结点

                        result.push_back(p->val);  q=p;              //保存刚刚访问过的结点

                }else{

                      /*当前结点不能访问,需要二次进栈*/

                      s.push(p);   p=p->right;  break;

                }

         }

    }while(!s.empty());

    return result;

}

4->树的层次遍历。例如:BinaryTree{3,9.20,#,#,15,7} 返回的层次遍历【【3】,【9,20】,【15,7】】

vector<vector<int> >levelOrder(TreeNode *root){

    vector<vector<int> > result;

    if(root==NULL)  return result;

    queue<TreeNode *>cur,next;

    vector<int> level;

    cur.push(root);

    while(!cur.empty()){

         while(!cur.empty()){

               TreeNode* node=cur.front();  cur.pop();

                level.push(node->val);

               if(node->left!=NULL)  next.push(node->left);

               if(node->right!=NULL)  next.push(node->right);

         }

          result.push_back(level);

          level.clear();

          swap(next,cur);

    }

    return result;

}

5->树的层次遍历二:例如:BinaryTree{3,9,20,#,#,15,7} 返回层次遍历【【15,7】,【9,20】,【3】】

解题方法:与上一题类似,将最终的结果反转一下。

6->树的Zigzag层次遍历:例如BinaryTree{3,9,20,#,#,15,7}返回层次遍历【【3】,【20,9】,【15,7】】

解题方法:广度优先遍历,用一个bool记录是从左到右还是从右到左,每一层结束就翻转一下

vector<vector<int> >zigzagLevelOrder(TreeNode *root){

    vector<vector<int> > result;

    if(root==NULL)  return result;

    queue<TreeNode *>q;

    bool  left_to_right=true;

    vector<int> level;

    q.push(root);  q.push(NULL);     //层之间的间隔标记

    while(!q.empty()){

         TreeNode* cur=q.front();

          q.pop();

           if(cur){

                level.push_back(cur-val);

                if(cur->left)  q.push(cur->left);

                if(cur->right)  q.push(cur->right);

           }else{

                if(left_to_right)  result.push_back(level);

                else{ reverse(level.begin(),level.end());  result.push_back(level); }

                level.clear();  left_to_right=!left_to_right;

                if(q.size()>0)  q.push(NULL);

           }

    }

    return result;

}

7->二叉搜索树,有两个结点的位置有错误,修正该二叉搜索树

解题方法:开辟一个指针数组,中序遍历,将指针依次存放在数组里,找出两个逆向的位置,交换它

void inOrderTraverse(TreeNode *root,TreeNode *&p1,TreeNode *&p2,TreeNode *&pre){

    if(root==NULL)   return ;

    if(root->left!=NULL)  inOrderTraverse(root->left,p1,p2,pre);

    if(pre!=NULL && root->val<pre->val){

           if(p1==NULL){p1=pre;  p2=root;}

           else p2=root;

    }

    pre=root;

   if(root->right!=NULL)  inOrderTraverse(root->right,p1,p2,pre);

}

void recoverTree(TreeNode *root){

    TreeNode*p1=NULL,*p2=NULL,*pre=NULL;

    inOrderTreaverse(root,p1,p2,pre);

    swap(p1->val,p2->val;);

}

8->判断两个二叉树的结构是否相同

bool isSameTree(TreeNode *p,TreeNode *q){

    if(p==NULL && q==NULL) return true;

    if(p==NULL || q==NULL)  return false;

    return p->val==q->val && isSameTree(p->left,q->left)  && isSameTree(p->right,q->right);

}

非递归解法:

bool isSameTree(TreeNode *p,TreeNode *q){

    stack<TreeNode *>s;

    s.push(p);  s.push(q);

    while(!s.empty()){

        p=s.top(); s.pop();

        q=s.top(); s.pop();

         if(p==NULL &&q==NULL) continue;

         if(p==NULL || q==NULL)  return false;

         if(p->val !=q->val) return false;

         s.push(p->left); s.push(q->left);

         s.push(p->right); s.push(q->right);

    }

    return true;

}

9->判断一棵树是否对称

非递归版:

bool isSymmetric(TreeNode * root){

    if(!root)  return true;

    stack<TreeNode *> s;

    s.push(root->left); s.push(rot->right);

    while(!s.empty()){

        TreeNode *p=s.top();  s.pop();

        TreeNode *q=s.top();  s.pop();

        if(p==NULL && q==NULL)  continue;

        if(p==NULL || q==NULL)  return false;

        if(p->val!=q->val) return false;

        s.push(p->left); s.push(q->right);

        s.push(p->right); s.push(q->left);

    }

    return true;

}

递归版本:

bool isSymmetric(TreeNode *root){

    return root?isSymmetric(root->left,root->right);

}

bool isSymmetric(TreeNode *left,TreeNode *right){

    if(!left && !right)  return true;

    if(!left || !right)  return false;

    return left->val==right->val && isSymmetric(left->left,right->right) && isSymmetric(left->right,right->left);

}


10->判断一棵二叉树是否是平衡二叉树

解题方法:平衡二叉树的概念,左右子树的高度差绝对值不超过1,左右子树也是一棵平衡二叉树

bool isBalanced(TreeNode *root){

    return balancedHeight(root)>=0;

}

int balancedHeight(TreeNode *root){                //求树的高度,如果是平衡二叉树返回当前高度,否则的话返回-1

    if(root==NULL)   return 0;

    int left=balanceHeight(root->left);

    int right=balanceHeight(root->right);

    if(left<0 || right<0 || abs(left-right)>1)  return -1;   //不符合平衡二叉树的条件,剪枝

    return  max(left,right)+1;

}


11->将一个二叉树按照先序遍历转化成链表,要求原地转化

void  flatten(TreeNode *root){

    if(root==NULL)  return;

    flatten(root->left);   flatten(root->right);

    if(root->left==NULL) return;

    TreeNode *p=root->left;  

    while(p->right) p=p->right;

    p->right=root->right;

    root->right=root->left;

    root->left=NULL;


12->为任意叉树的每个节点添加一个指向其右兄弟的指针

解题方法:很自然的就想到用广度搜索的办法,但是广度搜索的空间复杂度非常数,而这一题要求的是原地转化

void connect(TreeLinkNode *root){

    if(root==NULL)  return ;

    TreeLinkNode dummy(-1);     //辅助头节点

    for(TreeLinkNode *cur=root,*prev=&dummy;cur;cur=cur->next){

        if(cur->left!=NULL){

               prev->next=cur->left;  prev=prev->next;

        }

        if(cur->right!=NULL){

              prev->next=cur->right;prev=prev->next;

        }

    }

    connect(dummy.next);

}


***************二叉树的建立*****************

1->根据二叉树的前序遍历和中序遍历构建二叉树

解题方法:递归的方法,前序遍历的第一个节点为根节点,中遍历根据根节点将树分为左右两边,递归建树,即可完成目标。

TreeNode * buildTree(vector<int>& preorder,vector<int>& inorder){

    return buildTree(preorder.begin(),preorder.end(),inorder.begin(),inorder.end());

}

TreeNode *bulidTree(vector<int>::iterator pre_first,vector<int>::iterator pre_last,vector<int>::iterator in_first,vector<int>::iterator in_last){

    if(pre_first==pre_last)  return NULL;

    if(in_first==in_last) return NULL;

    TreeNode *root=new TreeNode(*pre_first);

    vector<int>::iterator inRootPos=find(in_first,in_last,*pre_first);

    int leftSize=distance(in_first,inRootPos);

    root->left=buildTree(next(pre_first),next(pre_first,leftSize+1),in_first,next(in_first,leftSize));

    root->right=buildTree(next(pre_first,leftSize+1),pre_last,next(inRootPos),in_last);

    return root;

}


2->根据中序遍历和后序遍历建立二叉树

TreeNode * buildTree(vector<int>& inorder,vector<int>& postorder){

    return buildTree(inorder.begin(),inorder.end(),postorder.begin(),postorder.end());

}

TreeNode* buildTree(vector<int>::iterator in_first,vector<int>::iterator in_last,vector<int>::iterator post_first,vector<int>::iterator post_last){

    if(in_first==in_last)  return NULL;

    if(post_first==post_last)  return NULL;

    int val=*prev(post_last);

    TreeNode* root=new TreeNode(val);

    vector<int>::iterator in_root_pos=find(in_first,in_last,val);

    int leftSize=distance(in_first,in_root_pos);

    auto post_left_last=next(post_first,leftSize);

    root->left=buildTree(in_first,int_root_pos,post_first,post_left_last);

    root->right=buildTree(next(in_root_post),in_last,post_left_last,prev(post_last));

    return root;

}

************二叉查找树***********

1->1到n个节点可以确定多少种不同的BST

解题方法:属于Catalan数的范畴。对于n个节点有递推公式:f(n)=f(0)*f(n-1)+f(1)*f(n-2)+.....+f(n-2)f(1)+f(n-1)*f(0),其中f(0)f(n-1)表示左子树0个节点,右子树n-1个节点的情况

int numTrees(int n){

    vector<int> f(n+1,0);

    f[0]=1;f[1]=1;

    for(int i=2;i<=n;i++)

         for(int k=1;k<=i;k++)  f[i]+=f[k-1]*f[i-k];

    return f[n];

}


2->和上一题不同,这一题要求,求出有n个节点的不同二叉搜索树

解题方法:一般采用递归的方法解决

vector <TreeNode *> generate(int start,int end){

    vector<TreeNode *> subTree;

    if(start>end){ subTree.push_back(NULL);  return subTree; }

    for(int k=start;k<=end;k++){

           vector<TreeNode *> leftSubs=generate(start,k-1);

           vector<TreeNode *> rightSubs=generate(k+1,end);

           for(each i in leftSubs)

                  for(each j in rightSubs){

                          TreeNode *node=new TreeNode(k);

                           node->left=i;  node ->right=j;

                           subTree.push_back(node);

                  }

    }

    return subTree;

}


3->判断一棵树是否是二叉搜索树

bool isValidBST(TreeNode* root){

    return isValidBST(root,INT_MIN,INT_MAX);

}

bool isValidBST(TreeNode* root,int lower,int upper){

    if(root==NULL)  return true;

    return root->val>lower &&root->val<upper  && isValidBST(root->left,lower,root->val)  &&isValidBST(root->right,root->val,upper);


4->将一个已经排序的数组转化为二叉搜索树

解题方法:采用二分法

TreeNode *sortedArrayToBST(int low,int high){

    if(low>=high) return;

    int mid=(low+high)/2;

    TreeNode *root=new TreeNode(*mid);

    root->left=sortedArrayToBST(low,mid);

    root->right=sortedArrayToBST(mid+1,high);

    return root;

}


5->将一个已经排序的链表转化为二叉搜索树

解题方法:采用二分法,只是链表不支持随机存储。要自己实现中间位置的查找


*************二叉树的递归*******************

1->树的最小深度

递归版本:

int minDepth(const TreeNode *root){

    return minDepth(root,false);

}

int minDepth(const TreeNode *root,bool  hasbrother){

    if(!root) return hasbrother?INT_MAX:0;

    return 1+min(minDepth(root->left,root->right!=NULL),minDepth(root->right,root->left!=NULL));

}

迭代版本:

int minDepth(TreeNode *root){

    if(root==NULL)  return 0;

    int result=INT_MAX;

    stack<pair<TreeNode *,int> >s;

    s.push(make_pair(root,1));

    while(!s.empty()){

        TreeNode * node=s.top()->first;

        int depth=s.top()->second;    s.pop();

        if(node->left==NULL && node->right==NULL)  result=min(result,depth);

        if(node->left  && result>depth)  s.push_back(make_pair(node->left,depth+1));

        if(node->right && result>depth)   s.push_back(make_pair(node->right,depth+1));      

    }

    return result;

}


2->二叉树的最大深度

递归的方法:

int  maxDepth(TreeNode *root){

    if(root==NULL)   return 0;

    return max(maxDepth(root->left),maxDepth(root->right))+1;

}


3->判断二叉树的根到节点是否存在和为某一值的路径,要求返回true或者false。

解题方法:采用朴素的深度搜索方法

bool hasPathSum(TreeNode* root,int sum){

    if(root==NULL)  return false;

    if(root->left==NULL && root->right==NULL)   //到达叶子结点

        return sum==root->val;

    return hasPathSum(root->left,sum-root->val) || hasPathSum(root->left,sum-root->val);

}


4->题目要求与上一题相同,不同点是要求求出所有可能的结果。

解题方法:DFS方法

vector <vector<int> > pathSum(TreeNode *root,int sum){

    vector< vector<int> >result;

    vector<int> cur;

   pathSum(root,sum,cur,result);

    return result;

}

void  pathSum(TreeNode* root,int gap,vector<int>&cur,vector<vector<int> >&result){

    if(root==NULL) return;

    cur.push_back(root->val);

    if(root->left==NULL && root->right==NULL)  {  if(grap==root->val)  result.push_back(cur);}

    pathSum(root->left,grap-root->val,cur,result);

    pathSum(root->right,grap-root->val,cur,result);

    cur.pop_back();

}


5->找出二叉树中和最大的路径,起点可以为任何结点,终点也可以试任何结点

int maxPathSum(TreeNode *root){

    max_sum=INT_MIN;  helper(root);  return max_sum;          //其中max_sum为全局变量

}

int helper(TreeNode *root){

    if(root==NULL)  return 0;

    int l=helper(root->left);

    int r=helper(root->right);

    int sum=root->val;

    if(l>0)  sum+=l;   if(r>0) sum+=r;

    max_sum=max(max_sum,sum);

    return  max(r,l)>0 ?max(l,r)+root->val:root->val;

}


6->将二叉树总的每层结点链接起来(在二叉树的遍历中有一题类似的,不过是在多叉树上进行这一个操作)

void connect(TreeLinkNode *root){

    connect(root,NULL);

}

void connect(TreeLinkNode *root,TreeLinkNode* sibling){

    if(root==NULL)  return ;

    else root->next=sibling;

    connect(root->left,root->right);

    if(sibling!=NULL)

        connect(root->right,sibling->left);

    else

        connect(root->right,NULL);

}


7->sum Root to leaf Numbers(一个二叉树的结点值为0到9的数值,将root到叶子结点的路径上的结点值,组合成一个数值,求出这些数值的和)

int sumNumbers(TreeNode *root){

    return helper(root,0);

}

int helper(TreeNode *root,int sum){

    if(root==NULL) return 0;

    if(root->left==NULL && root->right==NULL)  return sum*10+root->val;

    return helper(root->left,sum*10+root->val)+helper(root->right,sum*10+root->val);

}

发布了99 篇原创文章 · 获赞 8 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/CodeAsWind/article/details/39160381
今日推荐