zoukankan      html  css  js  c++  java
  • 【堆】

    看上去好像很简单的样子··然后折磨了我好久····

    主要是没仔细弄明白。

    堆分为最小堆和最大堆,以二叉树的形式存在,最小堆即根节点为整个树的最小值,最大堆则是根节点为最大值。

    建堆(以最大堆为例):

    首先数据以数组形式存储(int a[]或vector<int> a),若二叉树的根节点从0开始计数,则节点 i 的左右子节点的下标分别为2 * i + 1和 2 * i + 2(忘了怎么算可以画一棵树,就知道了)。

    void heap_down(int a[], int id, int numsSize)
    {
        int leftchild = id * 2 + 1;
        int rightchild = leftchild + 1;
        if(leftchild <= numsSize-1)
        {
            if(rightchild <= numsSize - 1)
                if(a[leftchild] < a[rightchild])
                    leftchild = rightchild;//根节点与左右子节点中最大的交换
            if(a[id] < a[leftchild])
            {
                swap(a[id], a[leftchild]);
                heap_down(a, leftchild, numsSize);//递归
            }
            
        }
    }

    到这里把向下建堆写好了,这个函数是每次能够建一个最大堆,我们堆排序还需要把堆顶元素与堆末尾元素交换,然后size--,再从堆顶向下建堆,循环size次完成堆排序,时间复杂度O(nlogn)。

    void heap_sort(int a[], int numsSize)
    {
        for(int i = numsSize/2;i>=0;i--)//为什么一定要从后往前heap_down
            heap_down(a,i,numsSize);
        int size = numsSize-1;//这里要保存一下数组的长度,因为必须要循环这么多次才能把所有的元素都排序一遍
        for(int j=0;j<=size;j++)
        {
            swap(a[0],a[numsSize-1]);
            numsSize--;
            heap_down(a,0,numsSize);
        }
    }

    接下来到了我之前一直犯错的地方:

    为什么一定要从往前进行heap_down操作?

    其实只要画个图就显而易见了,如果是从前往后循环的调用heap_down,首先第一次就会将堆顶元素和它的左右子节点中的较大者交换,然后················堆顶元素就再也变不了了,所有根本无法建立最大堆了!

    为什么惩罚自己如此愚蠢,花时间写了这么多字的blog,所以一定要记住这里的坑。

    另外由于heap_down操作自身会递归向下调用,所以在heap_sort中只要进行size/2次操作就可以完成最大堆的建立,虽然总体时间上并没有什么提升。

  • 相关阅读:
    卷积神经网络
    TensorFlow线性回归
    TensorFlow常用操作
    TensorFlow基本计算单元——变量
    Pandas基础
    Numpy基础
    Python基础
    Windows下安装TensorFlow教程
    mongodb并列查询,模糊查询
    C#对Mongodb数组对象操作
  • 原文地址:https://www.cnblogs.com/puyangsky/p/4899426.html
Copyright © 2011-2022 走看看