• 二叉树系列


    引言

    本文来自于Google的一道题目:

    how to merge two binary search tree into balanced binary search tree. how to merge two binary search tree into balanced binary search tree.. Let there be m elements in first tree and n elements in the other tree. Your merge function should take O(m+n) time and do it in place.

    http://www.careercup.com/question?id=5261732222074880

    要线性时间内完成,而且要求in place,不难想到把BST转换为Double linked list。

    然后将两个dll merge。但是,存在线性时间复杂度的算法,把dll转化成BST吗?

    下面就是本文要记述的内容,算法参考自

    http://www.geeksforgeeks.org/in-place-conversion-of-sorted-dll-to-balanced-bst/

    已排序的 Double linked list 转化为 BST

    因为要求线性时间,所以必须保证DLL上的每个节点只被访问 consant 次,最好是一次。

    既然要求每个节点只能被访问一次,那么从根节点构造肯定是不行的。这种算法让BST从叶节点开始被构造,通过灵活地运用递归,巧妙地实现了自底向上构造BST的过程,而且还能保证BST是平衡的。

    #include<iostream>
    #include<stack>
    using namespace std;
    
    struct BSTNode{
        int val;
        BSTNode *left;
        BSTNode *right;
        BSTNode(int v): val(v), left(NULL), right(NULL){}
    };
    
    class BSTtoDLL{
        public:
            BSTNode *func(BSTNode *root){
                BSTtoDLLCore(root);
                return head;
            }
    
        private:
            BSTNode* pre = NULL;
            BSTNode* head = NULL;
            void BSTtoDLLCore(BSTNode *root){
                if(!root) return;
                BSTtoDLLCore(root -> left);
                if(pre){
                    pre -> right = root;
                    root -> left = pre;
                }else{
                    head = root;
                }
                pre = root;
                BSTtoDLLCore(root -> right);
            }
    };
    
    class DLLtoBalancedBST{
        public:
            BSTNode* func(BSTNode* head){
                if(!head) return head;
                int n = 0;
                for(BSTNode *p = head; p; ++n, p = p -> right);
                return DLLtoBalancedBSTCore(&head, n);
            }
        private:
            //DLL to BST in place, Time O(N), Space O(LogN) for stack, N is the amount of nodes.
            //DLL needs to be sorted.
            BSTNode* DLLtoBalancedBSTCore(BSTNode** headref, int n){
                if(n == 0) return NULL;
                BSTNode* left = DLLtoBalancedBSTCore(headref, n/2);
                BSTNode *root = *headref;
                root -> left = left;
                *headref = root -> right;
                root -> right = DLLtoBalancedBSTCore(headref, n-n/2-1);
                return root;
            }
    
    };
    
    void InorderPrint(BSTNode* root){
        if(!root) return;
        stack<BSTNode *> st;
        while(!st.empty() || root){
            if(!root){
                root = st.top();
                st.pop();
                cout << root -> val << ' ';
                root = root -> right;
            }else{
                st.push(root);
                root = root -> left;
            }
        }
        cout << endl;
    }
    
    
    int main(){
        
        //Construct oringal BST
        BSTNode *root = new BSTNode(5);
        BSTNode *left3 = new BSTNode(3);
        BSTNode *left1 = new BSTNode(1);
        BSTNode *left2 = new BSTNode(2);
        BSTNode *right6 = new BSTNode(6);
        BSTNode *right7 = new BSTNode(7);
        
        root -> left = left2;
        left2 -> left = left1;
        left2 -> right = left3;
        root -> right = right7;
        right7 -> left = right6;
        
        cout << "-------Inorder print BST-------
    ";
        InorderPrint(root);
    
        //Convert BST to DLL
        BSTtoDLL bstdll;
        BSTNode *head = bstdll.func(root);
        BSTNode *p = head;
        cout << "-------print converted double linked list----------
    ";
        for(; p->right != NULL; cout << p -> val << ' ', p = p -> right);
        cout << endl;
        for(; p != NULL; cout << p -> val << ' ', p = p -> left);
        cout << endl;
    
        //Convert DLL back to Balenced BST
        DLLtoBalancedBST dllbst;
        BSTNode *con_root = dllbst.func(head);
        cout << "-------Inorder print converted BST-------
    ";
        InorderPrint(con_root);
    
        return 0;
    }

    高亮部分为转化过程。

    每次递归,headaddr这个指向节点的指针向末尾移动一次。因此每个节点只被访问一次,时间复杂度是线性的。

    我们可以发现,这种算法对单向链表也适用。当然单链表不能保证in place,必须新申明节点,但是时间复杂度依然是线性的。

    下面给出单向链表上的实现。

    已排序的单向Linked list 转化为BST

    #include<iostream>
    #include<stack>
    using namespace std;
    
    struct ListNode{
        int val;
        ListNode* next;
        ListNode(int v): val(v), next(NULL){}
    };
    
    struct BSTnode{
        int val;
        BSTnode* left;
        BSTnode* right;
        BSTnode(int v): val(v), left(NULL), right(NULL){}
    };
    
    BSTnode *LLtoBSTCore(ListNode **headaddr, int n){
        if(n <= 0) return NULL;
        BSTnode *left = LLtoBSTCore(headaddr, n/2);
        BSTnode *root = new BSTnode((*headaddr) -> val);
        root -> left = left;
        *headaddr = (*headaddr) -> next;
        root -> right = LLtoBSTCore(headaddr, n-n/2-1);
        return root;
    }
    
    BSTnode *LLtoBST(ListNode *head){
        if(!head) return NULL;
        int n = 0; ListNode *p = head;
        for(; p; ++n, p = p -> next);
        return LLtoBSTCore(&head, n);
    }
    
    int main(){
        ListNode *head = new ListNode(1);
        ListNode *end = head;
        for(int i = 2; i <= 9; end -> next = new ListNode(i++), end = end -> next);
        cout << "List: 
    ";
        for(ListNode *p = head; p; cout << p -> val << ' ', p = p -> next);
        cout << endl;
    
        BSTnode *root = LLtoBST(head);
    
        cout << "BST inorder: " << endl;
        stack<BSTnode *> st;
        while(!st.empty() || root){
            if(!root){
                root = st.top();
                st.pop();
                cout << root -> val << " ";
                root = root -> right;
            }else{
                st.push(root);
                root = root -> left;
            }
        }
        cout << endl;
        
    }

    高亮部分为转化过程。

    给一个已排序的序列的 Iterator,将序列转化为BST

    再推而广之,对于给定一个只能向 next 移动的iterator,通过这个算法也能构造将 iterator 经过的节点构造为BST。不过我们事先知道或者计算出序列的长度。

    这里给出C#的实现代码。IEnumerator 就是一个迭代器,支持MoveNext() - 将迭代器往后移,Current 属性 - 返回迭代器当前所指向的值。

    高亮部分为基于IEnumrator的构造过程。

    因为接口IEnumerator 不是.NET CLR 中的 primitive type(基元类型),因此将 IEnumerator 赋值或者作为函数参数时,都是按引用传递,这正是我们需要的。因此C#的实现代码省去了C++中使用 两个**的麻烦。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace ConsoleApplication1
    {
        public class BSTNode<T>
        {
            public T val;
            public BSTNode<T> left;
            public BSTNode<T> right;
            public BSTNode(T v)
            {
                val = v;
                left = null;
                right = null;
            }
        }
    
        /// <summary>
        /// Build Binary search tree from given iterator
        /// </summary>
        public class BuildBST
        {
            public BSTNode<T> BuildFromIEt<T>(IEnumerator<T> it, int n)
            {
                if (n == 0) return null;
                BSTNode<T> left = BuildFromIEt(it, n / 2);
                it.MoveNext();
                BSTNode<T> node = new BSTNode<T>(it.Current);
                node.left = left;
                node.right = BuildFromIEt(it, n - n / 2 - 1);
    
                return node;
            }
        }
    
        /// <summary>
        /// A class to out put nodes in a tree
        /// </summary>
        public class TreeTrav
        {
            public static void Inorde<T>(BSTNode<T> root)
            {
                if (root == null) return;
                Stack<BSTNode<T>> st = new Stack<BSTNode<T>>();
                while (root != null || st.Count > 0)
                {
                    if (root == null)
                    {
                        root = st.Peek();
                        st.Pop();
                        Console.Write(root.val.ToString() + ' ');
                        root = root.right;
                    }
                    else
                    {
                        st.Push(root);
                        root = root.left;
                    }
                }
                Console.WriteLine();
            }
        }
    
        class Program
        {
    
            static void Main(string[] args)
            {
                IEnumerable<int> list = new List<int>() { 1, 2, 3, 6, 7, 9 };
    
                Console.WriteLine("----Original list----");
                for (IEnumerator<int> it = list.GetEnumerator(); it.MoveNext(); Console.Write(it.Current.ToString() + ' ')) ;
                Console.WriteLine();
    
                BuildBST buildBST = new BuildBST();
                BSTNode<int> root = buildBST.BuildFromIEt(list.GetEnumerator(), list.Count());
                Console.WriteLine("----Inorder traverse generated BST----");
                TreeTrav.Inorde(root);
                Console.Read();
            }
        }
    }
  • 相关阅读:
    jquery判断<inpur type="checkbox" checked>是否被选择
    hibernate多对多的更新问题
    关于getHibernateTemplate().get()方法
    springmvc的@ResponseBody报错
    @RequestBody ajax 415 400
    js判断浏览器的类型,动态调整div布局
    平衡树treap 0基础详解
    P1582 倒水 题解
    vscode入门记
    P5025 [SNOI2017]炸弹 题解
  • 原文地址:https://www.cnblogs.com/felixfang/p/4241322.html
Copyright © 2020-2023  润新知