• 算法 有序列表和平衡二叉树 有序阵列与平衡二叉树


    标题叙述性说明:

    Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.


    给定一个有序的链表。要求构建一颗平衡二叉查找树。


    解析:二叉查找树的中序遍历的结构就是一颗二叉查找树,要使得终于的二叉查找树的结构尽可能的平衡。也就是说仅仅须要将左右两边的节点数尽可能的均匀,(注意,此处的均匀是一个递归的概念,也就是说每个节点的左右子树的节点个数都应该尽量均匀)。我们首先想到了二分。


    于是以下的代码应运而生:


        TreeNode *sortedListToBST(ListNode *head) 
        {
            if(head == nullptr) return (TreeNode *)nullptr;
            ListNode *fast=head->next;
            ListNode *slow=head , *prev= nullptr;
            while(fast && fast->next)
            {
                prev=slow;
                fast=fast->next->next;
                slow=slow->next;
            }
            //have left tree or not
            if(prev)prev->next=nullptr; //此处直接将next赋值为空,那么链表的结构便被改变了。
            else head=nullptr;
            TreeNode *node = new TreeNode(slow->val);
            fast=slow->next;
            slow->next=nullptr;
            TreeNode *L = sortedListToBST(head);
            TreeNode *R = sortedListToBST(fast);
            node->left=L;
            node->right=R;
            return node;
        }

    上述代码尽管能够完毕我们须要的平衡二叉查找树,可是上述代码却有一个致命的缺点:那就是内存泄露,

    上述代码在运行过程中将原始的链表的节点弄得面目全非,那么也就是说假设那么节点都是通过new操作符得来的话,那么在运行完这个函数之后。有大部分节点的指针已经无法訪问到,导致内存泄露。


    于是,我们不能使用拆分链表的形式来构建平衡二叉查找树。我们不能改变链表的结构,那么怎么办呢。我们须要做的就是记录当前链表的头结点和长度就可以。实现例如以下:


    class Solution {
        //之前的代码尽管AC了。可是会改变list的结构,这样必导致内存泄露,于是前面的代码所有都是错误的。
    private:
        int Len(ListNode *head)
        {
            int ret=0;
            while(head)
            {
                ++ret;
                head=head->next;
            }
            return ret;
        }
        TreeNode *helper(ListNode *head, int len)
        {
            if(head == nullptr || len <= 0 ) return nullptr;
            ListNode *cur=head;
            int mid=(len+1)/2-1;
            int tmp=mid;
            while(tmp)
            {
                cur=cur->next;
                --tmp;
            }
            TreeNode *root = new TreeNode(cur->val);
            root->left = helper(head,mid);
            root->right = helper(cur->next,len-mid-1);
            return root;
        }
    public:
        TreeNode *sortedListToBST(ListNode *head) {
            const int n = Len(head);
            TreeNode *root=helper(head,n);
            return root;
        }
    };

    于是上述代码中的内存泄露的问题便消除了。由于在整个过程中我们都没有改变链表的不论什么节点的指向。


    这里,最最值得一提的便是链表的销毁。

    在销毁链表时,要么使用返回值,要么传入的參数是链表的引用,或者是指针的指针,否则也会有内存的隐患:


    也就是说删除链表的代码为:

    void destory(ListNode * &head)
    {
        ListNode *tmp=nullptr;
        while(head)
        {
            tmp=head->next;
            delete head;
            head = nullptr ; //删除指针的额安全的方式。便是delete之后将该指针赋值为空
            head=tmp;
        }
        head = nullptr; //当然。头结点也不例外,假设传入的參数不是指针的指针或者是引用的话,那么head尽管delete掉了,可是该指针在下一次被赋值之前依旧指向内存的某一块区域。

    }



    [updated]类似的。使用同样的模板实现了有序数组到二叉查找树的转换,代码例如以下:

    在下述代码中使用的是迭代器来取代指针,跟上面是全然一样的代码模板。


        typedef vector<int>::const_iterator iter;
        TreeNode *helper(iter beg, const int n)
        {
            if( n <= 0 ) return nullptr;
            int mid = (n+1)/2-1;
            TreeNode *root =  new TreeNode(*(beg+mid));
            root->left = helper(beg,mid);
            root->right = helper(beg+mid+1, n-mid-1);
            return root;
        }
    public:
        TreeNode *sortedArrayToBST(vector<int> &num) {
            const int n = num.size();
            TreeNode *root = helper(num.begin(),n);
            return root;
        }




    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    Working with the RadioButton and CheclBox controls
    Simple Data Binding in Silverlight 4.0
    Data Binding in Silverlight 4.0
    Building a Simple DataGrid in Silverlight 4.0
    EXCEL数据导入SQL Server数据库中
    正则表达式必知必会
    Eclipse插件一次copy多个文件的相对路径路径
    走出软件作坊
    写在前面的话
    [转载]有经验的Java开发者和架构师容易犯的10个错误
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4744167.html
Copyright © 2020-2023  润新知