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日

相关文章

  • 思科CCNA认证学习笔记(一)网络基础知识

    思科CCNA认证学习笔记(一)网络基础知识攻略 概述 思科CCNA认证是网络行业的重要认证之一,具有广泛的认可度和传播力。其中网络基础知识是CCNA考试的重要内容,对于初学者来说,掌握网络基础知识是入门的必经之路。本篇攻略将详细讲解网络基础知识的相关内容,包括讲解网络的概念、网络的分类、网络的拓扑结构、网络的协议以及网络的设备。 网络的概念 网络是由两台或两…

    算法与数据结构 2023年5月19日
    00
  • php实现快速排序的三种方法分享

    那么现在我将为您介绍“php实现快速排序的三种方法分享”的完整攻略。 什么是快速排序 快速排序(Quick Sort)通常被认为是对冒泡排序的一种改进。在冒泡排序中,需要进行多次的数据比较和交换操作,而快速排序与其不同之处在于它通过一个基准值将待排序的数组分成两个部分。在计算机领域,快速排序是一种常见的排序算法。 快速排序的常规实现思路 快速排序的常规实现思…

    算法与数据结构 2023年5月19日
    00
  • C++实现自顶向下的归并排序算法

    下面是“C++实现自顶向下的归并排序算法”的完整攻略。 归并排序的概念 归并排序是一种分治法排序算法,它将一个大数组分成两个部分,分别对这两个部分进行排序,最后将两个排好序的部分合并起来。归并排序的时间复杂度为O(n log n)。 归并排序的步骤 实现归并排序需要以下三个步骤: 分割 – 将数组分成两个部分,分别对每个部分进行排序。该过程使用二分法来实现。…

    算法与数据结构 2023年5月19日
    00
  • java图搜索算法之图的对象化描述示例详解

    Java图搜索算法之图的对象化描述示例详解 什么是图? 图是一种非线性数据结构,由节点和边组成,节点表示图中对象,边表示节点间相互关系。图分为有向图和无向图,有向边和无向边。 图的对象化描述 Java中可以使用对象化的方式来描述一个图,主要有两个类: Vertex(节点类) 节点类表示图中的节点,主要有两个属性: label:节点标签,用于区分不同节点。 w…

    算法与数据结构 2023年5月19日
    00
  • 深入解析Radix Sort基数排序算法思想及C语言实现示例

    深入解析Radix Sort基数排序算法思想及C语言实现示例 什么是基数排序算法 基数排序即Radix Sort,是一种非比较型排序算法。相比于其他排序算法,如快速排序、归并排序等,基数排序的时间复杂度较为稳定,且不受数据规模的影响,适用于数据范围较小但位数较多的序列排序。 基数排序算法思想 基数排序算法的核心思想是按照不同位数上的数字对数据进行排序,从低位…

    算法与数据结构 2023年5月19日
    00
  • JavaScript算法学习之冒泡排序和选择排序

    JavaScript算法学习之冒泡排序和选择排序 冒泡排序和选择排序是常见的两种排序算法。在本文中,我们将详细讲解这两种排序算法,并提供代码示例供读者参考。 冒泡排序 冒泡排序是一种简单的排序算法,它通过比较相邻两个元素的大小,依次将最大的元素冒泡到数组的末尾。 以下是冒泡排序的代码示例: function bubbleSort(array) { const…

    算法与数据结构 2023年5月19日
    00
  • C/C++语言八大排序算法之桶排序全过程示例详解

    C/C++语言八大排序算法之桶排序全过程示例详解 什么是桶排序 桶排序(Bucket Sort)是一种线性排序算法,它的基本思想是将数组内的元素根据某个规则分配到若干个桶中,然后对每个桶内的元素进行排序,最终合并每个桶内的有序元素即可得到原数组的有序结果。 桶排序的主要应用场景是待排序元素的分布比较均匀的情况下,性能表现优于其他排序算法(例如快速排序、归并排…

    算法与数据结构 2023年5月19日
    00
  • Flutter Dart快速排序算法示例详解

    Flutter Dart快速排序算法示例详解 介绍 快速排序是一种排序算法,其基本思想是选择一个基准元素,将数组分成两个子数组,其中一个子数组的元素都比基准元素小,另一个子数组的元素都比基准元素大。然后递归地对两个子数组进行快速排序。 实现步骤 选择一个基准元素,并将其从数组中移除。 遍历数组,将小于基准元素的元素放入一个新的左侧数组中,大于基准元素的元素放…

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