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日

相关文章

  • 栈(Stack)

    概述 栈就是一种 只允许在表尾进行插入和删除操作 的 线性表 栈的特点 先进后出 ,在表尾进行插入和删除操作 数组实现栈 crown crown:使用bottom来确定栈顶所在数组的下标,默认为 -1 空栈 当空栈时 ,crown = -1 栈是否为空 当 crown = -1 时 ,栈为空 ,不能 遍历 ,出栈 , 获取栈顶元素 栈是否已满 当 crown…

    算法与数据结构 2023年4月19日
    00
  • 详解Java实现数据结构之并查集

    详解Java实现数据结构之并查集 简介 并查集是一种基于树型结构的数据结构,主要用于解决一些不交集问题。它支持两个操作: 合并两个元素所在的集合 判断两个元素是否在同一个集合中 在并查集中,每个节点都有一个指向其父节点的指针。如果一个节点的指针指向它本身,说明它是一个集合的根节点。 实现 我们用一个int类型的数组parent来表示每个节点的父节点。初始时,…

    数据结构 2023年5月17日
    00
  • Codeforces Round 868 Div 2

    A. A-characteristic (CF 1823 A) 题目大意 要求构造一个仅包含\(1\)和 \(-1\)的长度为 \(n\)的数组 \(a\),使得存在 \(k\)个下标对 \((i, j), i < j\)满足 \(a_i \times a_j = 1\)。 解题思路 当有\(x\)个 \(1\), \(y\)个 \(-1\)时,其满足…

    算法与数据结构 2023年4月30日
    00
  • C++数据结构哈希表详解

    C++数据结构哈希表详解 哈希表(Hash Table)是一种非常重要的数据结构,用于实现字典等各种应用。哈希表将关键字映射到一个固定大小的数据集合中,以支持常数时间复杂度的插入、查找和删除操作。哈希表的核心思想是将关键字通过哈希函数(Hash Function)映射到数据集合中的一个索引位置,哈希函数需要满足良好的散列性质,使得关键字能够均匀地散布在数据集…

    数据结构 2023年5月17日
    00
  • C++数据结构之红黑树的实现

    《C++数据结构之红黑树的实现》是一篇介绍红黑树实现的文章,通过本文,你可以了解到什么是红黑树以及如何实现红黑树。 什么是红黑树 红黑树是一种自平衡的二叉查找树,它具有良好的平衡性和查找性能。红黑树可以在O(log n)的时间内完成查找、插入和删除操作。 红黑树的一个重要性质是它的任何一个节点都有一个颜色(红色或黑色)属性。在插入、删除操作中,需要通过一定的…

    数据结构 2023年5月17日
    00
  • C语言 数据结构堆排序顺序存储(升序)

    C语言 数据结构堆排序顺序存储(升序)攻略 1. 堆排序概述 堆排序是一种常见的排序算法,通过构建最大堆或最小堆来实现排序。本文介绍的是使用顺序存储方式实现的最大堆排序,也就是升序排序。 2. 最大堆的定义和实现 最大堆指的是堆结构中父节点的值大于子节点的值,根节点的值最大。对于一棵完全二叉树,若父节点的下标为i,则其左子节点的下标为2i+1,右子节点的下标…

    数据结构 2023年5月17日
    00
  • 简单讲解哈希表

    哈希表(Hash Table),也被称为散列表,是一种高效的数据结构,它可以在O(1)的时间复杂度下完成插入、删除、查找等基本操作。哈希表是通过将关键字映射到一个固定大小的表中来实现的,这个映射函数被称为哈希函数。 什么是哈希函数 哈希函数是将任意长度的输入值(也称为“键”或“关键字”)映射为固定大小的输出值(也称为“哈希值”或“散列”)。哈希函数必须将不同…

    数据结构 2023年5月17日
    00
  • Java数据结构之堆(优先队列)的实现

    Java 数据结构之堆(优先队列)的实现 什么是堆(优先队列) 堆(Heap)是一种数据结构,使用数组实现。堆分为小根堆和大根堆,大根堆满足父节点值大于子节点,小根堆则相反。堆通常被用来实现优先队列(Priority Queue)。 优先队列(Priority Queue)是一个能够让用户迅速查找到队列中最小值(或最大值)的抽象数据类型(ADT)。优先队列通…

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