zoukankan      html  css  js  c++  java
  • 25 二叉搜索树与双向链表

    题目描述

    输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
     
    思路:分为循环版本和递归版本。
    循环版本:
    二叉搜索树的中序遍历就是递增序列,所以本题本质就是中序遍历。有两点非常需要注意:
    1)开始自己认为需要对链表的首尾节点进行特殊处理,比如开始节点需要left指向nullptr,但是画个图就会非常明显,中序遍历是左中右的顺序,所以头节点是遍历到最左边的叶子节点才开始处理,此时头结点left和right指针都指向nullptr,同理尾节点也是一样的,所以不需要进行特殊处理,需要注意的时候因为最后需要返回一个头节点,所以需要一个bool变量记录第一次遍历得到的头结点保存起来,后面进行return。
    2)开始自己想的是将中序遍历的结果使用一个数组保存下来,但是不需要这么做,只需要遍历的过程中,进行交换即可,一个传入的root变量,一个pre节点,
     
    root -> left = pre;
    pre -> right = root;
    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };*/
    class Solution {
    public:
        TreeNode* Convert(TreeNode* pRootOfTree){
            if(pRootOfTree == nullptr){
                return nullptr;
            }
            //inorder
            stack<TreeNode*> s; 
            TreeNode* pre = nullptr;
            TreeNode* root = pre;
            bool isFirst = true;
            while(!s.empty() || pRootOfTree != nullptr){
                while(pRootOfTree != nullptr){
                    s.push(pRootOfTree);
                    pRootOfTree = pRootOfTree -> left;
                                    
                }
                if(!s.empty()){
                   pRootOfTree = s.top();
                   s.pop();              
                   if(isFirst){
                       isFirst = false;
                       pre = pRootOfTree;
                       root = pre;
                        
                    }
                    else{//举例子,最左边的最右边的节点都是叶子节点,左右都是指向null,所以不需要特殊处理
                        pre -> right = pRootOfTree;
                        pRootOfTree -> left = pre;
                        pre = pRootOfTree;
                    }
                   pRootOfTree = pRootOfTree -> right;
                }
            }
             
            return root;
        }
    };

    2、递归版本

    将左子树转换为有序双向链表,然后找到左子树对应链表的最后一个节点leftLast,将leftLast和root节点连接起来,然后对右子树进行同样的处理,得到右子树对应的链表头结点是rightHead,将root和rightHead连接起来,放回结果的时候需要判断leftHead是否为空,为空的时候需要返回root。

    这里关键的理解就是helper这个递归函数每次返回的是一个链表的头结点,不管是左子树还是右子树调用返回的都是对应部分的头结点。

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };*/
    class Solution {
    public:
        TreeNode* helper(TreeNode* root){
            if(root == nullptr){
                return nullptr;
            }
            TreeNode* leftHead = helper(root -> left);
            TreeNode* leftLast = leftHead;
            if(leftLast != nullptr){
                while(leftLast != nullptr && leftLast -> right != nullptr){//find last left node 
                    leftLast = leftLast -> right;
                }
                leftLast -> right = root;
                root -> left = leftLast;
            }
            
            TreeNode* rightHead = helper(root -> right);
            if(rightHead != nullptr){
                root -> right = rightHead;
                rightHead -> left = root;
            }
            
            return (leftHead != nullptr) ? leftHead : root;
        }
        TreeNode* Convert(TreeNode* pRootOfTree){
           if(pRootOfTree == nullptr){
               return nullptr;
           } 
           return helper(pRootOfTree);
        }
    };
  • 相关阅读:
    js错误类型
    js事件流及事件冒泡
    js中BOM学习
    js匿名函数及闭包(javaScript高级程序设计第3版)
    js面向对象、原型及继承(javaScript高级程序设计第3版)
    js中变量、作用域及内存
    函数内部两个特殊的对象---arguments和this
    node+mongoose使用例子
    TypeError: HashUpdate fail
    Mac上安装tomcat服务器
  • 原文地址:https://www.cnblogs.com/dingxiaoqiang/p/8025090.html
Copyright © 2011-2022 走看看