简单讲解一下数据结构PriorityQueue(优先队列)

优先队列(Priority Queue)是一种抽象数据类型,元素按优先级出队而非插入顺序。每次出队操作会移除并返回优先级最高(或最低)的元素,具体取决于实现方式。

优先队列的实现方式是基于二叉堆,结构是完全二叉树的结构,

时间复杂度:插入(O(log n))、删除(O(log n))、获取队首(O(1)),

完全二叉树的结构:

 

 

能够看到,每一个节点都有两个子节点,其中子节点跟父节点的关系可以用一个公式来表达:

父节点=(子节点-1)/2 

左子节点=(父节点*2)+1

右子节点=(父节点*2)+2

比如0节点的两个子节点是1节点和2节点,1节点和2节点的父节点是0节点。

接下来上代码详细讲解:

我用C#代码举例:

      //优先队列类的泛型需要执定继承IComparable接口,来确保队列内的数据有比较函数
      public class PriorityQueue<T> where T : IComparable<T>

比较重要的字段展示:

        //这里用list来存数据,只是为了方便演示
        private List<T> data;
        
        //构造里创建对应类型的list列表
        public PriorityQueue()
        {
            data = new List<T>();
        }

很重要的进队接口:

        //进队函数
        public void Enqueue(T item)
        {
            data.Add(item);
            //数据列表当前最后一个数据的index
            int dataLastIndex = data.Count - 1;
            while (dataLastIndex > 0)
            {
                //找父节点
                int parentIndex = (dataLastIndex - 1) / 2;
                //CompareTo的值是为了排序从小到大,》0说名父节点更优
                if (data[dataLastIndex].CompareTo(data[parentIndex]) >= 0) break;
                // 当前的数据比父节点的更小,  需要交换父节点数据
                T tmp = data[dataLastIndex]; 
                data[dataLastIndex] = data[parentIndex]; data[parentIndex] = tmp;
                //循环将最小的值赋给父节点,直到根节点的值为最小
                dataLastIndex = parentIndex;
            }
        }

很重要的出队接口:

        public T Dequeue()
        {
            //当前数据列表最后一个数据下表
            int listMaxIndex = data.Count - 1;
            //当前列表第一个数据
            T frontItem = data[0];
            //最后一个数据放到0下标
            data[0] = data[listMaxIndex];
            //列表移除最后一个数据
            data.RemoveAt(listMaxIndex);
            //列表最大的下标更新
            --listMaxIndex;
            //根节点
            int parentIndex = 0;
            while (true)
            {
                //找根节点的左子节点
                int leftIndex = parentIndex * 2 + 1;
                //如果左节点大于数据列表的最大下标说明还没有子节点
                if (leftIndex > listMaxIndex) break;
                //找根节点的右子节点  也可以用  parent*2+2
                int rightIndex = leftIndex + 1;
                //如果右节点下标在列表的最大下标内,
                //并且右子节点的数据比左子节点的数据更优(CampareTo<0),
                //更换左子节点的下标为右子节点的下标
                //这里的leftIndex已经变了含义了,是指在当前子节点里最不优先的节点下标
                if (rightIndex <= listMaxIndex && 
                data[rightIndex].CompareTo(data[leftIndex]) < 0)
                    leftIndex = rightIndex;
                //如果子节点比父节点的数据更优(CampareTo>0),需要更换数据位置
                if (data[parentIndex].CompareTo(data[leftIndex]) <= 0) break;
                T tmp = data[parentIndex]; 
                data[parentIndex] = data[leftIndex]; 
                data[leftIndex] = tmp;
                //这时候更新父节点的下标,
                //以子节点为父节点重复循环内的操作,确保整个队列的数据位置正确
                parentIndex = leftIndex;
            }
            return frontItem;
        }

优先队列比较核心的两个接口大概就是这样的,实现就是按照子节点父节点的方式,去使得整个队列的顺序是按照指定的比较方法去排列,保证每一次进队操作,在对应的子父节点关系里的位置确保正确,每一次出队的元素都是整个队列里的最大值或者最小值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值