C语言数据结构之堆排序详解

 更新时间:2022年03月10日 11:21:39   作者:清欢有道  
堆是计算机科学中一类特殊的数据结构的统称,通常是一个可以被看做一棵完全二叉树的数组对象。而堆排序是利用堆这种数据结构所设计的一种排序算法。本文将通过图片详细介绍堆排序,需要的可以参考一下

1.堆的概念及结构

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树(二叉树具体概念参见——二叉树详解)的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

2.堆的实现

堆的实现请参见——二叉树详解(堆的实现)

2.1 堆的向下调整算法

(此文章都已建小堆为例)

向下调整算法前提:当前树左右子树都是小堆

核心思想:选出左右孩子中小的那个,和父亲交换,小的往上浮,大的往下沉,这里是小堆,如果是大堆则相反。

代码实现

void swap(int *x, int *y)
{
    int temp = *x;
    *x = *y;
    *y = temp;
}
//堆向下调整算法
void AdjustDown(int *a, int n, int root)
{
    int parent = root;
    int child = parent * 2 + 1;
    while (child<n)
    {
        //保证孩子节点child为两个孩子中的最小值;保证不越界
        if (a[child] > a[child + 1] && child+1 < n)
            ++child;
        if (a[child] < a[parent])
        {
            swap(&a[child], &a[parent]);
            parent = child;
            child = parent * 2 + 1;
        }
        else
            break;
    }
}

2.2 堆的向上调整算法

使用场景:向上调整算法适用于向堆中插入数据,当向堆中插入数据就可能会导致堆失去大堆或者小堆的性质,此时需要重新调整,向上调整的思路与向下调整算法的思路类似,向上调整算法只需要从插入结点位置开始和父节点比较。

图示:

代码实现:

void AdjustUp(int *a, int child)
{
    int parent = (child - 1) / 2;
    while (child > 0)
    {
        if (a[parent] > a[child])
        {
            swap(&a[parent], &a[child]);
            child = parent;
            parent = (child - 1) / 2;
        }
        else
            break;
    }
}

2.3 建堆(数组)

从最后一个非叶子节点位置行依次开始调整,如图:

代码实现:

int parent = (n-2) / 2;
    //首先对每一个非叶子节点进行一次向下调整算法,保证每个非叶子节点的
    //孩子都小于它的父节点,然后可得到最小值,就在堆的顶端的父节点(也叫做建小堆)
    while (parent >= 0)
    {
        AdjustDown(a, n, parent);
        --parent;
    }

2.4 堆排序

升序建大堆,降序建小堆

void HeapSort(int *a, int n)
{
    int parent = (n-2) / 2;
    //首先对每一个非叶子节点进行一次向下调整算法,保证每个非叶子节点的
    //孩子都小于它的父节点,然后可得到最小值,就在堆的顶端的父节点(也叫做建小堆)
    while (parent >= 0)
    {
        AdjustDown(a, n, parent);
        --parent;
    }
    int end = n-1;
    while (end>0)
    {
        //将堆顶的数与最后的end,以此循环,进行交换就可得到有序序列
        //注意:建小堆,得到降序序列
        swap(&a[end], &a[0]);
        AdjustDown(a, end, 0);
        --end;
    }
}

2.5 堆排序的时间复杂度

所以建堆时间复杂度为O(N);

向下调整算法时间复杂度 O(logN);

所以堆排序的时间复杂度为 O(N*logN)

以上就是C语言数据结构之堆排序详解的详细内容,更多关于C语言堆排序的资料请关注脚本之家其它相关文章!

相关文章

  • C++中的delete不会将操作数置0

    C++中的delete不会将操作数置0

    这篇文章主要介绍了C++中的delete不会将操作数置0的相关资料,需要的朋友可以参考下
    2016-05-05
  • OpenCV实现更改图片颜色功能

    OpenCV实现更改图片颜色功能

    这篇文章主要为大家详细介绍了如何利用OpenCV实现更改图片颜色的功能,文中代码介绍详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C语言关键字const和指针的结合使用

    C语言关键字const和指针的结合使用

    这篇文章主要介绍了C语言关键字const和指针的结合,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-02-02
  • C++ 空指针解引用的解决方法

    C++ 空指针解引用的解决方法

    空指针解引用是一种常见且严重的错误,它通常由于指针未初始化、被设置为nullptr或指向无效地址引起,本文主要介绍了C++ 空指针解引用的解决方法,感兴趣的可以了解一下
    2024-08-08
  • C++取得当前时间的方法

    C++取得当前时间的方法

    这篇文章主要介绍了C++取得当前时间的方法,实例展示了通过系统函数获取当前时间的实现方法,非常简单易懂,需要的朋友可以参考下
    2014-10-10
  • C++实现推箱子小项目

    C++实现推箱子小项目

    这篇文章主要为大家详细介绍了C++实现推箱子小项目,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • C++单一职责原则示例代码浅析

    C++单一职责原则示例代码浅析

    我们在设计一个类时要学会发现职责,并把那些职责相互分离,其实要去判断是否应该分离出一个类来并不难,前面说过,一个类应该只有一个引起它变化的原因,如果你能想到其它的原因也能去改变这个类,那么这个类就具有多于1个的职责,就应该考虑类的职责分离
    2023-02-02
  • C语言实现通用数据结构之通用椎栈

    C语言实现通用数据结构之通用椎栈

    这篇文章主要为大家详细介绍了C语言实现通用数据结构之通用椎栈,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C++运算符重载详情介绍

    C++运算符重载详情介绍

    这篇文章主要介绍了C++运算符重载,C++当中除了函数可以重载之外,其实运算符也是可以重载的,C++根据操作数的数目和类型来决定要使用哪一种操作,下面一起进入文章里哦阿姐更多详情吧
    2022-01-01
  • C语言实现bmp图像对比度扩展

    C语言实现bmp图像对比度扩展

    这篇文章主要为大家详细介绍了C语言实现bmp图像对比度扩展,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10

最新评论