Unity C# 优先队列

实现了支持泛型的优先队列,解决Unity官方不提供优先队列的问题。

API

属性和字段 解释
size 队列的长度
capacity 队列的容量
IsEmpty 返回队列是否为空
Top 返回队列第一个元素
枚举 解释
PriorityQueueMode.less 最小优先队列
PriorityQueueMode.equal 只会将相等的排在一起
PriorityQueueMode.greator 最大优先队列
函数 功能
Push 入队一个元素
Pop 出队一个元素
Peek 返回第一个元素
Clear 清空队列

示例

cs 复制代码
PriorityQueue<int> priorityQueue = new PriorityQueue<int>((a, b) => {
            if (a < b) return -1;
            else if (a == b) return 0;
            else if (a > b) return 1;
            return 0;
});

priorityQueue.Push(8);
priorityQueue.Push(9);
priorityQueue.Push(3);
priorityQueue.Push(2);
priorityQueue.Push(7);
priorityQueue.Push(5);
priorityQueue.Push(0);

while (!priorityQueue.IsEmpty) {
    Debug.Log(priorityQueue.Top);
    priorityQueue.Pop();
}

实现

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

namespace YBZ.Algorithm {
    public class PriorityQueue<T> where T : new ()
    {
        public int size;
        public int capacity;
        private T[] elements;

        // 是否为空
        public bool IsEmpty { get => size == 0; }

        /// 返回顶部元素
        public T Top { get => elements[0]; }

        /// 优先队列的模式
        private PriorityQueueMode _comparator;

        public enum PriorityQueueMode {
            less = -1, // 最小优先队列
            equal = 0, // 相等的排在一起
            greater = 1 // 最大优先队列
        }

        /// <summary>
        /// 以CMP(a,b) 为例:
        /// 当a>b时,返回1,表示放右边
        /// 当a==b时,返回0,表示不变
        ///  当a<b时,返回-1,表示放左边
        /// </summary>
        private Func<T,T,int> CMP;
        
        /// <summary>
        /// 构造函数, 必须实现
        /// </summary>
        /// <param name="CMP"></param>
        /// <param name="capacity"></param>
        /// <param name="priorityQueueMode"></param>
        public PriorityQueue(Func<T,T,int> CMP, PriorityQueueMode priorityQueueMode = PriorityQueueMode.less, int capacity = 1) {
            this.CMP = CMP;
            this.size = 0; // 数组索引从0开始
            this.capacity = capacity;
            this.elements = new T[capacity];
            this._comparator = priorityQueueMode;
        }

        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="value"></param>
        public void Push(T value) {
            if (size == capacity) {
                ExpandCapacity();
            }
            elements[size++] = value;

            ShiftUp();
        }

        /// <summary>
        /// 出队
        /// </summary>
        public void Pop() {
            if(size == 0) {
                return;
            }
            size--;
            Swap(ref elements[0], ref elements[size]);

            ShiftDown();
        }

        /// <summary>
        /// 清空队列
        /// </summary>
        public void Clear() {
            size = 0;
        }

        /// <summary>
        /// 返回位于Queue开始处的对象但不将其移除。
        /// </summary>
        /// <returns>返回第一个队列中元素</returns>
        public T Peek() {
            return Top;
        }

        /// <summary>
        /// 扩展队列的容量
        /// </summary>
        private void ExpandCapacity() {
            capacity = Mathf.CeilToInt(capacity * 1.5f);
            T[] temp = new T[capacity];

            for (int i = 0; i < elements.Length; i++) {
                temp[i] = elements[i];
            }
            elements = temp;
        }
        
        // 从下到上 重排序 
        private void ShiftUp() {
            int cur = size - 1 ;
            int parent = ( cur -1 ) >> 2;
            while (cur > 0) 
            {
                if (CMP(elements[cur],elements[parent]) == (int)_comparator) {
                    Swap(ref elements[cur], ref elements[parent]);
                    cur = parent;
                    parent = (cur - 1) >> 2;
                } else break;
            }
        }

        // 从上到下 重排序
        private void ShiftDown() {
            int cur = 0;
            int child = 1;
            while (child < size) {
                if (child + 1 < size && CMP(elements[child +1], elements[child]) == (int)_comparator) {
                    child++;
                }

                if (CMP(elements[child], elements[cur]) == (int)_comparator){

                    Swap(ref elements[child], ref elements[cur]);
                    cur = child;
                    child = cur << 1 + 1;
                } else break;
            }
        }

        /// <summary>
        /// 交换传入的两个元素
        /// </summary>
        /// <param name="lhs"></param>
        /// <param name="rhs"></param>
        private void Swap(ref T lhs,ref T rhs) {
            T temp = lhs;
            lhs = rhs;
            rhs = temp;
        }

        /// <summary>
        /// 返回队列中的所有元素,对于ToString()函数,值类型会返回值,引用类型会返回数据类型
        /// </summary>
        /// <returns></returns>
        public override string ToString() {
            string result = "";
            foreach (var v in elements) {
                result += v.ToString();
            }
            return result;
        }
    }
}
相关推荐
鼎艺创新科技7 小时前
不依赖 UE/Unity:我们如何从零搭建一套国产三维 GIS 渲染引擎
人工智能·算法·unity·游戏引擎·三维电子沙盘
Vae_Mars9 小时前
C#中的delegate委托
开发语言·c#
公子小六13 小时前
基于.NET的Windows窗体编程之WinForms音频控件
windows·microsoft·c#·.net·音视频·winforms
绿浪198414 小时前
c# 结构体 能不能直接封送检测
开发语言·c#
新手unity自用笔记14 小时前
unity基于Socket的网络学习
网络·网络协议·学习·unity·c#·游戏引擎
格林威15 小时前
C#图像像素放大:邻域平均、双线性插值实现像素放大的C#实现代码
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
心前阳光16 小时前
Unity之XR Interaction Toolkit | IPointerDownHandler问题
unity·游戏引擎·xr
用户2986985301420 小时前
C# 实现 PowerPoint 多格式转换:图片、PDF 与 SVG 实战
c#·.net·svg
格林威1 天前
C#图像处理:使用imagemagick实现像素放大水印转换等多种功能
android·开发语言·图像处理·人工智能·计算机视觉·c#·视觉检测
胖纸不争1 天前
Clasp:一个带插件系统的 .NET 10 命令行工具箱
c#·net core