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

yizhihongxing

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日

相关文章

  • 1811 E Living Sequence 两种解法

    思维 进制转换 数位DP 无前导0 T3Problem – 1811E – Codeforces 题目大意 从一个不含有数字4的递增序列中找第k个数并输出。如 \(1,2,3,5,6,7,8,9,10,11,12\), \(k = 4\) 时输出 \(5\)。 思路1 有一个巧妙的解法:考虑这个问题, 从一个没有限制的从1开始的递增序列找出第k个数, 显然就…

    算法与数据结构 2023年4月17日
    00
  • Java数据结构之单链表的实现与面试题汇总

    Java数据结构之单链表的实现与面试题汇总 一、前言 单链表是数据结构中最基础的数据结构之一,也是在面试时经常会考察的一个知识点。本文将详细介绍单链表的实现过程,并对常见的单链表面试题进行总结,帮助大家深入了解单链表的原理和应用。 二、单链表的实现 单链表是由一些列节点构成的,每个节点包括一个数据和一个指向下一个节点的指针。下面我们将实现一个简单的单链表,并…

    数据结构 2023年5月17日
    00
  • Java数据结构之链表实现(单向、双向链表及链表反转)

    Java数据结构之链表实现 链表基础概念 链表是一种数据结构,它由一系列节点(Node)组成,每个节点包含两个部分,一个是数据域(data),一个是指针域(next)。数据域存储数据信息,指针域指向下一个节点。 链表的种类很多,比如单向链表、双向链表、循环链表等等。 单向链表:链表的每个节点只有一个指针域,指向下一个节点。 双向链表:链表的每个节点有两个指针…

    数据结构 2023年5月17日
    00
  • Java面试题冲刺第十三天–数据库(3)

    当我们准备面试数据库相关的职位时,需要掌握SQL语言和常见的数据库管理系统。下面是针对Java面试中可能出现的常见数据库面试题的一些攻略。 1. 数据库连接的常见方式 在Java中,要与数据库连接有两种方式:JDBC和ORM框架。 (1) JDBC JDBC是Java连接数据库的标准方式,使用JDBC可以通过Java程序来连接不同的数据库。连接数据库的步骤包…

    数据结构 2023年5月17日
    00
  • JavaScript队列数据结构详解

    JavaScript队列数据结构详解 本文将为大家详细讲解JavaScript队列数据结构的相关知识。 什么是队列数据结构 队列是一种线性数据结构,它只允许在队列的两端进行插入和删除操作。在队列中,新元素插入到队列的末尾,也称为队尾。而删除操作则是从队列的前面删除元素,也称为队首。 将元素插入队列的操作称为入队,将元素删除队列的操作称为出队。除此之外,还有一…

    数据结构 2023年5月17日
    00
  • 一、对系统理论的认识

           经过一周的时间学习,我们知道了系统的定义:是一个由一组相互连接的要素构成的,能够实现某个目标的整体,任何一个系统都包括三种构成要件:要素连接,功能或目标。       1.系统的连接使得系统呈现特定的结构,使得系统的各个部件连接而产生系统特有的功能—相关性导新功能涌现。连接的媒介—“三流”(信息流,能量流,物质流)。       2.系统的静态…

    算法与数据结构 2023年4月18日
    00
  • C++高级数据结构之线段树

    C++高级数据结构之线段树攻略 什么是线段树 线段树是一种数据结构,它可以支持区间查询和单点修改,是处理静态区间问题的常用手段。它利用了 二分思想,将区间离散化成一些个体,然后考虑对个体进行处理,再结合区间合并的特性,更新区间信息。线段树主要由四个操作构成:建树、单点修改、区间查询和区间修改。 线段树的数据表示 在实现线段树时,我们需要考虑数据结构的几个要素…

    数据结构 2023年5月17日
    00
  • C语言数据结构之平衡二叉树(AVL树)实现方法示例

    C语言数据结构之平衡二叉树(AVL树)实现方法示例 介绍 AVL树是一种自平衡二叉搜索树,它保证了所有节点的左右子树高度差不超过1,从而提高了查找、插入和删除操作的效率。本篇文章将介绍如何使用C语言实现AVL树,并提供两个例子以说明实现方法。 实现方法 结构体定义 首先,定义AVL树节点的结构体,包括该节点存储的值、该节点的高度、该节点的左右子树指针。 ty…

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