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语言abort函数实例用法

    c语言abort函数实例用法

    在本篇文章里小编给大家整理了一篇关于c语言abort函数实例用法及相关知识点,有兴趣的朋友们可以学习下。
    2021-09-09
  • C++中new和delete的使用方法详解

    C++中new和delete的使用方法详解

    这篇文章主要介绍了C++中new和delete的使用方法详解的相关资料,希望通过本文能帮助到大家,需要的朋友可以参考下
    2017-10-10
  • Linux下用C++实现俄罗斯方块

    Linux下用C++实现俄罗斯方块

    这篇文章主要为大家详细介绍了Linux下用C++实现俄罗斯方块的相关资料,感兴趣的小伙伴们可以参考一下
    2016-08-08
  • C语言数据结构之平衡二叉树(AVL树)实现方法示例

    C语言数据结构之平衡二叉树(AVL树)实现方法示例

    这篇文章主要介绍了C语言数据结构之平衡二叉树(AVL树)实现方法,结合实例形式分析了C语言平衡二叉树的相关定义与使用技巧,需要的朋友可以参考下
    2018-01-01
  • 在C++中使用HP-Socket

    在C++中使用HP-Socket

    这篇文章主要介绍了C++中简单使用HP-Socket,HP-Socket 是一套通用的高性能 TCP/UDP /HTTP 通信 框架 ,包含服务端组件、客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP /HTTP 通信系统,下面来看看更具体的介绍吧
    2021-11-11
  • C++读取INI配置文件类实例详解

    C++读取INI配置文件类实例详解

    这篇文章主要介绍了C++读取INI配置文件类的实现方法,需要的朋友可以参考下
    2014-07-07
  • C语言scanf,fscanf和sscanf的区别

    C语言scanf,fscanf和sscanf的区别

    每种语言都对正则表达式有着不同程度的支持,在C语言中,有输入功能的这三个函数对正则表达式的支持并不强大,但是我们还是有必要了解一下
    2021-10-10
  • c++基础语法:构造函数与析构函数

    c++基础语法:构造函数与析构函数

    构造函数用来构造一个对象,主要完成一些初始化工作,如果类中不提供构造函数,编译器会默认的提供一个默认构造函数(参数为空的构造函数就是默认构造函数) ;析构函数是隐式调用的,delete对象时候会自动调用完成对象的清理工作
    2013-09-09
  • C语言中关于库函数 qsort 快排的用法

    C语言中关于库函数 qsort 快排的用法

    快速排序Qsort是所有学习算法和数据结构最基础的一个部分,也是考试题和面试的一个小重点。本片文章带你了解Qsort的详细用法规则
    2021-09-09
  • C++ DLL实现循环播放音乐的示例详解

    C++ DLL实现循环播放音乐的示例详解

    这篇文章主要为大家详细介绍了C++ DLL实现循环播放音乐的相关知识,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解下
    2024-03-03

最新评论