C语言排序之 堆排序

 更新时间:2022年04月19日 10:44:16   作者:sndapk  
这篇文章主要介绍了C语言排序之堆排序,文章基于C语言的相关资料展开详细内容,具有一定的参考资料,需要的小伙伴可以参考一下

前言:

堆是具有以下性质的完全二叉树

每个节点大于或等于其左右子节点,此时称为大顶(根)堆

​每个节点小于或等于其左右子节点,此时称为小顶(根)堆

完全二叉树在数组中下标换算公式

假设堆根节点从1开始编号(从1开始方便计算,0下标空着)
下面以编号为i的非根节点为例,计算其关联节点的下标公式为:
其父节点:i/2
其左孩子:2i
其右孩子:2i+1

注:把这个完全二叉树按层序遍历放入数组(0下标不用),则满足上面的关系表达

代码工作流程

整体流程

a. 根据节点换算公式先从最下层非叶节点开始,依次从右到左(自下而上)一直到根创建初始堆

b. 循环n-1次,依次执行:条件判断后交换堆顶和堆尾元素
重建除堆尾外元素为新堆,一直到根

重建堆函数流程

接收参数开始下标和数组有效长度
保存堆顶,自上而下建堆,如果堆顶(临时堆顶)比子节点小(大顶堆中),则孩子赋值给临时堆顶位置(不需要swap函数交换,swap没必要),并让临时堆顶位置指定子节点
for循环终止一定会找到合适的位置,此时临时堆顶指向的位置可能是函数调用时的位置,也可能发生改变(代码中执行了一次强制赋值)

大小顶堆使用场景

大顶堆用来做升序排序,小顶堆用来做降序排序

时间复杂度

O(nlogn)
不稳定

代码

#include <stdio.h>
#include <stdbool.h>

#define MAXSIZE 9

typedef struct {
    int r[MAXSIZE+1]; // first index used as tmp, not real data
    int len;
}SqList;

void swap(SqList *L, int i, int j) {
    int tmp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = tmp;
}


void heap_adjust(SqList *L, int s, int len) {
    int temp, i;

    temp = L->r[s]; // s(start) index may be a invalid element in this heap and try adjust

    for (i=s*2; i<=len; i*=2) { // compare with child
        if (i<len && L->r[i] < L->r[i+1]) {
            i++; // select the max child
        }

        if (temp >= L->r[i]) {
            break; // need not adjust
        }

        L->r[s] = L->r[i]; //need not swap, because always use temp compare with next level child

        s = i; // next loop, now s sub tree root node may be a invalid element
    }

    L->r[s] = temp; // finally, must be found the right place(or not changed)

}


void heap_adjust_2(SqList *L, int s, int len) {
    printf("use test function\n");
    int temp, i;

    temp = L->r[s]; // s(start) index may be a invalid element in this heap and try adjust

    for (i=s*2; i<=len; i*=2) { // compare with child
        if (i<len && L->r[i] < L->r[i+1]) {
            i++; // select the max child
        }

        if (temp >= L->r[i]) {
            break; // need not adjust
        }

        swap(L, s, i); //need not swap, because always use temp compare with next level child

        s = i; // next loop, now s sub tree root node may be a invalid element
    }

    L->r[s] = temp; // finally, must be found the right place(or not changed)

}

void heap_sort(SqList *L) {
    // init serial to a heap first(type: big top), down->up and right->left
    int i, j;
    for (i=L->len/2; i>0; --i) {
        heap_adjust(L, i, L->len);
        //heap_adjust_2(L, i, L->len);
    }


    for (j=L->len; j>1; --j) {
        swap(L, 1, j);
        heap_adjust(L, 1, j-1);
    }

}

int main(void) {
    SqList list = {
        {999,50,10,90,30,70,40,80,60,20},
        MAXSIZE
    };

    heap_sort(&list);
    printf("after heap_sort:\n");
    for (int i=0; i<=MAXSIZE; i++) {
        printf("index: %d, value: %d\n",i,list.r[i]);
    }
    return 0;
}

output

➜  c gcc sort_heap.c && ./a.out
after heap_sort:
index: 0, value: 999
index: 1, value: 10
index: 2, value: 20
index: 3, value: 30
index: 4, value: 40
index: 5, value: 50
index: 6, value: 60
index: 7, value: 70
index: 8, value: 80
index: 9, value: 90

到此这篇关于C语言排序之 堆排序的文章就介绍到这了,更多相关C语言排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++实现统计代码运行时间的示例详解

    C++实现统计代码运行时间的示例详解

    这篇文章主要为大家详细介绍了C++一个有趣的小项目——统计代码运行时间,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-05-05
  • C++深入分析数据在内存中的存储形态

    C++深入分析数据在内存中的存储形态

    使用编程语言进行编程时,需要用到各种变量来存储各种信息。变量保留的是它所存储的值的内存位置。这意味着,当您创建一个变量时,就会在内存中保留一些空间。您可能需要存储各种数据类型的信息,操作系统会根据变量的数据类型,来分配内存和决定在保留内存中存储什么
    2023-01-01
  • C++详细实现红黑树流程详解

    C++详细实现红黑树流程详解

    今天我要跟大家介绍二叉搜索树中的另一颗树——红黑树,它主要是通过控制颜色来控制自身的平衡,但它的平衡没有AVL树的平衡那么严格
    2022-06-06
  • 手把手带你学习C++的数据类型

    手把手带你学习C++的数据类型

    这篇文章主要为大家介绍了C++的数据类型,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助,希望能够给你带来帮助
    2021-11-11
  • 掌握C++编程中反斜杠续行符的使用方法

    掌握C++编程中反斜杠续行符的使用方法

    这篇文章主要介绍了掌握C++编程中反斜杠续行符的使用方法,包括取反斜杠的本意的方法等基本知识点,需要的朋友可以参考下
    2016-01-01
  • C语言中花式退出程序的方式总结

    C语言中花式退出程序的方式总结

    在本篇文章当中主要给大家介绍C语言当中一些不常用的特性,比如在main函数之前和之后设置我们想要执行的函数,以及各种花式退出程序的方式,需要的可以参考一下
    2022-10-10
  • 浅谈 C++17 里的 Visitor 模式

    浅谈 C++17 里的 Visitor 模式

    Visitor模式经常用于将更新的设计封装在一个类中,并且由待更改的类提供一个接受接口,其关键技术在于双分派技术,本文主要介绍 C++17 里的 Visitor 模式的相关资料,需要的朋友可以参考下面文章的具体内容
    2021-09-09
  • KMP算法最浅显理解(小白教程)

    KMP算法最浅显理解(小白教程)

    这篇文章主要介绍了KMP算法最浅显理解(小白教程),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • C++如何计算结构体与对象的大小

    C++如何计算结构体与对象的大小

    这篇文章主要给大家介绍了关于C++如何计算结构体与对象大小的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05
  • C++音乐播放按钮的封装过程详解

    C++音乐播放按钮的封装过程详解

    此篇文章用于记录学习C++封装音乐播放按钮,封装将对象的属性和行为作为一个整体,表现生活中的事物、将属性和行为加以权限控制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08

最新评论