c++深入浅出讲解堆排序和堆

yizhihongxing

C++深入浅出讲解堆排序和堆

堆的定义

堆是一种特殊的树形数据结构,它满足以下两个特性:

  • 堆是一个完全二叉树(Complete Binary Tree);
  • 堆中每个节点的值都大于等于(或小于等于)其左右子节点的值。

可以看出,堆一般分为两种类型:大根堆(Max Heap)和小根堆(Min Heap)。大根堆的每个节点的值都大于等于其左右子节点的值,小根堆则相反。

堆的应用

堆主要应用于优先队列、Top K 问题、求中位数等场景。

  • 在优先队列中,堆可以快速地找到队列中的最大或最小值;
  • 在 Top K 问题中,堆可以维护一个大小为 K 的堆,依次将数据插入堆中,最后堆中的数据即为前 K 大或前 K 小的元素;
  • 求中位数问题可以通过维护两个堆来处理,使得左边堆的最大值小于右边堆的最小值。

堆的实现

堆可以通过数组来实现,因为完全二叉树可以被序列化成一个数组。

插入元素

插入元素时,可以将新元素插入到堆的最后一个位置,然后使用一个循环将新元素与其父节点进行比较,如果父节点的值小于新元素,则将父节点和新元素交换位置,直到新元素的父节点的值大于等于新元素的值为止。

删除元素

删除元素时,可以将堆中最后一个元素移到堆顶,然后让其与左右子节点中较大的值进行比较,如果较大的值大于该节点的值,则将其与较大的子节点交换位置,并继续向下比较。直到该节点的值大于等于其左右子节点的值为止。

堆排序

堆排序是一种不稳定的排序算法,它的时间复杂度为 O(nlogn)。

堆排序的思路

  1. 构建大根堆(或小根堆):将待排序数组构建成一个大根堆(或小根堆);
  2. 堆排序:将大根堆(或小根堆)根节点与最后一个叶子节点进行交换,并将交换后的最后一个叶子节点排除在堆的范围之外;此时,根节点可能不再满足堆的性质,因此需要将其与左右子节点中较大的节点进行比较并交换位置,然后继续向下比较,直到满足堆的性质为止;
  3. 重复步骤 2,直到整个数组有序。

堆排序的实现

void heapSort(vector<int>& nums) {
    int n = nums.size();
    // 从最后一个非叶子节点开始,依次向下调整堆
    for (int i = (n - 2) / 2; i >= 0; i--) {
        heapify(nums, i, n);
    }
    // 交换堆顶与最后一个叶子节点,并重新调整堆
    for (int i = n - 1; i > 0; i--) {
        swap(nums[0], nums[i]);
        heapify(nums, 0, i);
    }
}

void heapify(vector<int>& nums, int i, int n) {
    int largest = i;
    int left = i * 2 + 1, right = i * 2 + 2;
    if (left < n && nums[left] > nums[largest]) {
        largest = left;
    }
    if (right < n && nums[right] > nums[largest]) {
        largest = right;
    }
    if (largest != i) {
        swap(nums[i], nums[largest]);
        heapify(nums, largest, n);
    }
}

这里使用了一个辅助函数 heapify() 来调整堆,它将一个大小为 n 的数组 nums 中的第 i 个节点向下调整,使得以 i 为根节点的子树满足堆的性质。heapify() 的具体实现可以参考前面所述。

堆排序的示例

下面是一个堆排序的示例:

#include <iostream>
#include <vector>

using namespace std;

void heapify(vector<int>& nums, int i, int n);

void heapSort(vector<int>& nums) {
    int n = nums.size();
    // 从最后一个非叶子节点开始,依次向下调整堆
    for (int i = (n - 2) / 2; i >= 0; i--) {
        heapify(nums, i, n);
    }
    // 交换堆顶与最后一个叶子节点,并重新调整堆
    for (int i = n - 1; i > 0; i--) {
        swap(nums[0], nums[i]);
        heapify(nums, 0, i);
    }
}

void heapify(vector<int>& nums, int i, int n) {
    int largest = i;
    int left = i * 2 + 1, right = i * 2 + 2;
    if (left < n && nums[left] > nums[largest]) {
        largest = left;
    }
    if (right < n && nums[right] > nums[largest]) {
        largest = right;
    }
    if (largest != i) {
        swap(nums[i], nums[largest]);
        heapify(nums, largest, n);
    }
}

int main() {
    vector<int> nums = {3, 8, 5, 2, 9, 7, 1, 4, 6};
    heapSort(nums);
    for (int num : nums) {
        cout << num << " ";
    }
    cout << endl;
    return 0;
}

输出结果如下:

1 2 3 4 5 6 7 8 9

这个例子演示了如何使用堆排序将无序数组 nums 排序。经过堆排序之后,数组 nums 变成了升序排列。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++深入浅出讲解堆排序和堆 - Python技术站

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

相关文章

  • C语言排序算法之冒泡排序实现方法【改进版】

    C语言排序算法之冒泡排序实现方法【改进版】可以采用双层循环的方式实现。接下来,我将为您详细介绍该排序算法的实现方法。 冒泡排序的基本思路 冒泡排序的基本思路是:通过比较相邻的元素,将小的元素交换到前面,大的元素交换到后面。在第一轮排序时,第一个元素与第二个元素进行比较,若第一个元素比第二个元素大,则将两个元素交换位置。接下来,第二个元素与第三个元素进行比较,…

    算法与数据结构 2023年5月19日
    00
  • php自定义二维数组排序函数array_orderby用法示例

    首先,让我们了解一下什么是“数组排序函数”以及“自定义排序函数”。 数组排序函数是指一些用来对数组排序的函数,例如sort()和asort()。自定义排序函数则是指我们可以根据自己的需求来编写一个排序函数,然后通过函数名传递给排序函数,让它按照我们自己的规则进行排序。 在PHP中,有一个函数array_orderby()可以帮助我们实现自定义排序功能。以下是…

    算法与数据结构 2023年5月19日
    00
  • PHP排序算法之冒泡排序(Bubble Sort)实现方法详解

    PHP排序算法之冒泡排序(Bubble Sort)实现方法详解 冒泡排序概述 冒泡排序是一种基本的排序算法,它的基本思想是比较相邻的两个元素,如果前一个元素比后一个元素大,就交换这两个元素,重复进行这个过程,直到没有任何一对元素需要比较为止。冒泡排序得名于通过交换相邻的元素来把最大值“冒泡”到数列的尽头。 冒泡排序的时间复杂度为O(n²),效率较低,但其思想…

    算法与数据结构 2023年5月19日
    00
  • Golang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等) 负载均衡是指在分布式系统中,将工作负载分摊到多个计算资源来进行共同处理的技术。 Golang作为一种高性能、可靠性语言,天然适合做负载均衡,因此我们可以用Golang实现四种常用的负载均衡算法。 什么是负载均衡算法? 负载均衡算法是指在分发服务时,选择合适的服务器来处理请求的一种算法。负载均衡可分为静态负载…

    算法与数据结构 2023年5月19日
    00
  • Java全排列算法字典序下的下一个排列讲解

    Java全排列算法字典序下的下一个排列是一个经典的计算机算法问题,本攻略将为大家讲解如何使用Java实现。 思路 在Java中,全排列可以使用递归实现,也可以使用字典序算法实现。本攻略就是讲解如何使用字典序算法实现Java全排列算法中的找到下一个排列。 Java全排列算法中的字典序下一个排列可以按以下步骤实现: 从右到左找到第一个顺序对 (i,j),满足 A…

    算法与数据结构 2023年5月19日
    00
  • 冒泡排序算法及Ruby版的简单实现

    冒泡排序是一种比较简单的排序算法,其基本思想是重复地遍历数列,每次比较相邻的两个元素,如果前一个元素比后一个元素大,则交换这两个元素的位置,直到遍历完整个数列,这样一次遍历后,数列中最大的元素就被排到了最后面。重复执行此过程,直到整个数列有序为止。 以下是冒泡排序算法的Ruby版简单实现: def bubble_sort(array) n = array.l…

    算法与数据结构 2023年5月19日
    00
  • 可能是你看过最全的十大排序算法详解(完整版代码)

    针对“可能是你看过最全的十大排序算法详解(完整版代码)”这篇文章,下面是详细的攻略: 标题 首先,该文章的标题是:可能是你看过最全的十大排序算法详解(完整版代码) 文章简介 其次,在文章简介中,作者提到该篇文章是一个完整介绍了十大排序算法并且附有代码实现的文章,可以帮助读者了解这些排序算法的原理和代码实现。 内容 文章的主体部分是对十大排序算法进行详细的讲解…

    算法与数据结构 2023年5月19日
    00
  • C/C++实现快速排序算法的思路及原理解析

    C/C++实现快速排序算法的思路及原理解析 快速排序算法是一种高效的排序算法,它的平均时间复杂度是 O(nlogn),最坏情况下的时间复杂度是 O(n^2)。快速排序算法的核心思想是分治法,通过不断将原问题分解成规模更小的子问题来实现排序。本文将详细讲解 C/C++ 实现快速排序算法的思路及原理解析,包括实现过程和两个示例说明。 快速排序算法实现原理 快速排…

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