堆排序

作者: MoneyRobber | 来源:发表于2019-01-24 12:22 被阅读0次

堆排序过程图示

大根堆

除了根节点以外的所有节点都要满足
A[parent(i)] >= A[i]
二叉堆是一个数组,可以被看成一个近似的完全二叉树,树上的每一个节点都对应数组中一个元素,我们假设有某一个节点的下标为i,我们很容易计算出他的父节点,左孩子,右孩子

  • parent[i]
    return (i+1)/2-1
  • left[I]
    return 2i+1
  • right[I]
    return 2i+2
创建大根堆
  • 给定一个列表array=[16,7,3,20,17,8],对其进行堆排序,首先根据该数组元素构建一个完全二叉树


  • 然后需要构造初始堆,则从最后一个非叶节点开始调整(假设有n个元素,最后一个非叶节点的下标为n/2),调整过程如下:
    第一步: 初始化大顶堆(从最后一个有子节点开始往上调整最大堆)


  • 20和16交换后导致16不满足堆的性质,因此需重新调整,调整完之后就得到了初始堆


堆顶元素R[1]与最后一个元素R[n]交换,交换后堆长度减一
重新调整堆
  • 此时3位于堆顶不满堆的性质,则需调整继续调整(从顶点开始往下调整)


  • 重复上面的步骤


堆排序时间复杂度

创建大根堆时间复杂度

从二叉树的非叶子节点开始从右向左,从下往上调整元素,那么每一层的调整的时间为s = 2^{i-1} * ( k - i ),其中i表示层数,k表示总层数,k-i表示下调的深度,n表示元素个数,s表示总时间
s = 2^{k-2} x1 + 2^{k-3}x2 + 2^{k-4}x3 + ... + 2x(k-1)
对等式左右两边进行两次升幂操作,得出
s = n - 1 - \log_2{n}
由于logn是n的低阶
所有创建大根堆的时间复杂度为O(n)

重新调整堆的时间复杂度

创建大根堆/调整堆时间都会排好一个数,所以每次参与调整的元素个数都会减1,n表示元素个数,s表示总时间
s = \log_2{n} + \log_2{n-1} + \log_2{n-2} + ... + log1
s = \log_2{n!}
因为 {n/2}^{n/2} <= n! <= {n}^{n}
推导 n/4\log_2{n} <= log(n!) <= n\log_2{n}
所以时间复杂度为O(n\log_2{n})
总时间复杂度为n\log_2{n} + n去掉常数,总时间复杂度为O(n\log_2{n})

Talk is cheap,show me the code

void swap(int* a, int* b) {
    int temp = *b;
    *b = *a;
    *a = temp;
}

//堆调整
void adjustHeap (int arr[],int start,int len) {
    while (1) {
        int leftSon  =start*2 +1;
        int rightson = start*2+2;
        
        if (leftSon > len - 1) {
            return;
        }
        int maxSonIndex = leftSon;
        if (rightson <= len -1 && arr[rightson] > arr[leftSon]) {
            maxSonIndex = rightson;
        }
        if (arr[start] < arr[maxSonIndex]) {
            swap(&arr[start], &arr[maxSonIndex]);
        } else {
            break;
        }
        start = maxSonIndex;
    }
}

//创建大根堆
void maxHeapSort (int arr[],int len) {
    int parent = len/2 - 1;
    while (parent >= 0) {
        int leftSon  =parent*2 +1;
        int rightson = parent*2+2;
        int maxSonIndex = leftSon;
        if (rightson <= len -1 && arr[rightson] > arr[leftSon]) {
            maxSonIndex = rightson;
        }
        if (arr[parent] < arr[maxSonIndex]) {
            swap(&arr[parent], &arr[maxSonIndex]);
            adjustHeap(arr, maxSonIndex,len);
        }
        parent --;
    }
}

//堆排序
void heapSort (int arr[],int len) {
    maxHeapSort (arr,len);
    for (int i = len -1; i>0; i--) {
        swap(&arr[0], &arr[i]);
        adjustHeap(arr, 0, i-1);
    }
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6};
        int len = (int) sizeof(arr) / sizeof(*arr);
        heapSort(arr,len);
        for (int i = 0; i < len; i++)
            printf("%d ", arr[i]);
    }
    return 0;
}

console

0 0 0 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7 8 8 8 9 9 9 Program ended with exit code: 0

相关文章

  • 堆排序

    目录 1.堆排序介绍 2.堆排序图文说明 3.堆排序的时间复杂度和稳定性 4.堆排序实现 堆排序介绍 堆排序(He...

  • 堆排序---基础篇

    本文主要介绍堆排序的一些基本过程和分析。 大纲 堆排序简介 堆排序代码实现 1. 堆排序简介 1.1 堆排序的存储...

  • 堆和堆排序

    最小K个数 堆排序 堆排序

  • JS实现堆排序

    原理 堆排序原理 实现 说明 堆排序对大文件很有效 堆排序是不稳定排序

  • iOS算法总结-堆排序

    iOS算法总结-堆排序 iOS算法总结-堆排序

  • 堆排序

    转载:图解排序算法(三)之堆排序 预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选...

  • 排序

    原创 堆排序: 使用visit数组从本质出发获取大顶堆排序。

  • 堆排序

    堆排序

  • C++基础入门之模板堆排序(上):模板上的list的创造与操作

    整段源码链接C++的模板元堆排序 要点 组建数据结构list 组建对list的各种基本操作 堆排序中组建堆排序个个...

  • 3.2-选择排序-堆排序

    参考链接 选择排序:堆排序(Heap Sort) 白话经典算法系列之七 堆与堆排序 堆排序与快速排序,归并排序一样...

网友评论

      本文标题:堆排序

      本文链接:https://www.haomeiwen.com/subject/plrhjqtx.html