【C++】优先队列

优先队结构的不同物理结构与常用操作算法

优先队列是一种特殊的队列,队列中的元素具有优先级,每次弹出操作会弹出优先级最高的元素。

优先队列常用的物理结构有:

1. 数组:简单但不高效,插入和删除操作需要移动大量元素,时间复杂度高。

2. 二叉堆:是一种完全二叉树,通常用数组表示。插入和删除操作时间复杂度为O(logn)

3. 二叉搜索树:节点值大于左子树所有节点,小于右子树所有节点。插入和删除操作时间复杂度取决于树的高度,平衡二叉搜索树时间复杂度为O(logn)

常用操作设计:

1. 插入元素:将新元素插入到合适的位置,维持堆的性质。

2. 删除最大/最小元素:删除根节点元素,并调整堆的结构。

3. 获取最大/最小元素:直接返回堆顶元素。

4. 堆大小:返回堆中的元素个数。

5. 堆空:判断堆是否为空。

使用数组结构实现最小堆的代码:

#include <iostream>

using namespace std;

template <typename T>
class PriorityQueue
{
private:
    T *arr;
    int capacity;
    int size;

public:
    PriorityQueue(int cap)  //创造队列
    {
        capacity = cap;
        size = 0;
        arr = new T[cap];
    }

    int getSize()
    {
        return size;
    }

    bool isEmpty()
    {
        return size == 0;
    }

    void insert(T elem)
    {
        if (size == capacity)
        {
            return;
        }
        size++;
        arr[size - 1] = elem;
        int i = size - 1;
        while (i > 0 && arr[i] < arr[(i - 1) / 2])
        {
            swap(arr[i], arr[(i - 1) / 2]);
            i = (i - 1) / 2;
        }
    }

    T getMin() // 返回最小值
    {
        return arr[0];
    }

    T extractMin() // 提取最小值
    {
        if (isEmpty())
        {
            return -1;
        }
        T root = arr[0];
        arr[0] = arr[size - 1];
        size--;
        int i = 0;
        while (2 * i + 1 < size)
        {
            int leftChild = 2 * i + 1;
            int rightChild = 2 * i + 2;
            if (rightChild < size && arr[leftChild] > arr[rightChild])
            {
                leftChild = rightChild;
            }
            if (arr[i] <= arr[leftChild])
            {
                break;
            }
            swap(arr[i], arr[leftChild]);
            i = leftChild;
        }
        return root;
    }

    bool find(T elem)  //查找
    {
        for (int i = 0; i < size; i++)
        {
            if (arr[i] == elem)
            {
                return true;
            }
        }
        return false;
    }

    void deleteElem(T elem)  //删除队列元素
    {
        if (isEmpty() || !find(elem))
        {
            return;
        }
        int i;
        for (i = 0; i < size; i++)
        {
            if (arr[i] == elem)
            {
                break;
            }
        }
        arr[i] = arr[size - 1];
        size--;
        while (i < size && arr[i] < arr[(i - 1) / 2])
        {
            swap(arr[i], arr[(i - 1) / 2]);
            i = (i - 1) / 2;
        }
        while (2 * i + 1 < size)
        {
            int leftChild = 2 * i + 1;
            int rightChild = 2 * i + 2;
            if (rightChild < size && arr[leftChild] > arr[rightChild])
            {
                leftChild = rightChild;
            }
            if (arr[i] <= arr[leftChild])
            {
                break;
            }
            swap(arr[i], arr[leftChild]);
            i = leftChild;
        }
    }
};

int main()
{
    PriorityQueue<int> pq(5);
    pq.insert(3);
    pq.insert(1);
    pq.insert(4);
    cout << pq.getMin() << endl;
    cout << pq.extractMin() << endl;
    cout << pq.getSize() << endl;
    pq.deleteElem(4);
    cout << pq.find(4) << endl;
    return 0;
}

运行结果截图:

最小堆和最大堆只有比较函数不同。最小堆使用 < 比较,最大堆使用 > 比较。所以要将最小堆修改为最大堆,只需要修改比较函数即可。这里对应的修改代码为:

T getMax() // 返回最大值 
{ 
  return arr[0]; 
}

T extractMax() // 提取最大值
{ 
  if (isEmpty()) 
  { 
    return -1; 
  } 
  T root = arr[0]; 
  arr[0] = arr[size - 1]; 
  size--; 
  int i = 0; 
  while (2 * i + 1 < size) 
  { 
    int leftChild = 2 * i + 1; 
    int rightChild = 2 * i + 2; 
    if (rightChild < size && arr[leftChild] < arr[rightChild]) 
    { 
      leftChild = rightChild; 
    }
    if (arr[i] >= arr[leftChild]) 
    { 
      break; 
    } 
    swap(arr[i], arr[leftChild]); 
    i = leftChild; 
  } 
  return root; 
}

可以看到,这里把 < 改为 > ,将 getMin() 改为 getMax(),将 extractMin() 改为 extractMax()。这样,堆中最大的值会在堆顶,所以这就是一个最大堆了。

总结

优先队列是一种抽象数据结构,定义了插入、删除和获取最大/最小元素等操作。堆是一种具体的数据结构,可以用来实现优先队列。堆是一个近似完全二叉树,并且满足堆序性质:父节点的值总是大于(或小于)子节点的值。

二叉堆是一种特殊的堆,完全二叉树,通常用数组表示。二叉堆很适合实现优先队列,时间复杂度为O(logn) 。优先队列强调数据元素的优先级与排序,堆提供了一种数据结构来高效实现这一功能。

参考文献

[1]张铭,王腾蛟,赵海燕编著,《数据结构与算法》,高等教育出版社,2008.6

[2] (美) 乔兹德克(Drozdek, A.) 著 徐丹,吴伟敏 译  C++数据结构与算法(第4版)(国外计算机科学经典教材)清华大学出版社2014-10-01

[3] (美)萨尼 著,王立柱,刘志红 译,数据结构、算法与应用 C++语言描述(原书第2版)机械工业出版社,2015-04-01

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值