考研数据结构笔记—堆排序

Posted evenleo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了考研数据结构笔记—堆排序相关的知识,希望对你有一定的参考价值。

完全二叉树是效率很高的数据结构,堆是一种完全二叉树或者近似完全二叉树,所以效率同样极高。目前十分常用的排序算法、Dijkstra算法、Prim算法等都要用堆才能优化。

堆排序是一种选择排序算法,与原序列的初始排列次序无关,即最好、最坏和一般情况排序的时间复杂度不变,均为O(nlgn)。而且,堆排序只需要一个记录记录元素大小的辅助空间(供交换使用),故空间复杂度为O(1)。正由于堆排序不仅时间复杂度小,而且空间复杂度O(1)也是最小,所以是用于排序的最佳选择。

堆的定义

n个元素序列 { k0,k1,..., k} 当且仅当满足下列条件之一时,称之为堆(其中 i = 0, 1, ..., n/2 向下取整)。

  • ki <= k2i+1 且 k<= k2i+2(最小堆)
  • ki >= k2i+1 且 ki >= k2i+2(最大堆)

堆排序实现

方法1:

利用最小堆性质实现堆排序

/*交换数组中两个元素的值*/
void swap(int *arr, int a, int b)
{
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}

/*(小根)堆调整*/
void minHeapify(int *arr, int heapSize, int curNode)
{
    /*找出当前节点和其左右节点三者的最小值*/
    int minNode = curNode;  
    int left  = curNode * 2 + 1;
    int right = curNode * 2 + 2;
    if(left < heapSize && arr[left] < arr[minNode]) //左孩子存在且较小
        minNode = left;
    if(right < heapSize && arr[right] < arr[minNode]) //右孩子存在且较小
        minNode = right;

    if(minNode != curNode)    //当前节点不是最小则需要交换
    {   
        swap(arr, minNode, curNode);
        minHeapify(arr, heapSize, minNode);  //子节点需重新调整
    }
}

/*构建堆*/
void createHeap(int *arr, int heapSize)
{
    for(int i = heapSize/2 - 1; i >= 0; i--)  //从最后一个非叶节点开始
    {
        minHeapify(arr, heapSize, i);
    }
}

/*(最小)堆排序
*思想:
*1、构建最小堆
*2、从最后一个元素开始只第二个元素将依次与首元素交换
*3、全局调整堆
*上面步骤2和步骤3将所有元素都与首元素交换,然后进行全局范围的堆调整,利用最小堆的性质实现将所有元素按从小到大的方式排序
*/ void heapSort(int *arr, int length) { createHeap(arr, length); //构建堆 for(int i = length-1; i > 0; i--) { swap(arr, 0, i); //与首元素交换 minHeapify(arr, length, 0); //调整堆 } }

 方法2

利用最大堆性质实现堆排序

/*交换数组中两个元素的值*/
void swap(int *arr, int a, int b)
{
    int temp = arr[a];
    arr[a] = arr[b];
    arr[b] = temp;
}

/*(大根)堆调整*/
void maxHeapify(int *arr, int heapSize, int curNode)
{
    /*找出当前节点和其左右节点三者的最小值*/
    int maxNode = curNode;  
    int left  = curNode * 2 + 1;
    int right = curNode * 2 + 2;
    if(left < heapSize && arr[left] > arr[maxNode]) //左孩子存在且较小
        maxNode = left;
    if(right < heapSize && arr[right] > arr[maxNode]) //右孩子存在且较小
        maxNode = right;

    if(maxNode != curNode)    //当前节点不是最小则需要交换
    {   
        swap(arr, maxNode, curNode);
        maxHeapify(arr, heapSize, maxNode);  //子节点需重新调整
    }
}

/*构建堆*/
void createHeap(int *arr, int heapSize)
{
    for(int i = heapSize/2 - 1; i >= 0; i--)  //从最后一个非叶节点开始
    {
        maxHeapify(arr, heapSize, i);
    }
}

/*(最大)堆排序
*思想:
*1、构建最大堆
*2、从最后一个元素开始只第二个元素将依次与首元素交换
*3、进行数组中当前元素前面的所有元素的局部调整堆
*上面步骤2和步骤3将所有元素都与首元素交换,将局部范围内的最大值沉到后面,然后进行当前元素前面所有元素的局部范围内的堆调整
*即在数组A中,当前元素索引为i,将A[i]与A[0]交换,将A[0,1,...,i]中最大的值放到A[i],然后进行A[0,1,...,i-1]堆调整,
*将A[0,1,...,i-1]内的最大值放到A[0]中,待下一次交换使用,实现将局部的最大值依次沉到数组后面,完成排序
*/
void heapSort(int *arr, int length)
{
    createHeap(arr, length);  //构建堆
    for(int i = length-1; i > 0; i--)
    {   
        swap(arr, 0, i);  //与首元素交换
        maxHeapify(arr, i, 0);  //调整堆
    }
}

 

以上是关于考研数据结构笔记—堆排序的主要内容,如果未能解决你的问题,请参考以下文章

2023数据结构考研复习-排序

2022计算机考研408—数据结构—排序

数据结构 | 考研八大内部排序算法

计算机考研之数据结构重点知识19

Java排序算法 - 堆排序的代码

数据结构学习笔记——选择排序(简单选择排序和堆排序)