首页 > 编程语言 >[数据结构和算法] 堆/优先队列的实现

[数据结构和算法] 堆/优先队列的实现

时间:2023-10-02 18:11:44浏览次数:35  
标签:parent 队列 tree son int 算法 数据结构 86 节点

预备知识

  • 完全二叉树可以用数组表示
    • 从下标0开始存储数据:左子节点 = 2 * 父节点 + 1右子节点 = 2 * 父节点 + 2
    • 从下标1开始存储数据:左子结点 = 2 * 父节点右子节点= 2 * 父节点 + 1
    • 大根堆:父节点的值大于等于左右子节点的值;
    • 小根堆:父节点的值小于等于左右子节点的值;

【注】看不懂的没必要往下了~

示例:大根堆的实现

C++实现:(实际上就是C++中的优先队列容器)

#include <bits/stdc++.h>
using namespace std;
namespace chasemeng {
    template<typename T>
    class priority_queue {
    public:
        // 插入元素:添加到树的末尾,然后上浮
        void push(T& val) {
            _tree.push_back(val);
            // === 上浮 ===
            int son = size() - 1;
            // 遍历父节点
            for (int i = (son - 1) / 2; i >= 0; i = (i - 1) / 2) {
                if (_tree[son] <= _tree[i]) {
                    break;
                }
                swap(_tree[son], _tree[i]);
                son = i;
            }
        }
        // 弹出堆顶元素:将最后一个元素置换到堆顶,然后下沉该元素
        void pop() {
            swap(_tree.front(), _tree.back());
            _tree.pop_back();
            if (_tree.empty()) {
                return;
            }
            // 调整元素
            int left = 0, right = size() - 1;
            int parent = left;
            // 遍历子节点
            for (int i = 2 * left + 1; i <= right; i = 2 * i + 1) {
                if (i < right && _tree[i] < _tree[i + 1]) {
                    ++i;
                }
                if (_tree[parent] >= _tree[i]) {
                    break;
                }
                swap(_tree[parent], _tree[i]);
                parent = i;
            }
        }
        // 获取堆顶元素
        T top() {
            if (this->size() <= 0) {
                cout << "完蛋了" << endl;
                throw "完蛋了";
            }
            return _tree.front();
        }
        // 是否为空
        bool empty() {return _tree.empty();}
        // 获取元素个数
        int size() {return _tree.size();}
        
    private:
        vector<T> _tree;
    };
}

【注】小根堆的实现基本不用怎么改动,自己思考一下即可。

测试

int main() {
    srand((unsigned)time(NULL));
    chasemeng::priority_queue<int> pque;
    for (int i = 0; i < 20; ++i) {
        int num = rand() % 100;
        cout << num << " \n"[i == 20 - 1];
        pque.push(num);
    }
    while (!pque.empty()) {
        cout << pque.top() << " ";
        pque.pop();
    }
    return 0;
}

结果

执行完成,耗时:0 ms
76 31 86 80 69 7 71 31 28 95 84 97 63 56 24 59 71 86 97 40
97 97 95 86 86 84 80 76 71 71 69 63 59 56 40 31 31 28 24 7 

完整代码

#include <bits/stdc++.h>
using namespace std;
namespace chasemeng {
    template<typename T>
    class priority_queue {
    public:
        // 插入元素:添加到树的末尾,然后上浮
        void push(T& val) {
            _tree.push_back(val);
            // === 上浮 ===
            int son = size() - 1;
            // 遍历父节点
            for (int i = (son - 1) / 2; i >= 0; i = (i - 1) / 2) {
                if (_tree[son] <= _tree[i]) {
                    break;
                }
                swap(_tree[son], _tree[i]);
                son = i;
            }
        }
        // 弹出堆顶元素:将最后一个元素置换到堆顶,然后下沉该元素
        void pop() {
            swap(_tree.front(), _tree.back());
            _tree.pop_back();
            if (_tree.empty()) {
                return;
            }
            // 调整元素
            int left = 0, right = size() - 1;
            int parent = left;
            // 遍历子节点
            for (int i = 2 * left + 1; i <= right; i = 2 * i + 1) {
                if (i < right && _tree[i] < _tree[i + 1]) {
                    ++i;
                }
                if (_tree[parent] >= _tree[i]) {
                    break;
                }
                swap(_tree[parent], _tree[i]);
                parent = i;
            }
        }
        // 获取堆顶元素
        T top() {
            if (this->size() <= 0) {
                cout << "完蛋了" << endl;
                throw "完蛋了";
            }
            return _tree.front();
        }
        // 是否为空
        bool empty() {return _tree.empty();}
        // 获取元素个数
        int size() {return _tree.size();}
        
    private:
        vector<T> _tree;
    };
}
int main() {
    srand((unsigned)time(NULL));
    chasemeng::priority_queue<int> pque;
    for (int i = 0; i < 20; ++i) {
        int num = rand() % 100;
        cout << num << " \n"[i == 20 - 1];
        pque.push(num);
    }
    while (!pque.empty()) {
        cout << pque.top() << " ";
        pque.pop();
    }
    return 0;
}

【注】自己测试没有问题,如果有bug,请反馈一下~

标签:parent,队列,tree,son,int,算法,数据结构,86,节点
From: https://www.cnblogs.com/chasemeng/p/17740297.html

相关文章

  • 【数据结构】2.栈和队列
    1.栈1.1栈的抽象父类#pragmaoncetemplate<classT>classStack{public://析构函数virtual~Stack(){}//栈是否为空virtualboolempty()const=0;//栈的大小virtualintsize()const=0;//栈顶元素virtualT&top()=0......
  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    二、用go语言,说明如何在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。要求PUSH和POP操作的运行时间为O(1)。文心一言:在这个问题中,我们要在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。这......
  • 基础数据结构:数组实现的单链表(静态链表)、双链表
    1、单链表(静态链表)以AcWing.826为例,题目要求如下:实现一个单链表,链表初始为空,支持三种操作:向链表头插入一个数;删除第k个插入的数后面的数;在第k个插入的数后插入一个数。现在要对该链表进行M次操作,进行完所有操作后,从头到尾输出整个链表。注意:题目中第k个插入的数并不是指当......
  • 文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    二、用go语言,说明如何在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。要求PUSH和POP操作的运行时间为O(1)。文心一言:在这个问题中,我们要在一个数组A[1..n]中实现两个栈,使得当两个栈的元素个数之和不为n时,两者都不会发生上溢。......
  • 雷达到达角估计算法3DFFT,DBF,MUSIC,Capon的原理、对比、各自的优势
    雷达到达角估计算法3DFFT,DBF,MUSIC,Capon的原理、对比、各自的优势雷达到达角估计是雷达信号处理中的一个重要问题,旨在确定来自目标的雷达信号的到达角度。雷达到达角估计算法可以分为时域方法和频域方法两种类型。其中,频域方法可以进一步分为基于阵列信号处理的方法和基于普通雷达......
  • 选择排序算法:简单但有效的排序方法
    在计算机科学中,排序算法是基础且重要的主题之一。选择排序(SelectionSort)是其中一个简单但非常有用的排序算法。本文将详细介绍选择排序的原理和步骤,并提供Java语言的实现示例。选择排序的原理选择排序的核心思想是不断地从待排序的元素中选择最小的元素,然后将其放置在已排序部分的......
  • [算法]按位异或^的种种玩法
    本文使用C语言什么是按位异或^首先将不同数制的数写成二进制,例如9->0b1001.然后最末位对齐,依次按位异或.规则:0^0=0;1^1=0;1^0=1推论:任意整数x,都有0^x=x;x^x=0\来看看应用寻找一个单身狗数像[1,3,2,2,3]这样除了某一个数1,剩下的数字都是成......
  • [算法]双指针的种种应用
    本文使用C语言Q:为什么要用双指针?A:因为通过使用双指针可以使算法的时间复杂度降低(或者降低遍历次数),有时也能降低空间复杂度分类根据双指针的用法,可分为前后双指针,头尾双指针,快慢双指针.....前后双指针应用一删除排序数组中的重复项要求:原地删除,并返回新数组的......
  • 【数据结构】串
    串串的顺序实现简单的模式匹配算法KMP算法KMP算法的进一步优化串的顺序实现初始化#defineMaxSize50typedefcharElemType;//顺序存储表示typedefstruct{ElemTypedata[MaxSize];intlength;}SString;/***初始化串*/voidInitString(SString*string)......
  • 【数据结构】线性表
    线性表顺序表链式存储单链表双链表知识目录顺序表概念:用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。特点:逻辑上相邻的数据元素,物理次序也是相邻的。只要确定好了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以线性表的顺序存......