C语言数据结构之堆、堆排序的分析及实现

C语言数据结构之堆、堆排序的分析及实现

什么是堆

堆(Heap)是一种特殊的树形数据结构,它满足两个条件:

  1. 堆是一棵完全二叉树;
  2. 堆中任意节点的值总是不大于/不小于其子节点的值。

如果父节点的值不大于所有子节点的值,此堆称为小根堆,又称为最小堆。如果父节点的值不小于所有子节点的值,此堆称为大根堆,又称为最大堆。

堆通常可以使用数组来实现,具体实现方法是将堆的元素依次存入数组中,对于任意下标为i的节点,它的左儿子的下标为2i+1,右儿子的下标为2i+2,它的父节点的下标为(i-1)/2。

堆排序的基本思想

堆排序是一种利用堆的数据结构对数组中的元素进行排序的算法。它的基本思路如下:

  1. 先把要排序的数组构建成一个大根堆(或小根堆);
  2. 取出堆顶的元素,将其和末尾元素交换;
  3. 缩小范围:把数组范围缩小至之前的数组长度-1,并且刚才被调换到了最后面的那个元素不再参与调整堆的过程;
  4. 重新调整堆(依次下沉);
  5. 循环执行第2到第4步,直到整个数组排好序为止。

堆排序的实现步骤

1. 构建堆

构建堆的过程是将一个数组调整为一个大根堆或小根堆的过程。我们以构建大根堆为例,构建小根堆只需要把「a[i] < a[lchild(i)]」改为「a[i] > a[lchild(i)]」即可。

void heapify(int a[], int n, int i) {
    int largest = i; // 初始化最大元素为当前节点
    int l = 2 * i + 1; // 左子节点
    int r = 2 * i + 2; // 右子节点

    // 如果左子节点比当前节点大,则更新最大元素
    if (l < n && a[l] > a[largest]) {
        largest = l;
    }

    // 如果右子节点比当前节点大,则更新最大元素
    if (r < n && a[r] > a[largest]) {
        largest = r;
    }

    // 如果最大元素不是当前节点,则交换之后再递归调整堆
    if (largest != i) {
        swap(&a[i], &a[largest]);
        heapify(a, n, largest);
    }
}

2. 堆排序

在构建好一个大根堆或小根堆之后,我们就可以把堆首(最大或最小元素)和堆尾调换。然后重新调整堆,再次得到一个大根堆或小根堆,然后再把堆首和堆尾交换,这样循环下去就可以得到一个有序的序列了。

void heapSort(int a[], int n) {
    // 构建大根堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(a, n, i);
    }

    // 交换堆顶元素和堆尾元素,然后重新调整堆
    for (int i = n - 1; i >= 0; i--) {
        swap(&a[0], &a[i]);
        heapify(a, i, 0);
    }
}

示例说明

示例1:从小到大排序

我们来看一下一个从小到大排序的示例:

int a[] = {5,2,9,4,7,6,1,3,8};
int n = sizeof(a)/sizeof(a[0]);

heapSort(a, n); // 排序

for (int i = 0; i < n; i++) {
    printf("%d ", a[i]); // 输出结果:1 2 3 4 5 6 7 8 9
}

示例2:从大到小排序

如果要从大到小排序,只需要将堆的排序顺序改为小根堆即可:

void heapify(int a[], int n, int i) {
    int smallest = i; // 初始化最小元素为当前节点
    int l = 2 * i + 1; // 左子节点
    int r = 2 * i + 2; // 右子节点

    // 如果左子节点比当前节点小,则更新最小元素
    if (l < n && a[l] < a[smallest]) {
        smallest = l;
    }

    // 如果右子节点比当前节点小,则更新最小元素
    if (r < n && a[r] < a[smallest]) {
        smallest = r;
    }

    // 如果最小元素不是当前节点,则交换之后再递归调整堆
    if (smallest != i) {
        swap(&a[i], &a[smallest]);
        heapify(a, n, smallest);
    }
}

void heapSort(int a[], int n) {
    // 构建小根堆
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(a, n, i);
    }

    // 交换堆顶元素和堆尾元素,然后重新调整堆
    for (int i = n - 1; i >= 0; i--) {
        swap(&a[0], &a[i]);
        heapify(a, i, 0);
    }
}

int a[] = {5,2,9,4,7,6,1,3,8};
int n = sizeof(a)/sizeof(a[0]);

heapSort(a, n); // 排序

for (int i = 0; i < n; i++) {
    printf("%d ", a[i]); // 输出结果:9 8 7 6 5 4 3 2 1
}

以上就是关于堆(Heap)和堆排序(Heap Sort)的具体分析及实现步骤,以及两个排序示例讲解。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之堆、堆排序的分析及实现 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 集合框架及背后的数据结构

    集合框架及背后的数据结构 集合框架是Java编程语言中的一组接口和实现类,用于存储数据的集合。集合框架中提供了许多不同类型的集合,包括List、Set、Map等。背后的数据结构是实现集合框架的关键,不同的数据结构适用于不同的集合类型和场景。 集合框架中的接口和实现类 Java中的集合框架定义了一些接口以及这些接口的实现类,在使用Java集合的时候,主要是使用…

    数据结构 2023年5月17日
    00
  • 8个简单部分开启Java语言学习之路 附java学习书单

    8个简单部分开启Java语言学习之路 如果你想要学习Java语言,但是不知道从何入手,在这里,我们将为你提供一份简单易懂的攻略,分8个步骤带你开启Java语言学习之路。 1. 安装Java开发工具 Java学习的第一步是安装Java开发工具,目前比较流行的Java开发工具有多种,例如Eclipse、Intellij IDEA、NetBeans等。本攻略以In…

    数据结构 2023年5月17日
    00
  • oracle 数据库学习 基本结构介绍

    Oracle 数据库学习:基本结构介绍攻略 概述 Oracle 数据库是目前世界上使用最为广泛的一种关系型数据库。学习 Oracle 数据库需要具备一定的数据库基础知识,特别是SQL语言的使用,才能更好地理解 Oracle 数据库的基本结构。本攻略将从以下几个方面介绍 Oracle 数据库的基本结构: 数据库系统组成; Oracle 实例; 数据库; 表空间…

    数据结构 2023年5月17日
    00
  • C#数据结构与算法揭秘二 线性结构

    C#数据结构与算法揭秘二 线性结构 线性结构是指数据元素之间一对一的关系,即数据元素之间存在一个前驱和一个后继。一般有两种基本形式:线性表和栈、队列。 线性表 线性表是由同类型数据元素构成有序序列的线性结构,常被用于实现基于数组的数据结构,如向量、矩阵等。 线性表可以分为顺序表和链表两种。 顺序表(Sequence List):是把线性表的元素按照顺序存储在…

    数据结构 2023年5月17日
    00
  • C语言数据结构算法基础之循环队列示例

    标题:C语言数据结构算法基础之循环队列示例 1. 简介 循环队列是一种常见的数据结构,它采用固定大小的数组来模拟队列的数据结构,可以高效地处理队列的进出操作。本文将会讲解循环队列的实现原理和示例代码。 2. 循环队列基本原理 循环队列通过两个指针front和rear来实现队列的添加和删除操作。在初始化时,front和rear的初始值都为0。每当数据进入队列时…

    数据结构 2023年5月17日
    00
  • C语言数据结构二叉树简单应用

    C语言数据结构二叉树简单应用攻略 1. 什么是二叉树? 二叉树(Binary Tree)是一种树形结构,它的每个节点最多包含两个子节点,它是非线性数据结构,可以用来表示许多问题,例如家族关系、计算机文件系统等等。 2. 二叉树的基本操作 二叉树的基本操作包括插入、删除、查找等等,本攻略主要讲解插入和查找的实现。 插入操作的代码如下: // 二叉树的插入操作 …

    数据结构 2023年5月17日
    00
  • mysql的Buffer Pool存储及原理解析

    下面我就来详细讲解一下“mysql的Buffer Pool存储及原理解析”的攻略。 Buffer Pool简介 在MySQL中,Buffer Pool是一个重要的概念,也可以说是MySQL最重要的性能优化建议之一。Buffer Pool是MySQL内存中缓存数据页的数据结构,用于加速数据的读写。 数据页 在MySQL中,数据是以数据页(page)为单位进行读…

    数据结构 2023年5月17日
    00
  • C++数据结构之哈希表的实现

    以下是详细的讲解: C++数据结构之哈希表的实现 哈希表的概念 哈希表是一种能够实现快速查找的散列表,通过将关键字映射到哈希表中的一个位置来实现快速查找。哈希表的查询、删除时间复杂度为O(1),操作效率非常高,所以常常被用来对大量数据进行检索。 哈希表的实现 哈希函数 哈希函数的主要作用就是将任意长度的输入数据转化为固定长度的散列值,一般采用对关键字进行取模…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部