C++数据结构之堆详解

C++数据结构之堆详解

什么是堆

堆是一种完全二叉树。

堆分为大根堆和小根堆,大根堆满足每个节点的值都大于等于它的子节点,小根堆满足每个节点的值都小于等于它的子节点。

堆的实现

常见的实现堆的方式有数组和链表两种。

数组

由于二叉堆是完全二叉树,所以可以用数组来实现:

对于一个节点i,它的左子节点的下标是2 * i + 1,右子节点的下标是2 * i + 2,它的父节点的下标是(i - 1) / 2。

例如:

           1
         /  \
        2    3
       / \  / \
      4  5 6   7 

用数组实现时,可以按层级顺序将节点存储在数组中,下标为i的节点的左子节点为2 * i + 1,右子节点为2 * i + 2,其父节点为(i - 1) / 2。

上述二叉树可以用数组实现如下:

[1, 2, 3, 4, 5, 6, 7]

数组的第一个元素永远是根节点。

链表

堆也可以用链表来实现,每个节点包含指向左右子节点的指针和节点的值。

堆的基本操作

插入元素

要在堆中插入元素,必须保持堆的连通性,以及满足堆的特性。在插入一个新节点时,先插入到堆的最后一个位置,然后从该节点开始向上比较,如果该节点的值大于它的父节点的值,就交换它们的位置。

例如,现在有以下的大根堆:

          4
        /   \
       3     2
      / \   /
     1   5 6

要在这个堆中插入一个元素7,首先将它插入到堆的最后一个位置:

          4
        /   \
       3     2
      / \   / \
     1   5 6   7

然后从7节点开始向上比较,发现它大于2,所以将它与2交换位置:

          4
        /   \
       3     7
      / \   / \
     1   5 6   2

再与6交换位置:

          4
        /   \
       3     7
      / \   / \
     1   5 6   2

最终变成以下堆:

          7
        /   \
       3     6
      / \   / \
     1   5 4   2

删除元素

要在堆中删除一个元素,只能删除堆的根节点。将根节点移除后,将堆的最后一个元素放到根节点的位置,然后从该节点开始向下比较,如果该节点的值小于它的子节点的值,就交换它们的位置。

例如,现在有以下的大根堆:

          7
        /   \
       3     6
      / \   / \
     1   5 4   2

要从这个堆中删除最大的元素7,首先将它移除,并将堆的最后一个元素2放到根节点的位置:

          2
        /   \
       3     6
      / \   / 
     1   5 4   

然后从2节点开始向下比较,发现它小于6,所以将它与6交换位置:

          6
        /   \
       3     2
      / \   / 
     1   5 4   

再交换3和6的位置:

          6
        /   \
       1     2
      / \   / 
     3   5 4   

最终变成以下堆:

          6
        /   \
       1     4
      / \   / 
     3   5 2   

堆排序

堆排序使用堆的特性来排序元素。首先将所有元素插入到堆中,然后从堆中依次取出根节点,就可以得到一个有序序列。

例如,要对以下数组排序:

[3, 2, 5, 1, 4]

首先将它们插入到堆中:

          5
        /   \
       3     4
      / \   / 
     1   2   

然后依次从堆中取出根节点,就可以得到一个有序序列:

1, 2, 3, 4, 5

示例说明

示例1

以下是一个从小到大的堆排序示例:

#include <iostream>
#include <vector>

// 堆排序
void heap_sort(std::vector<int>& nums)
{
    // 构建初始堆
    int n = nums.size();
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(nums, n, i);

    // 依次取出堆顶元素
    for (int i = n - 1; i >= 0; i--)
    {
        std::swap(nums[0], nums[i]);
        heapify(nums, i, 0);
    }
}

// 堆排序的调整函数
void heapify(std::vector<int>& nums, int n, int i)
{
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && nums[left] > nums[largest])
        largest = left;

    if (right < n && nums[right] > nums[largest])
        largest = right;

    if (largest != i)
    {
        std::swap(nums[i], nums[largest]);
        heapify(nums, n, largest);
    }
}

int main()
{
    std::vector<int> nums{ 3, 2, 5, 1, 4 };

    heap_sort(nums);

    for (auto num : nums)
        std::cout << num << " ";

    return 0;
}

输出结果:

1 2 3 4 5

示例2

以下是一个从大到小的堆排序示例:

#include <iostream>
#include <vector>

// 堆排序
void heap_sort(std::vector<int>& nums)
{
    // 构建初始堆
    int n = nums.size();
    for (int i = n / 2 - 1; i >= 0; i--)
        heapify(nums, n, i);

    // 依次取出堆顶元素
    for (int i = n - 1; i >= 0; i--)
    {
        std::swap(nums[0], nums[i]);
        heapify(nums, i, 0);
    }
}

// 堆排序的调整函数
void heapify(std::vector<int>& nums, int n, int i)
{
    int largest = i;
    int left = 2 * i + 1;
    int right = 2 * i + 2;

    if (left < n && nums[left] < nums[largest])
        largest = left;

    if (right < n && nums[right] < nums[largest])
        largest = right;

    if (largest != i)
    {
        std::swap(nums[i], nums[largest]);
        heapify(nums, n, largest);
    }
}

int main()
{
    std::vector<int> nums{ 3, 2, 5, 1, 4 };

    heap_sort(nums);

    for (auto num : nums)
        std::cout << num << " ";

    return 0;
}

输出结果:

5 4 3 2 1

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++数据结构之堆详解 - Python技术站

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

相关文章

  • [paper reading]|IC-FPS: Instance-Centroid Faster Point Sampling Module for 3D Point-base

    摘要: 本文说首次实现了大规模点云场景中基于点的模型的实时检测(<30ms); 首先指出FPS采样策略进行下采样是耗时的,尤其当点云增加的时候,计算量和推理时间快速增加; 本文提出IC-FPS;包含两个模块:local feature diffusion based background point filter (LFDBF);Centroid In…

    算法与数据结构 2023年4月17日
    00
  • Codeforces Round 867 (Div. 3)

    A. TubeTube Feed 分析: 从所有a[i]+i-1<=t的选择种取个max即可 code: #include <bits/stdc++.h> using namespace std; const int N = 55; int a[N], b[N]; int main() { std::ios::sync_with_stdio…

    算法与数据结构 2023年5月4日
    00
  • AtCoder Beginner Contest 299

    A – Treasure Chest (abc299 a) 题目大意 给定一个包含 |*.的字符串,其中|两个,*一个,问*是否在两个|之间。 解题思路 找到两个|的下标\(l, r\)以及 *的下标\(mid\),看看是否满足 \(l < mid < r\)即可。 神奇的代码 #include <bits/stdc++.h> usi…

    算法与数据结构 2023年4月23日
    00
  • C语言实现数据结构迷宫实验

    C语言实现数据结构迷宫实验攻略 简介 迷宫是计算机图形学中的一个经典问题,也是数据结构和算法中常见的题目。C语言是一种广泛使用的编程语言,具有充分的编程接口和功能,可以方便地实现迷宫算法和数据结构。 本文将详细讲解C语言实现数据结构迷宫实验的完整攻略,让读者能够更加深入地理解迷宫算法和数据结构的应用。 实现步骤 1. 创建迷宫结构体 首先需要创建一个迷宫结构…

    数据结构 2023年5月17日
    00
  • 深入浅析C语言中堆栈和队列

    深入浅析C语言中堆栈和队列 堆栈(Stack) 堆栈是一种先进后出(Last In First Out,LIFO)的线性数据结构,只允许在一端进行插入和删除操作。堆栈在C语言中常用于函数调用时的参数传递、表达式求值和程序中断处理等场景。 实现堆栈的基本操作 下面是堆栈的基本操作,可以用数组来实现: 初始化 #define MAX_SIZE 100 // 假设…

    数据结构 2023年5月17日
    00
  • 带头节点的单链表的思路及代码实现

    带头节点的单链表的思路及代码实现(JAVA) 一、什么是的单链表 ①标准定义 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) +指针(指示后继元素存储位置,元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。) 以上是标准定义不太好让人对单链表有直观…

    算法与数据结构 2023年4月17日
    00
  • Java数据结构及算法实例:插入排序 Insertion Sort

    Java数据结构及算法实例:插入排序 Insertion Sort 算法简介 插入排序是一种简单的排序算法,它的工作方式是每次将一个待排序的元素与前面已经排好序的元素逐个比较,并插入到合适的位置。插入排序的时间复杂度为O(n^2),是一种比较低效的排序算法。 算法实现 以下是使用Java语言实现插入排序算法的代码: public static void in…

    数据结构 2023年5月17日
    00
  • Python中的函数式编程:不可变的数据结构

    Python是一门支持函数式编程的语言。相比于传统的命令式编程,函数式编程更加强调数据的不可变性。本文将介绍如何在Python中使用不可变的数据结构实现函数式编程。 什么是不可变的数据结构? 不可变数据结构是指一旦创建就无法改变的数据结构。在Python中,元组(tuple)是一个典型的不可变数据结构。以下是一个创建元组的示例代码: a_tuple = (1…

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