数据结构与算法-006.顺序队列

一、队列的概念:

队列(简称作队,Queue)也是一种特殊的线性表,队列的数据元素以及数据元素间的逻辑关系和线性表完全相同,其差别是线性表允许在任意位置插入和删除,而队列只允许在其一端进行插入操作在其另一端进行删除操作。

队列中允许进行插入操作的一端称为队尾,允许进行删除操作的一端称为队头。队列的插入操作通常称作入队列,队列的删除操作通常称作出队列。

下图是一个依次向队列中插入数据元素a0,a1,…,an-1后的示意图:

faf7d1e6-07b1-44bb-9752-5fcc113a0648

上图中,a0是当前 队头数据元素,an-1是当前 队尾数据元素。

为了避免当只有一个元素时,对头和队尾重合使得处理变得麻烦,所以引入两个指针:front指针指向队头元素,rear指针指向队尾元素的下一个位置,这样的话,当front指针等于rear时,此队列不是还剩一个元素,而是空队列。

二、队列的抽象数据类型:

数据集合:

队列的数据集合可以表示为a0,a1,…,an-1,每个数据元素的数据类型可以是任意的类型。

操作集合:

(1)入队列append(obj):把数据元素obj插入队尾。

(2)出队列delete():把队头数据元素删除并由函数返回。

(3)取队头数据元素getFront():取队头数据元素并由函数返回。

(4)非空否isEmpty():非空否。若队列非空,则函数返回false,否则函数返回true。

三、循环顺序队列:

线性表有顺序存储和链式存储,队列是一种特殊的线性表,同样也存在这两种存储方式。我们先来看一下队列的顺序存储。

1、顺序队列的“假溢出”:

607ede1a-91b5-4ac9-8850-07078379fddb

上图中,front指针指向队头元素,rear指针指向队尾元素的下一个位置。图(d)中b、c、d出队后,front指针指向元素e,rear指针在数组外面。假设这个队列的总个数不超过5个,但目前如果接着入队的话,因数组末尾元素已经被占用,再向后加就会产生数组越界的错误,可实际上队列在下标为0、1、2、3、4的地方还是空闲的,我们把这种现象叫做“假溢出”。

2、循环顺序队列:
所以解决假溢出的办法就是后面满了,就再从头开始,也就是头尾相接的循环。我们把队列的这种逻辑上首尾相连的顺序存储结构称为循环队列。
在这里插入图片描述

如何判断循环队列究竟是空的还是满的:

现在问题又来了,我们之前说,空队列时,front指针等于rear指针,那么现在循环队列满的时候,也是front等于rear,那么如何判断循环队列究竟是空的还是满的?有如下办法:

办法1:设置一个标志位flag。初始时置flag=0;每当入队列操作成功就置flag=1;每当出队列操作成功就置flag=0。则队列空的判断条件为:rear == front && tag==0;队列满的判断条件为:rear = = front && tag= =1。
办法2:保留一个元素的存储空间。此时,队列满时的判断条件为 (rear + 1) % maxSize == front;队列空的判断条件还是front == rear。
办法3:设计一个计数器count,统计队列中的元素个数。此时,队列满的判断条件为:count > 0 && rear == front ;队列空的判断条件为count == 0。

下面是具体代码的实现
实现队列方法的接口:IQueue.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace 队列
{
    interface IQueue<T>//泛型接口,因为不确定是什么类型的
    {
        int Count { get; }
        int GetLength();
        bool IsEmpty();
        void Clear();
        void Enqueue(T item);
        T Dequeue();
        T Peek();
    }
}

实现顺序队列方法的类:SeqQueue.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace 队列
{
    class SeqQueue<T> : IQueue<T>
    {
        private T[] data;
        private int count;//表示当前有多少个元素;
        private int front;//队首指标=队首元素索引-1
        private int rear;//队尾指标=队尾索引

        //构造方法,初始化容量
        public SeqQueue(int size)
        {
            data = new T [size];
            count = 0;
            front = -1;
            rear = -1;
        }

        public SeqQueue() : this(10)
        {

        }

        public int Count
        {
            get { return count;}
            
        }


        public void Clear()
        {
            count = 0;
            front = rear = -1;
        }

        //出队
        public T Dequeue()
        {
            if (count > 0)
            {
                T temp = data[front + 1];
                front++;
                count--;
                return temp;

            }
            else
            {
                Console.WriteLine("队列为空,无法取得队首的数据");
                return default(T);
            }
        }

        //入队
        public void Enqueue(T item)
        {
            if (count == data.Length)
            {
                Console.WriteLine("队列已满,不可以再添加新的数据");
            }
            else//当有空间可存的时候
            {
                if (rear == data.Length - 1)//当rear位于队列的最后一个索引的时候,此时rear又循环到了第一个索引
                {
                    data[0] = item;
                    rear = 0;
                    count++;
                }
                else
                {
                    data[rear + 1] = item;
                    rear++;
                    count++;

                }
            }
        }

        public int GetLength()
        {
            return count;
        }

        public bool IsEmpty()
        {
            return count == 0;
        }

        public T Peek()
        {
            //T temp = data[front + 1];
            //return temp;
            return data[front + 1];
        }
    }
}

测试:Program.cs

using System;
using System.Collections;
using System.Collections.Generic;

namespace 队列
{
    class Program
    {
        static void Main(string[] args)
        {
            //1.使用BCL中的队列
            //Queue<int> queue=new Queue<int>();
            //12使用我们自己的队列方法
            IQueue<int> queue=new SeqQueue<int>();

            //入队(添加数据)
            queue.Enqueue(23);//队首
            queue.Enqueue(45);
            queue.Enqueue(78);
            queue.Enqueue(24);//队尾

            Console.WriteLine("添加了23, 45 67 89之后队列的大小为:"+queue.Count);
             //出队(取得队首的数据,并删除)
            int i = queue.Dequeue();
            Console.WriteLine("取得队首的数据为:"+i);
            Console.WriteLine("出队之后队列的大小为:"+queue.Count);
            int j = queue.Peek();
            Console.WriteLine("Peek得到的结果是:"+j);
            Console.WriteLine("Peek之后队列的大小为::"+queue.Count);
            queue.Clear();
            Console.WriteLine("CLear之后队列的大小:"+queue.Count);
            Console.ReadKey();
        }
    }
}

运行结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值