Unity--优先级队列

Unity–优先级队列

优先级队列是一种抽象数据类型,类似于常规队列或栈,但它每个元素都有一个与之关联的优先级。在优先级队列中,元素的出队顺序不是简单的先进先出(FIFO),而是基于元素的优先级。具有最高优先级的元素会先出队,而优先级较低的元素会后出队。

工作原理和详细过程

  1. 数据结构
    • 优先级队列通常使用堆(Heap)数据结构来实现,特别是最小堆或最大堆。在最小堆中,堆的根节点包含队列中优先级最高的元素;在最大堆中,根节点包含优先级最低的元素。
  2. 插入元素(Enqueue)
    • 当向优先级队列中插入一个新元素时,该元素被添加到堆的末尾。
    • 然后,通过比较新元素与其父节点的优先级,如果新元素的优先级更高(对于最小堆来说是更小),则与父节点交换位置。
    • 这个过程一直持续到新元素到达正确的位置,或者它成为根节点。
  3. 删除元素(Dequeue)
    • 当从优先级队列中删除一个元素时,总是移除堆的根节点,因为它包含当前队列中优先级最高的元素。
    • 然后,将堆的最后一个元素移动到根节点的位置。
    • 接着,通过比较新根节点与其子节点的优先级,如果子节点的优先级更高,则与具有最高优先级的子节点交换位置。
    • 这个过程一直持续到新根节点到达正确的位置,或者它成为叶节点。
  4. 维护堆属性
    • 在插入和删除操作过程中,为了保持堆的属性,可能需要进行多次节点交换,这些操作称为“堆化”(Heapify)。
    • 插入时进行的堆化称为“上浮”(Heapify Up),而删除时进行的堆化称为“下沉”(Heapify Down)。
  5. 时间复杂度
    • 插入和删除操作的时间复杂度通常是O(log n),其中n是队列中元素的数量。这是因为堆的高度是log n,而插入和删除操作最多需要从根节点移动到叶节点。

应用场景

优先级队列在许多场景中非常有用,例如:

  • 任务调度:根据任务的优先级来调度它们。
  • 数据压缩:例如在霍夫曼编码中使用优先级队列来构建编码树。
  • 图算法:例如在Dijkstra算法中使用优先级队列来选择下一个要处理的节点。

小结

优先级队列是一种基于优先级来处理元素的队列,它通过堆数据结构实现,提供了高效的插入和删除操作。它在处理具有不同优先级的任务或数据时非常有用,是许多算法和数据结构的核心组件。

代码实现

基于C#的优先级队列

// **************************************
// description: 优先级队列
// -*- coding : utf-8 -*-
// @Date      : 2024/08/22
// @Author    : Caron4
// @File      : PriotityQueue.cs
// **************************************

using System;
using System.Collections.Generic;

namespace Utils
{
    // 优先级队列类,使用堆数据结构实现。
    // <typeparam name="T">队列中元素的类型,必须实现IComparable<T>接口。</typeparam>
    public class PriotityQueue<T> where T : IComparable<T>
    {
        private List<T> list = null;
        // 获取队列中元素的数量。
        public int Count { get => list.Count; }

        // 优先级队列的构造函数,队列的初始容量初始化为4
        public PriotityQueue(int capacity = 4)
        {
            list = new List<T>(capacity);
        }


        // 将元素添加到队列中,并保持队列的优先级顺序。
        public void Enqueue(T item)
        {
            list.Add(item);
            HeapifyUp(list.Count - 1);
        }

        // 从队列中移除并返回具有最高优先级的元素。
        public T Dequeue()
        {
            if (list.Count == 0)
            {
                return default;
            }
            T item = list[0];
            int endIndex = list.Count - 1;
            list[0] = list[endIndex];
            list.RemoveAt(endIndex);
            --endIndex;
            HeapifyDown(0, endIndex);

            return item;
        }

        // 返回队列中具有最高优先级的元素,但不从队列中移除它
        public T Peek()
        {
            return list.Count > 0 ? list[0] : default;
        }

        // 返回指定元素在队列中的索引
        public int IndexOf(T t)
        {
            return list.IndexOf(t);
        }

        //  移除指定索引处的元素
        public T RemoveAt(int removeIndex)
        {
            if (list.Count <= removeIndex)
            {
                return default;
            }
            T item = list[removeIndex];
            int endIndex = list.Count - 1;
            list[removeIndex] = list[endIndex];
            list.RemoveAt(endIndex);
            --endIndex;

            if (removeIndex < endIndex)
            {
                int parentIndex = (removeIndex - 1) / 2;
                if (parentIndex > 0 && list[removeIndex].CompareTo(list[parentIndex]) < 0)
                {
                    HeapifyUp(removeIndex);
                }
                else
                {
                    HeapifyDown(removeIndex, endIndex);
                }
            }

            return item;
        }

        // 移除指定索引处的元素
        public T RemoveItem(T t)
        {
            int index = IndexOf(t);
            return index != -1 ? RemoveAt(index) : default;
        }

        // 移除队列中指定的元素
        public void Clear()
        {
            list.Clear();
        }

        //检查队列中是否包含指定元素。
        public bool Contains(T t)
        {
            return list.Contains(t);
        }

        // 查队列是否为空
        public bool IsEmpty()
        {
            return list.Count == 0;
        }

        // 将队列转换为列表
        public List<T> ToList()
        {
            return list;
        }

        //  将队列转换为数组
        public T[] ToArray()
        {
            return list.ToArray();
        }

        // 用于维护队列的优先级顺序,确保新添加的元素被放置在正确的位置。
        void HeapifyUp(int childIndex)
        {
            int parentIndex = (childIndex - 1) / 2;
            while (childIndex > 0 && list[childIndex].CompareTo(list[parentIndex]) < 0)
            {
                Swap(childIndex, parentIndex);
                childIndex = parentIndex;
                parentIndex = (childIndex - 1) / 2;
            }
        }

        //用于维护队列的优先级顺序,确保在移除元素后队列仍然保持正确的顺序。
        void HeapifyDown(int topIndex, int endIndex)
        {
            while (true)
            {
                int minIndex = topIndex;
                int childIndex = topIndex * 2 + 1;
                if (childIndex <= endIndex && list[childIndex].CompareTo(list[topIndex]) < 0)
                    minIndex = childIndex;
                childIndex = topIndex * 2 + 2;
                if (childIndex <= endIndex && list[childIndex].CompareTo(list[minIndex]) < 0)
                    minIndex = childIndex;
                if (topIndex == minIndex) break;
                Swap(topIndex, minIndex);
                topIndex = minIndex;
            }
        }

        // 交换两个数据
        void Swap(int a, int b)
        {
            T temp = list[a];
            list[a] = list[b];
            list[b] = temp;
        }
    }
}

基于c++的优先级队列

#include <iostream>
#include <vector>
#include <algorithm> // for std::swap
#include <stdexcept> // for std::runtime_error
// 优先级队列类
template <typename T>
class PriotityQueue
{
private:
    std::vector<T> heap;
public:
    // 构造函数
    PriotityQueue(int capacity = 4) : heap(capacity) {}
    // 获取队列中元素的数量
    size_t Count() const { return heap.size(); }
    // 将元素添加到队列中
    void Enqueue(const T& item)
    {
        heap.push_back(item);
        HeapifyUp(heap.size() - 1);
    }
    // 从队列中移除并返回具有最高优先级的元素
    T Dequeue()
    {
        if (heap.empty())
            throw std::runtime_error("Queue is empty");
        T item = heap.front();
        std::swap(heap.front(), heap.back());
        heap.pop_back();
        HeapifyDown(0);
        return item;
    }
    // 返回队列中具有最高优先级的元素
    T Peek() const
    {
        if (heap.empty())
            throw std::runtime_error("Queue is empty");
        return heap.front();
    }
    // 返回指定元素在队列中的索引
    int IndexOf(const T& t) const
    {
        auto it = std::find(heap.begin(), heap.end(), t);
        if (it != heap.end())
            return std::distance(heap.begin(), it);
        return -1;
    }
    // 移除指定索引处的元素
    T RemoveAt(int removeIndex)
    {
        if (removeIndex >= heap.size())
            throw std::out_of_range("Index out of range");
        T item = heap[removeIndex];
        std::swap(heap[removeIndex], heap.back());
        heap.pop_back();
        if (removeIndex < heap.size())
        {
            int parentIndex = (removeIndex - 1) / 2;
            if (parentIndex >= 0 && heap[removeIndex] < heap[parentIndex])
                HeapifyUp(removeIndex);
            else
                HeapifyDown(removeIndex);
        }
        return item;
    }
    // 移除指定元素
    void RemoveItem(const T& t)
    {
        int index = IndexOf(t);
        if (index != -1)
            RemoveAt(index);
    }
    // 清空队列
    void Clear() { heap.clear(); }
    // 检查队列中是否包含指定元素
    bool Contains(const T& t) const
    {
        return std::find(heap.begin(), heap.end(), t) != heap.end();
    }
    // 检查队列是否为空
    bool IsEmpty() const { return heap.empty(); }
    // 将队列转换为列表
    std::vector<T> ToList() const { return heap; }
    // 将队列转换为数组
    std::vector<T> ToArray() const { return heap; }
    // 用于维护队列的优先级顺序
    void HeapifyUp(int childIndex)
    {
        int parentIndex = (childIndex - 1) / 2;
        while (childIndex > 0 && heap[childIndex] < heap[parentIndex])
        {
            std::swap(heap[childIndex], heap[parentIndex]);
            childIndex = parentIndex;
            parentIndex = (childIndex - 1) / 2;
        }
    }
    // 用于维护队列的优先级顺序
    void HeapifyDown(int topIndex)
    {
        while (true)
        {
            int minIndex = topIndex;
            int childIndex = topIndex * 2 + 1;
            if (childIndex < heap.size() && heap[childIndex] < heap[topIndex])
                minIndex = childIndex;
            childIndex = topIndex * 2 + 2;
            if (childIndex < heap.size() && heap[childIndex] < heap[minIndex])
                minIndex = childIndex;
            if (topIndex == minIndex) break;
            std::swap(heap[topIndex], heap[minIndex]);
            topIndex = minIndex;
        }
    }
};
// 主函数,用于测试优先级队列
int main()
{
    PriotityQueue<int> pq;
    pq.Enqueue(10);
    pq.Enqueue(5);
    pq.Enqueue(20);
    std::cout << pq.Dequeue() << std::endl; // 应该输出5
    std::cout << pq.Dequeue() << std::endl; // 应该输出10
    return 0;
}

请注意,C++中的模板类需要在使用时指定类型,例如PriotityQueue<int>。此外,C++中的异常处理是通过抛出和捕获异常来完成的,所以我添加了std::runtime_error来处理队列空的情况。其他成员函数的实现也被省略了,如果你使用以上代码的话, 你可以根据上面的模式来实现它们。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值