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

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日

相关文章

  • Javascript实现快速排序(Quicksort)的算法详解

    Javascript实现快速排序的算法详解 在这个攻略中,我们将通过Javascript实现快速排序算法,并讲解算法的详细过程。 快速排序的基本思想 快速排序是一种基于交换的排序算法,其基本思想是通过选择一个基准元素,在一趟排序过程中,将之前需要排序的序列中的元素分割成两个部分,其中,左边部分元素的值都小于基准元素的值,右边部分元素的值都大于基准元素的值,然…

    算法与数据结构 2023年5月19日
    00
  • C语言中的5种简单排序算法(适合小白)

    C语言中的5种简单排序算法(适合小白) 介绍 排序算法是计算机科学中最基本的算法之一,其主要目的是将一组无序的数据按照一定的规则进行排列。在计算机程序设计中,排序算法是非常常用的操作之一。 本文将会介绍C语言中5种简单的排序算法,这些算法非常适合新手上手学习。 以下是5种简单排序算法的详细介绍和实例代码。 冒泡排序(Bubble Sort) 冒泡排序也是一种…

    算法与数据结构 2023年5月19日
    00
  • C++堆排序算法的实现方法

    C++堆排序算法的实现方法 堆排序是一种高效的排序算法,使用一定程度的空间复杂度换来更快的时间复杂度。下面将详细讲解C++中堆排序算法的实现方法。 算法实现步骤: 将待排序数组构建成一个二叉堆。 将堆顶元素与堆底元素进行交换。 对除了堆底元素以外的堆进行调整,使其重新成为一个新的堆。 重复2、3步骤,直到整个数组排序完成。 代码实现 C++中STL容器提供了…

    算法与数据结构 2023年5月19日
    00
  • TF-IDF与余弦相似性的应用(一) 自动提取关键词

    下面我将详细讲解“TF-IDF与余弦相似性的应用(一) 自动提取关键词”的完整攻略。 什么是TF-IDF? TF-IDF(Term Frequency-Inverse Document Frequency)是一种常用于信息检索与分类中的文本特征提取方法,用于评估一段文本中词的重要程度。TF-IDF的核心思想就是:一个词在一篇文档中出现的频次(TF)越高,同时…

    算法与数据结构 2023年5月19日
    00
  • C语言之直接插入排序算法的方法

    C语言直接插入排序算法的方法 什么是直接插入排序 直接插入排序,是一种应用最广泛的排序算法之一,也是一种稳定的排序算法。它的基本思想是将一个记录插入到已经排好序的有序表中,从而得到一个新的有序表。具体的过程是将待排序的元素插入到已经排好序的元素中,使插入后仍保持有序。 代码实现 下面是用C语言实现直接插入排序算法的代码: void direct_insert…

    算法与数据结构 2023年5月19日
    00
  • Java排序之冒泡排序的实现与优化

    Java排序之冒泡排序的实现与优化 冒泡排序基本原理 冒泡排序是一种简单的排序算法,其基本思想是通过比较相邻的元素,将较大的数交换到右边,较小的数交换到左边。这样每一轮交换后,未排序的数列中的最大元素就被移动到了最右边,因此被称为“冒泡排序”。 基本算法实现 下面是基本的冒泡排序算法实现: public static void bubbleSort(int[…

    算法与数据结构 2023年5月19日
    00
  • PHP 各种排序算法实现代码

    下面我将详细讲解“PHP 各种排序算法实现代码”的完整攻略。 简介 排序算法是计算机科学最常用的算法之一,它可以将一组数据按照特定的排序规则进行排序。在实际的开发中,我们经常需要对数据进行排序,比如搜索引擎对搜索结果页的排序,电商网站对商品列表页的排序等。 目前常见的排序算法有插入排序、选择排序、希尔排序、归并排序、快速排序、堆排序等。下面我们将会分别介绍这…

    算法与数据结构 2023年5月19日
    00
  • C++中字符串全排列算法及next_permutation原理详解

    C++中字符串全排列算法及next_permutation原理详解 介绍 全排列是指将一组数按一定顺序进行排列,得到所有有可能的组合。例如,对于数字1、2、3,全排列如下: 123132213231312321 C++中有现成的函数next_permutation可以实现全排列,但理解其原理仍然很重要,本篇文章将详细讲解next_permutation的原理…

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