栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

算法日记(九)之优先队列

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

算法日记(九)之优先队列

在前面,我们已经分享完队列的基本内容,现在我们来看看队列衍生出来的一种数据结构——优先队列。优先队列行为像队列,但先出队列的元素不是先进队列的元素,而是队列中优先级最高的元素。优先队列是与堆,树相结合的一种数据结构。下面一起来看看吧

1.概念

优先队列可以插入元素、查询最大值、删除最大值。优先队列其实就是最大堆或最小堆,最大堆可以用来实现最大优先队列,最小堆可以用来实现最小优先队列。用各种堆都可以实现优先队列。优先队列分为几种,下面一起来看看吧

2,分类

(一).STL优先队列

注意:优先队列如果要自定义排序函数,只能用仿函数,不能用普通函数的指针。优先队列是一类容器适配器,特地被设计满足该容器的第一个元素按照没有严格弱序排序,总是所有元素中最大的。

在说STL优先队列前,先介绍一下:priority_queue 

priority_queue 的模板参数:

template ,

class Compare = less > class priority_queue;

T:元素类型。
Container:低层存储容器类型,默认为vector< T >类型。
Compare:两个参数且返回值为bool类型的双参判断式,默认为less< T >判断式。

priority_queue自定数据类型和自定义排序方式

1.使用自定义类型比较关系

即重载数据类型Node的 < 、>运算符,使得Node类型的对象可以使用<,>符号进行比较。代码如下:

struct Node {
    int size;
    int price;
    // 重载<运算符
    bool operator<(const Node &b) const {
        return this->size == b.size ? this->price > b.price : this->size < b.size;
    }
};

int main() {
    priority_queue priorityQueue;
    for (int i = 0; i < 5; i++) {
        priorityQueue.push(Node{i, 5 - i});
    }
    while (!priorityQueue.empty()) {
        Node top = priorityQueue.top();
        cout << "size:" << top.size << " price:" << top.price << endl;
        priorityQueue.pop();
    }
    return 0;
}

输出结果:
size:4 price:1
size:3 price:2
size:2 price:3
size:1 price:4
size:0 price:5

由于priority_queue中默认使用less判断式比较元素大小,因此可以使用对Node类型数据进行 < 符号的重载以满足可以使用less的要求()。假如需要使用priority_queue, greater> priorityQueue;初始化优先队列,还需要对Node的>符号进行重载,代码如下:

struct Node {
    int size;
    int price;
    // 重载>运算符
    bool operator>(const Node &b) const {
        return this->size == b.size ? this->price < b.price : this->size > b.size;
    }
};

2.使用仿函数(函数对象)

使用仿函数(函数对象)作为Compare双参判断式。代码如下:

struct Node {
    int size;
    int price;
};
class Cmp {
public:
    bool operator()(const Node &a, const Node &b) {
        return a.size == b.size ? a.price > b.price : a.size < b.size;
    }
};
int main() {
    priority_queue, Cmp> priorityQueue;
    for (int i = 0; i < 5; i++) {
        priorityQueue.push(Node{i, 5 - i});
    }
    while (!priorityQueue.empty()) {
        Node top = priorityQueue.top();
        cout << "size:" << top.size << " price:" << top.price << endl;
        priorityQueue.pop();
    }
    return 0;
}
输出结果:

size:4 price:1
size:3 price:2
size:2 price:3
size:1 price:4
size:0 price:5
需要注意的是:使用仿函数对优先队列进行自定义排序,需要在声明priority_queue对象时显式地定义Container类型和Compare类型,即:

priority_queue, Cmp> priorityQueue;

3.使用lambda表达式,不是很重要,这里就不多说了

4.函数指针

使用函数指针与3. 使用lambda表达式类似,都是在priority_queue<.,.,Cmp>中定义Compare的类型同时在priorityQueue(cmp)的中输入具体的对象作为参数,不过 这里使用的是函数和函数的指针(地址)而不是lambda表达式对象。例子如下:

bool cmpFun(const Node &a, const Node &b) {
    return a.size == b.size ? a.price > b.price : a.size < b.size;
}
bool (*p)(const Node &, const Node &) = cmpFun;
priority_queue, decltype(*p)> priorityQueue(*p);

实例:

#include
#include
#include
using namespace std;
class cmp
{
public:
    bool operator()(int a, int b)
    {
        return a < b;
    }
};
 
bool cmp2(int a, int b)
{
    return a < b;
}
 
template
void display()
{
    A q;
    q.push(1);
    q.push(3);
    q.push(4);
    q.push(2);
    while (!q.empty())
    {
        cout << q.top();
        q.pop();
    }
    cout << endl;
}
 
int main()
{
    display < priority_queue> >();  //默认大顶堆    
    display < priority_queue , greater> >();//小顶堆
    display < priority_queue , less> >();//大顶堆
    display < priority_queue, cmp>>();//大顶堆
    //display < priority_queue, cmp2>>();  错误
    return 0;
}

输出结果:

4321
1234
4321
4321

二.二叉堆实现优先队列

二叉堆其实就是一种特殊的二叉树(完全二叉树),只不过存储在数组里。(所以我们的排序过程应该是在数组中原地进行的)。一般的链表二叉树,我们操作节点的指针,而在数组里,我们用数组的索引当作指针即可。例子:

#include
#include
using namespace std;
template
bool cmp(T a, T b)
{
    return a < b; //最大堆
}
 
template
void exchange(T* a, T* b)
{
    T tmp = *a;
    *a = *b;
    *b = tmp;
}
 
int LeftChild(int id)
{
    return id * 2;
}
int RightChild(int id)
{
    return id * 2 + 1;
}
int Parent(int id)
{
    return id/2;
}
 
template
void AdjustHeap(T* arr, int rootId, int size)
{
    int largest = rootId, left = LeftChild(rootId), right = RightChild(rootId);
    if (left < size && cmp(arr[largest], arr[left]))largest = left;
    if (right < size && cmp(arr[largest], arr[right]))largest = right;
    if (largest == rootId)return;
    exchange(arr + rootId, arr + largest);
    AdjustHeap(arr, largest, size);
}
 
template
void HeapIncrese(T* arr, int size, int id, T newValue)
{
    arr[id] = newValue;
    while (id > 0 && cmp(arr[Parent(id)], arr[id])) {
        exchange(arr + id, arr + Parent(id));
        id = Parent(id);
    }
}
 
template
void HeapInsert(T* arr, int &size,T value)
{
    HeapIncrese(arr,size+1,size,value);
    size++;
}
 
int g_size;
void Init()
{
    g_size = 0;
}
template
T Top(T* arr)
{
    return arr[0];
}
template
void Push(T* arr, T value)
{
    HeapInsert(arr,g_size,value);
}
template
void Pop(T* arr)
{
    g_size--;
    exchange(arr, arr+g_size);
    AdjustHeap(arr, 0, g_size);
}
 
int main()
{
    int q[10];
    Init();
    Push(q,4);
    Push(q,2);
    Push(q,6);
    Push(q,3);
    Push(q,4);
    Push(q,5);
    cout<     Pop(q);
    cout<     Pop(q);
    cout<     Pop(q);
    cout<     Pop(q);
    cout<     Pop(q);
    cout<     Pop(q);
    cout<     return 0;
}

运行结果:6 5 4 4 3 2 0

三,二项堆实现优先队列。二项堆(Binomial Heap)是二项树(Binomial Tree)的集合

四.线段树实现优先队列

实例:

struct anode
{
    int t;
    int d;
};
int n;
int num[10001],maxx[40001];
struct anode node[10001];
 
void build(int key, int low, int high)//id
{
    if (low == high)
    {
        maxx[key] = low;
        return;
    }
    int mid = (low + high) / 2;
    build(key * 2, low, mid);
    build(key * 2 + 1, mid + 1, high);
    maxx[key] = (num[maxx[key * 2]] > num[maxx[key * 2 + 1]]) ? maxx[key * 2] : maxx[key * 2 + 1];
}
 
void update(int key, int low, int high, int uplace)//id
{
    if (low == high)
    {
        maxx[key] = low;
        return;
    }
    int mid = (low + high) / 2;
    if (uplace <= mid)update(key * 2, low, mid, uplace);
    else update(key * 2 + 1, mid + 1, high, uplace);
    maxx[key] = (num[maxx[key * 2]] > num[maxx[key * 2 + 1]]) ? maxx[key * 2] : maxx[key * 2 + 1];
}
 
int query(int key, int low, int high, int x, int y)//id
{
    if (low == x && high == y)return maxx[key];
    int mid = (low + high) / 2;
    if (mid < x)return query(key * 2 + 1, mid + 1, high, x, y);
    if (mid >= y)return query(key * 2, low, mid, x, y);
    int a = query(key * 2, low, mid, x, mid);
    int b = query(key * 2 + 1, mid + 1, high, mid + 1, y);
    return  (num[a]>num[b]) ? a : b;
}
 
void push(int loc)
{
    num[loc]=node[loc].t; ///根据实际情况修改
    update(1,1,n,loc);
}
void pop(int loc)
{
    num[loc]=0; ///根据实际情况修改
    update(1,1,n,loc);
}
int top()//id
{
    return query(1,1,n,1,n);
}

好啦,关于优先队列的知识就分享到这啦

本贴为博主亲手整理。如有错误,请评论区指出,一起进步。谢谢大家的浏览.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935620.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号