Data Structures in C++:堆和堆排序

本文深入探讨了堆数据结构的概念,包括大顶堆和小顶堆,以及它们在堆排序算法中的应用。同时,文章提供了详细的堆排序代码实现,并介绍了C++11中priority_queue容器的工作原理及使用方法。


堆 Heap 这种数据结构其实就是一颗 “完全二叉树”,每个节点的值总是不大于或不小于其父节点的值:一棵深度为k的有n个结点的二叉树,对树中的结点按从上至下、从左到右的顺序进行编号,如果编号为i(1≤i≤n)的结点与满二叉树中编号为i的结点在二叉树中的位置相同,则这棵二叉树称为完全二叉树。一棵深度为k且有 个结点的二叉树称为 “满二叉树”。
在这里插入图片描述

堆的分类:

  • 大顶堆:每个节点的值都大于或等于其子节点的值
  • 小顶堆:每个节点的值都小于或等于其子节点的值
    在这里插入图片描述

大顶堆和小顶堆都可以用来“从小到大”或“从大到小”排序,一般使用大顶堆。


堆的代码实现

堆就是一颗完全二叉树,中间没有空洞,因此可以使用内存连续的数组或动态数组来实现。以大顶堆为例。

先将堆中结点的序号和数组索引进行对应:(与层次遍历类似)
在这里插入图片描述
显然,每对父子结点在数组中的索引存在数学关系:

  • 索引为 t t t 的结点,其父结点索引为 ( t − 1 ) / 2 (t-1)/2 (t1)/2
  • 索引为 t t t 的结点,其左孩子索引为 t × 2 + 1 t×2+1 t×2+1,右孩子索引为 t × 2 + 2 t×2+2 t×2+2

插入操作:push

  • 先将元素插入到最后一个结点
  • 由此逐层向上渗透:若比父结点大,就交换
    在这里插入图片描述

删除操作:pop

  • 先将根节点删除,替换为最后一个结点
  • 由此逐层向下渗透:若比左右结点小,就和bigger交换
    在这里插入图片描述

模板类代码:

#pragma once
#include <vector>

template<typename T>
class MaxHeap
{
public:
    MaxHeap() {}
    ~MaxHeap() {}
    void push(T& x);
    void pop();
    bool empty() const;
    const T& top() const;

//private:
    std::vector<T> heap;
};

template<typename T>
inline void MaxHeap<T>::push(T& x)
{
    // 添加元素
    heap.push_back(x);
    // 向上渗透
    int index = heap.size() - 1;
    while (index > 0)
    {
        int parent = (index - 1) / 2;
        if (heap[parent] >= x) break;
        heap[index] = heap[parent];
        index = parent;
    }
    heap[index] = x;
}

template<typename T>
inline void MaxHeap<T>::pop()
{
    // 替换根结点
    T x = heap[0] = heap[heap.size() - 1];
    heap.pop_back();
    if (heap.empty()) return;
    // 向下渗透
    int index = 0;
    while (index * 2 + 1 < heap.size()) // 左子结点存在
    {
        int larger_child;
        int l_child = index * 2 + 1;
        int r_child = index * 2 + 2;
        if (r_child < heap.size() && heap[r_child] >= heap[l_child])  // 右子结点存在
        {
            larger_child = r_child;
        }
        else
        {
            larger_child = l_child;
        }
        if (x > heap[larger_child])   // 截止
            break;
        heap[index] = heap[larger_child];
        index = larger_child;
    }
    heap[index] = x;
}

template<typename T>
inline bool MaxHeap<T>::empty() const
{
    return heap.empty();
}

template<typename T>
inline const T& MaxHeap<T>::top() const
{
    return heap[0];
}

堆排序

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏、最好、平均时间复杂度均为O(nlogn),是不稳定排序。

基本思想:

  1. 构造一个空的大顶堆;
  2. 将待排序序列push进入大顶堆,此时,整个序列的最大值就是堆顶的根节点
  3. 将大顶堆的根节点反复读出、删除即得到有序序列

堆排序测试代码:

#include <iostream>
#include "MaxHeap.h"

using namespace std;

int main(int argc, char* argv[])
{
    int a[10] = { 11,3,25,177,299,0,52,74,86,308 };
    int n = 10;

    MaxHeap<int> heap;
    for (auto x : a)
    {
        heap.push(x);
    }

    cout << "从小到大:";
    for (int i = n-1; i >=0; i--)
    {
        a[i] = heap.top();
        heap.pop();
    }

    //cout << "从大到小:";
    //for (int i = 0; i < n; i++)
    //{
    //    a[i] = heap.top();
    //    heap.pop();
    //}

	// 输出排序结果
    for (int i = 0; i < n; i++)
        cout << a[i] << ", ";
    cout << endl;

    return 0;
}

C++11 中的堆 priority_queue

优先队列是一种容器适配器,默认第一个元素总是保持最大,内部类似于堆结构。提供常数时间的最大元素(默认)查找,对数代价的插入与删除(二分法)。

成员函数:

  • top 访问队头元素
  • empty 队列是否为空
  • size 返回队列内元素个数
  • push 插入元素到队尾 (并排序)
  • emplace 原地构造一个元素并插入队列(并排序)
  • pop 弹出队头元素
  • swap 交换内容

定义:
priority_queue<Type, Container, Functional>

  • Type 就是数据类型
  • Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector)
  • Functional 就是比较的方式,当需要用自定义的数据类型时才需要传入

这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆。

小顶堆定义:
priority_queue < int, vector<int>, greater<int> > q;

### 回答1: 《数据结构与算法分析:C语言描述》这本书是一本非常经典的计算机科学教材,主要介绍了C语言下的数据结构算法分析。这本书涵盖了很多基础的数据结构算法,比如链表、、排序搜索等等。通过学习这些知识,读者能够深入了解计算机科学的基础理论实践技能。 从数据结构的角度来看,这本书深入浅出地介绍了线性数据结构树状数据结构,并讲解了如何通过操作这些数据结构来进行高效的数据处理。例如,在数组中进行快速查找插入、在链表中进行高效地增删操作、在树中进行高效的搜索等等。 从算法的角度来看,这本书介绍了很多著名的算法,比如递归、贪心算法、分治算法、动态规划算法等等。这些算法是计算机科学中非常重要的基础算法,它们在各个领域都有着广泛的应用。 总之,《数据结构与算法分析:C语言描述》这本书是计算机科学领域的经典教材,对于想要深入了解数据结构算法分析的读者来说,这本书是不可或缺的。 ### 回答2: 《Data Structures and Algorithm Analysis in C》是一本关于数据结构算法的经典教材,作者是Mark Allen Weiss。该书主要分为两部分,第一部分介绍了C语言的编程基础,包括语言特性、指针、内存管理等;第二部分则涵盖了数据结构算法的各种概念、技术实现方法。 本书首先介绍了常用数据结构,包括数组、链表、栈、队列、、二叉树等,然后讲解了各种经典算法,如排序、查找、图论算法等。在讲解数据结构算法的同时,作者对每个主题都提供了C语言代码实现,并给出了能够测试代码的样例数据。此外,书中还包括大量习题实验,帮助读者深入理解熟练掌握各种数据结构算法。 该书不仅适合作为计算机科学工程专业的本科生研究生的教材,也适合程序员进一步学习提高自己的算法数据结构能力。通过学习本书,读者将会掌握各种数据结构算法的设计实现方法,同时也能够提高自己的编程能力提高代码的效率。 ### 回答3: 《Data Structures and Algorithm Analysis in C》(C语言数据结构与算法分析)是一本经典的计算机科学教材,由Mark Allen Weiss撰写。本书以C语言为基础,介绍了常见的数据结构算法,并涉及到其分析实现。 本书分为四个部分。第一部分主要是C语言的基础知识算法分析的基本原则。第二部分介绍常见的数据结构,如数组、链表、树、图等,旨在帮助读者了解这些数据结构的实现应用。第三部分是算法设计分析的内容,讲述了排序、查找、字符串匹配等经典问题,涉及到算法的复杂度效率等方面。最后,第四部分提供了一些高级话题,如红黑树、哈希表等。 这本书的特点是内容包罗万象,深入浅出,除了C语言的基本知识外,还讲述了许多实用的技巧方法。由于对数据结构算法的深入掌握是计算机科学人员必备的技能,因此该书可以作为各种程序设计相关课程、面试准备算法实践的重要参考。 总之,这本书是数据结构算法领域的经典教材之一,对于任何想要提高编程能力算法思维的人都是一本必读之作。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值