C++中二叉堆排序详解

C++中二叉堆排序详解

什么是二叉堆排序

二叉堆是一种特殊的二叉树,它有两个特性:

  1. 根节点的键值是所有节点中最小/最大的;
  2. 对于节点i的键值一定不大/小于它的父节点i/2。

根据第二个规则,我们可以对于任何一个节点i,以i为根的子树都是一个小根堆/大根堆。将二叉堆中最小/最大的根节点取出,然后将最后一个节点放到根位置,再对根节点进行一次向下调整的操作,就可以将次小/大的节点取出。以此类推,不断重复这个过程,直到所有的节点都取出来了,则排序完成。

C++实现

向下调整

向下调整的过程需要通过一个函数来实现,如果当前节点的子节点比当前节点更小(小根堆)或更大(大根堆),则需要对当前节点进行调整,将当前节点与子节点交换。

void adjustDown(vector<int>& nums, int i, int len) {
    int temp = nums[i];
    int targetIndex = i * 2 + 1;
    while (targetIndex < len) {
        if (targetIndex + 1 < len and nums[targetIndex+1] < nums[targetIndex]) {
            targetIndex ++;
        }
        if (nums[targetIndex] >= temp) {
            break;
        }
        nums[i] = nums[targetIndex];
        i = targetIndex;
        targetIndex = 2 * i + 1;
    }
    nums[i] = temp;
}

建立二叉堆

建立二叉堆其实就是将一个乱序的数组转化为二叉堆。我们可以在数组中依次取出每个数字,将其插入到构建好的二叉堆中。

void buildHeap(vector<int>& nums) {
    int len = nums.size();
    int endNode = len / 2 - 1;
    for (int i = endNode; i >= 0; i--) {
        adjustDown(nums, i, len);
    }
}

排序

当我们建立好一颗二叉堆时,有一个非常重要的性质就是:最小/大值一定在数组的第一个位置,我们可以将其直接取出并放在排序好后数组的最后。通过这个方式,我们不断取出最小/大值,一次放在排序后的数组中,直到整个数组都排序完成。

void heapSort(vector<int>& nums) {
    // 建立二叉堆
    buildHeap(nums);

    // 从最后一个节点开始往前取数
    int len = nums.size();
    for (int i = len - 1; i > 0; i--) {
        swap(nums[0], nums[i]);  // 将最后一个元素放在排序好的队列首部
        adjustDown(nums, 0, i);  // 建立一个新的二叉堆,并将下一个最小/大值放在根节点位置
    }
}

示例

以小根堆为例,对于一个乱序的数组 [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5],我们可以通过以下方式进行二叉堆排序:

vector<int> nums = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};

// 将乱序数组转化为小根堆
buildHeap(nums);
// 输出建立完成的小根堆
cout << "Heap: ";
for (int num: nums) {
    cout << num << " ";
}
cout << endl;

// 对小根堆进行排序
heapSort(nums);
// 输出排序完成后的数组
cout << "Sorted nums: ";
for (int num: nums) {
    cout << num << " ";
}

输出结果如下:

Heap: 1 1 2 3 3 4 9 6 5 5 5 
Sorted nums: 1 1 2 3 3 4 5 5 5 6 9 

总结

通过现在的学习,我们了解了什么是二叉堆排序,也实现了在C++中二叉堆排序的过程。二叉堆排序是常用的排序算法,其时间复杂度为O(nlogn)。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++中二叉堆排序详解 - Python技术站

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

相关文章

  • 冒泡排序算法及Ruby版的简单实现

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

    算法与数据结构 2023年5月19日
    00
  • 大数据情况下桶排序算法的运用与C++代码实现示例

    桶排序算法是一种基于计数的排序算法,它的主要思想是把一组数据分成多个桶,对每个桶中的数据进行排序,最后依次把每个桶中的数据合并起来,得到排序后的结果。在大数据情况下,桶排序算法可以大幅减少排序时间,因为它可以快速地将数据分成多个桶,进行并行排序,最终合并起来。 以下是桶排序算法在大数据情况下的运用及C++代码示例: 算法思路 先确定桶的数量,也就是需要将数据…

    算法与数据结构 2023年5月19日
    00
  • Java 直接插入排序的三种实现

    Java 直接插入排序的三种实现 本文将介绍 Java 中直接插入排序的三种实现方式,分别为插入排序、希尔排序和折半插入排序。 插入排序 插入排序是一种简单直观的排序算法,其基本思想是将一个待排序的元素插入到已排好序列中的适当位置。 以下是 Java 中插入排序的实现代码: public static void insertSort(int[] arr) {…

    算法与数据结构 2023年5月19日
    00
  • Java 十大排序算法之计数排序刨析

    Java 十大排序算法之计数排序刨析 算法介绍 计数排序是一个时间复杂度为O(n+k)的非基于比较的排序算法,其中n是待排序元素的个数,k是待排序元素的范围,即待排序元素的最大值减去最小值再加1。 算法通过构建一个长度为k的计数数组来统计每个元素出现的次数,然后借助计数数组按顺序输出每个元素,就完成了排序过程。 因为计数排序是非基于比较的算法,因此可以在一定…

    算法与数据结构 2023年5月19日
    00
  • 京东在数据挖掘方面对推荐技术的优化

    京东在数据挖掘方面对推荐技术的优化 京东是中国著名的电商平台,一直在推进自己的推荐系统技术,以提高用户交互体验和推广效果。在数据挖掘方面,京东对推荐技术进行了一系列的优化,包括以下几个方面: 1. 数据收集和处理 京东首先通过大数据技术收集和整理用户的行为数据,包括购买、浏览、评价等多个方面。同时利用机器学习技术进行数据建模,包括对用户画像、商品描述等方面的…

    算法与数据结构 2023年5月19日
    00
  • C语言 扩展欧几里得算法代码

    下面我来为你详细讲解一下“C语言 扩展欧几里得算法代码”的完整攻略。 什么是扩展欧几里得算法? 扩展欧几里得算法是求解两个整数 a、b 的最大公约数(Greatest Common Divisor,简称 GCD)的一种算法。该算法可以不仅计算出最大公约数,还可以得到一组关于 a、b 的贝祖等式的整数解和一些运算过程。 算法流程 扩展欧几里得算法的流程如下: …

    算法与数据结构 2023年5月19日
    00
  • 使用C语言求解扑克牌的顺子及n个骰子的点数问题

    “使用C语言求解扑克牌的顺子及n个骰子的点数问题”,我们可以分别来看一下。 1. 求解扑克牌的顺子 首先我们需要了解什么是扑克牌的顺子,即五张连续的牌,如”10 J Q K A”等。因为一副牌里,最小的牌为2,最大的牌为A(即1),所以任何5张牌中最大和最小的差值不能超过4。 我们可以先将5张牌进行排序,然后用最大牌和最小牌计算差值,再去除所有大小王,如果差…

    算法与数据结构 2023年5月19日
    00
  • PHP字符串逆序排列实现方法小结【strrev函数,二分法,循环法,递归法】

    下面我将为您详细讲解“PHP字符串逆序排列实现方法小结【strrev函数,二分法,循环法,递归法】”的完整攻略。 什么是字符串逆序排列? 字符串逆序排列指的是将一个字符串中的字符按照相反的顺序重新排列,比如将字符串 “hello world” 更改为 “dlrow olleh”。 使用strrev函数实现字符串逆序排列 PHP内置函数 strrev() 可以…

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