zoukankan      html  css  js  c++  java
  • 堆与堆排序/Heap&Heap sort

    最近在自学算法导论,看到堆排序这一章,来做一下笔记。
    堆排序是一种时间复杂度为O(lgn)的原址排序算法。它使用了一种叫做堆的数据结构。
    堆排序具有空间原址性,即指任何时候都需要常数个额外的元素空间存储临时数据。

    堆:
    二叉堆是一个数组,它可以被看成一个近似的完全二叉树。
    除了最底层以外,该树是满的;且最底层是从左向右填充。
    堆又可以分为大根堆和小根堆。
    大根堆:爸爸元素值>=儿子元素值
    小根堆:爸爸元素值<=儿子元素值
    可以把堆看成是一棵树,把堆的高度定义为根结点的高度。

    建立一个堆包含建立堆(build_max_heap)和维护堆(max_heapify)两个操作。

    维护堆(max_heapify):
    由于大根堆具有根节点元素大于或等于孩子元素的特点。在输出堆顶或者堆排序的过程中,可能存在着大根堆“大根”性质被破坏的情况。这是就需要使用维护堆对大根堆进行“大根”性质的维护。
    调用此函数传入一个数组arr与要调节位置的元素i 要求元素i的左右孩子都是大根堆
    此时就可以用max_heapify通过让数组arr[i]的值在大根堆中逐步下降,使得下标为i的根结点所在的子树重新遵循大根堆的性质。
    算法思想:
    在(max_heapify)算法执行的过程中,每次从arr[i]、arr[left]、和arr[right]中选择一个最大的元素,将下标保存在largest中。并将arr[largest]与arr[i]的元素值进行交换。
    若当前arr[i]为最大的元素,则程序结束。(由调用(max_heapify)的前提可以知道除了当前结点i以外,其左右子树必然符合大根堆的性质。)否则则递归调用(max_heapify(arr,largest,heap_size)继续对堆进行调整。
    算法如下:

    void max_heapify(int arr[],int i,int heap_size)//i为当前元素节点
    {
        int largest;
        int left=2*i;
        int right=2*i+1;
        if(left<=heap_size&&arr[left]>arr[i]) largest=left;
        else largest=i;
        if(right<=heap_size&&arr[right]>arr[largest])
            largest=right;
        if(largest!=i)
        {
            swap(arr[largest],arr[i]);
            max_heapify(arr,largest,heap_size);
        }
    }

    建立堆(build_max_heap):
    在一个数组上建立堆可以自底向上地利用(max_heapify)来逐步调整数组,使其最后建成大根堆。
    这里值得一提的是为什么要从n/2到1这样的顺序进行建堆。
    从堆的性质我们可以知道,下标(n/2...n)的元素必然是叶子元素,而单个叶子元素也符合大根堆的性质。调用(max_heapify)的前提是当前i元素的子树得全是大根堆。所以建堆只能从下往上建。

    void build_max_heap(int arr[],int length)
    {
        int heap_size=length;
        for(int i=length/2; i>=1; i--)
        {
            max_heapify(arr,i,heap_size);
        }
    }

    堆排序(heapsort):
    堆排序是在堆的基础上进行的。
    将大根堆进行排序,使数组升序排列的堆排序算法思想如下:
    首先把根顶arr[1]与最后一个元素arr[n]进行交换,这样最大的元素便换到了最底
    交换后heap_size减1
    对余下的部分,由于交换了元素大根堆的性质遭到破坏。这时调用(max_heapify(arr,1,heap_size))对堆进行调整,使得最大的元素在最上
    然后又交换根顶和最后一个元素(此时已是arr[1]与arr[n-1]),
    heap_size减1,重复调用(max_heapify)来调整堆的性质……
    就这样对下标为第n-1到2的元素进行调整。
    最后即可将数组使数组呈升序排列。
    具体算法如下:

    void heapsort(int arr[],int length)
    {
        int heap_size=length;
        build_max_heap(arr,length);
        for(int i=length; i>=2; i--)
        {
            swap(arr[1],arr[i]);
            heap_size--;
            max_heapify(arr,1,heap_size);
        }
    }

    总代码如下:

    #include<cstdlib>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void max_heapify(int arr[],int i,int heap_size)//i为当前元素节点
    {
        int largest;
        int left=2*i;
        int right=2*i+1;
        if(left<=heap_size&&arr[left]>arr[i]) largest=left;
        else largest=i;
        if(right<=heap_size&&arr[right]>arr[largest])
            largest=right;
        if(largest!=i)
        {
            swap(arr[largest],arr[i]);
            max_heapify(arr,largest,heap_size);
        }
    }
    void build_max_heap(int arr[],int length)
    {
        int heap_size=length;
        for(int i=length/2; i>=1; i--)
        {
            max_heapify(arr,i,heap_size);
        }
    }
    void heapsort(int arr[],int length)
    {
        int heap_size=length;
        build_max_heap(arr,length);
        for(int i=length; i>=2; i--)
        {
            swap(arr[1],arr[i]);
            heap_size--;
            max_heapify(arr,1,heap_size);
        }
    }
    int main()
    {
        int arr[]= {0,13,10,4,7,3,6,4,1,35,47};
        int len=10;
        heapsort(arr,len);
        cout<<"heapsort:
    ";
        for(int i=1; i<=len; i++)
        {
            cout<<arr[i]<<' ';
        }
        cout<<endl;
        return 0;
    }
  • 相关阅读:
    三维重建:SLAM算法的考题总结
    ubuntu16.04安装KDE
    pip更新
    DNN结构演进History—CNN-GoogLeNet :Going Deeper with Convolutions
    OpenCV直方图均衡化
    图像连通域检测的2路算法Code
    OpenCV中的模板匹配/Filter2d
    OpenCV边缘检测的详细参数调节
    ICCV2015上的GazeTracker论文总结
    图像的连通域检测的堆栈算法
  • 原文地址:https://www.cnblogs.com/AKsnoopy/p/8551370.html
Copyright © 2011-2022 走看看