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语言排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言 数据结构堆排序顺序存储(升序)

    堆排序顺序存储(升序) 一: 完全二叉树的概念:前h-1层为满二叉树,最后一层连续缺失右结点! 二:首先堆是一棵全完二叉树: a:构建一个堆分为两步:⑴创建一棵完全二叉树      ⑵调整为一个堆 (标注:大根堆为升序,小根堆为降序) b:算法描述:①创建一棵完全二叉树 ②while(有双亲){ A:调整为大根堆: B:交换根和叶子结点: C:砍掉叶子结点: } c:时间复杂度为 O(nlogn)  ,空间复杂度为 O(1), 是不稳定排序! 代码实现: /*堆排序思想:[完全二叉树的定义:前

  • C语言数据结构二叉树之堆的实现和堆排序详解

    目录 一.本章重点 二.堆 2.1堆的介绍 2.2堆的接口实现 三.堆排序 一.本章重点 堆的介绍 堆的接口实现 堆排序 二.堆 2.1堆的介绍 一般来说,堆在物理结构上是连续的数组结构,在逻辑结构上是一颗完全二叉树. 但要满足 每个父亲节点的值都得大于孩子节点的值,这样的堆称为大堆. 每个父亲节点的值都得小于孩子节点的值,这样的堆称为小堆. 那么以下就是一个小堆. 百度百科: 堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆. 若将和此次序列对应的一维数

  • C语言实现堆排序的简单实例

    本文通过一个C语言实现堆排序的简单实例,帮助大家抛开复杂的概念,更好的理解堆排序. 实例代码如下: void FindMaxInHeap(int arr[], const int size) { for (int j = size - 1; j > 0; --j) { int parent = j / 2; int child = j; if (j < size - 1 && arr[j] < arr[j+1]) { ++child; } if (arr[child] &

  • C语言数据结构之堆排序源代码

    本文实例为大家分享了C语言堆排序源代码,供大家参考,具体内容如下 1. 堆排序 堆排序的定义及思想可以参考百度百科: 用一句概括,堆排序就是一种改进的选择排序,改进的地方在于,每次做选择的时候,不单单把最大的数字选择出来,而且把排序过程中的一些操作进行了记录,这样在后续排序中可以利用,并且有分组的思想在里面,从而提高了排序效率,其效率为O(n*logn). 2. 源代码 堆排序中有两个核心的操作,一个是创建大顶堆(或者小顶堆,这里用的是大顶堆),再一个就是对堆进行调整.这里需要注意的是,并没有真

  • C语言实现基于最大堆和最小堆的堆排序算法示例

    堆定义 堆实际上是一棵完全二叉树,其任何一非叶节点满足性质: Key[i]<=key[2i+1]&&Key[i]<=key[2i+2](小顶堆)或者:Key[i]>=Key[2i+1]&&key>=key[2i+2](大顶堆) 即任何一非叶节点的关键字不大于或者不小于其左右孩子节点的关键字. 堆排序的思想 利用大顶堆(小顶堆)堆顶记录的是最大关键字(最小关键字)这一特性,使得每次从无序中选择最大记录(最小记录)变得简单. 最大堆:所有节点的子节点比其

  • C语言实现各种排序算法实例代码(选择,冒泡,插入,归并,希尔,快排,堆排序,计数)

    目录 前言 选择排序 冒泡排序 插入排序 归并排序 希尔排序 快速排序 堆排序 计数排序 总结 前言 平时用惯了高级语言高级工具高级算法,难免对一些基础算法感到生疏.但最基础的排序算法中实则蕴含着相当丰富的优化思维,熟练运用可起到举一反三之功效. 选择排序 选择排序几乎是最无脑的一种排序算法,通过遍历一次数组,选出其中最大(小)的值放在新数组的第一位:再从数组中剩下的数里选出最大(小)的,放到第二位,依次类推. 算法步骤 设数组有n个元素,{ a 0 , a 1 , - , a n } 从数组第

  • C语言八大排序之堆排序

    目录 前言 一.堆排序的概念 二.堆排序的实现 第一步:构建堆 第二步:排序 三.完整代码 四.证明建堆的时间复杂度 前言 本章我们来讲解八大排序之堆排序.2022,地球Online新赛季开始了!让我们一起努力内卷吧! 一.堆排序的概念 堆排序(Heapsort):利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.通过堆来进行选择数据,需要注意的是 排升序要建大堆,排降序建小堆. 堆排序使用堆来选数,效率就高了很多. 时间复杂度: 空间复杂度: 稳定性:不稳定 二.堆排序的实

  • C语言数据结构中堆排序的分析总结

    目录 一.本章重点 二.堆 2.1堆的介绍(三点) 2.2向上调整 2.3向下调整 2.4建堆(两种方式) 三.堆排序 一.本章重点 堆 向上调整 向下调整 堆排序 二.堆 2.1堆的介绍(三点) 1.物理结构是数组 2.逻辑结构是完全二叉树 3.大堆:所有的父亲节点都大于等于孩子节点,小堆:所有的父亲节点都小于等于孩子节点. 2.2向上调整 概念:有一个小/大堆,在数组最后插入一个元素,通过向上调整,使得该堆还是小/大堆. 使用条件:数组前n-1个元素构成一个堆. 以大堆为例: 逻辑实现: 将

  • C语言对堆排序一个算法思路和实现代码

    算法思想简单描述: 堆排序是一种树形选择排序,是对直接选择排序的有效改进. 堆的定义如下:具有n个元素的序列(h1,h2,...,hn),当且仅当满足(hi>=h2i,hi>=2i+1)或(hi<=h2i,hi<=2i+1)(i=1,2,...,n/2)时称之为堆.在这里只讨论满足前者条件的堆. 由堆的定义可以看出,堆顶元素(即第一个元素)必为最大项.完全二叉树可以很直观地表示堆的结构.堆顶为根,其它为左子树.右子树. 初始时把要排序的数的序列看作是一棵顺序存储的二叉树,调整它们的

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

    目录 1.堆的概念及结构 2.堆的实现 2.1堆的向下调整算法 2.2堆的向上调整算法 2.3建堆(数组) 2.4堆排序 2.5堆排序的时间复杂度 1.堆的概念及结构 如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树(二叉树具体概念参见——二叉树详解)的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大

随机推荐