特殊的线性结构--队列

队列也是一种线性结构。有着先进先出的特性。如图

    很显然队列内部的存储结构也是线性表或者链表。好现在考虑线性表,假如用数组存,入队非常简单就是在数组的后面赋值就OK了,但是出队就出现问题了,比如A元素进队 在数组中是a[0]存的现在要出队的数据根据队列先进先出的特性,我们现在要取出a[0],可以很显然直接砍掉数组的前面的元素是不可能的如果调用Array.Copy或者写个算法循环移位的话就存在O(n)的时间复杂度,可是很显然仅仅是一个出队的操作,如果有O(n)的时间复杂度是不划算的所以我们采取了一种策略。

   设置一个头索引front和一个尾索引rear。入队就让rear后移,出队就取出front 然后后移,可以这里又存在一个问题了如果front后移了front前面的空间不是浪费了么?所以这里我们又得采取一种策略那就是循环队列。简单点说rear到达MaxSize的时候 再前移就是回到了0 如图

这样简单点说只需要让front不断的后移动知道它移动到rear就全部出队了 队列就是空的了或者说设置一个count出队就+1出队就-1 count == 0队列就是空的看你怎么理解了

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 栈队列
{
    public class MyQueue<T>
    {
        //队列的最大长度一般不改变,而且固定
        private readonly int MaxSize = 5;

        //数组首元素索引
        int front = 0;
        
        //数组尾元素的下一个的索引
        int rear = 0;

        //书上是用 (rear - front + MaxSize)%MaxSize 这点我觉得不妥欢迎大家对这点留言讨论
        private int count = 0;

        //队列的长度
        public int Count
        {
            //rear 和 front的比较要分情况
            get {
                 //1.rear > front  ___________front_________rear____;
                //2.front > rear ________rear______front________-
                //3.重合
                //都是 
                //不用+1因为rear本身就指向的是尾巴元素的下一个元素(本来要加1的2-4的长度是4-2+1=3)
                return count;
            }
        }

        //我们把队列设置成动态增长的
        T[] nums;

        //初始化内部数组
        public MyQueue()
        {  
            nums = new T[MaxSize];  
        }
       
        public MyQueue(T[] items):this()
        {
            //将每个元素压栈
            foreach (T item in items)
            {
                EnQueue(item);
            }
        }

        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="elem"></param>
        public void EnQueue(T elem)
        {
            //rear如果和front重合了队列就满了
            if (Count >= MaxSize)
            {
                throw new Exception("队列是满的");
            }
            nums[rear] = elem;
            //为了保险怕rear超过MaxSize
            rear = (rear + 1) % MaxSize;
            
            count++;

        }
        /// <summary>
        /// 出队并且返回对首元素
        /// </summary>
        /// <returns></returns>
        public T DeQueue()
        {
            if (count <= 0)
            {
                throw new Exception("队列是空的");
            }
            T data = nums[front];
            //重新设置队列起始位置,循环队列
            front = (front + 1) % MaxSize;
            count--;
            return data;
        }
        /// <summary>
        /// 返回队首的对象但是不将其移除
        /// </summary>
        /// <returns></returns>
        public T Peek()
        {
            if (count <= 0)
            {
                throw new Exception("队列是空的");
            }
            return nums[front];
        }

        /// <summary>
        /// 队列的显示
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            int index = front;
            int length = count;
            //输出length次
            while (length-->0)
            {
                sb.Append(nums[index++ % MaxSize]+" ");     
            }
            return sb.ToString();
        }
    }
}


 

.net框架的源码也是使用的这种循环队列的方式

上篇的栈我没有用链表这次的队列 我也就用链表实现了一下队列 链式队列有个好处出队的时候砍下队头 只需要设置队列头节点的链式关系就OK了 不需要调Array.Copy或者循环移位链式队列代码如下:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 链式队列
{
    class MyQueue<T>
    {
        //队列的最大长度
        int MaxSize = 5;
        //front是个哨兵元素他的.next即为队首值
        QNode<T> front;
        QNode<T> rear;

        //队列的长度
        int count;

        public int Count
        {
            get { return count; }
        }


        public MyQueue()
        {
            //初始化头节点
            rear = front = new QNode<T>();
          
        }

        public MyQueue(T[] nums)
            : this()
        {
            foreach (T item in nums)
            {
                EnQueue(item);
            }
        }

        /// <summary>
        /// 入队
        /// </summary>
        /// <param name="elem"></param>
        public void EnQueue(T elem)
        {
            if (Count >= MaxSize)
            {
                throw new Exception("队列是满的");
            }

            QNode<T> q = new QNode<T>();
            q.data = elem; 
            if (front == null)
            {
                front = q;
                rear = q;
                return;
            }
            rear.next = q;
            rear = q;
            count++;     
        }

        /// <summary>
        /// 出队并返回队首元素
        /// </summary>
        /// <returns></returns>
        public T DeQueue()
        {
            if (Count<= 0)
            {
                throw new Exception("栈是空的");
            }
            QNode<T> q = new QNode<T>();
            //取得队首元素
            q = front.next;
            //获取队首元素的值
            T data = q.data;
            //重新设置链表关系 此时原来q的原来的引用front.next重新指向队首 q会被GC回收
            front.next = q.next;
            count--;
            return data;
        }

        /// <summary>
        /// 取出队列首元素,但是首元素不出队列
        /// </summary>
        /// <returns></returns>
        public T Peek()
        {
            return front.next.data;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            QNode<T> q = front.next;
            while (q != null)
            {
                sb.Append(q.data+" ");
                q = q.next;
            }
            return sb.ToString();
        }
    }
}


测试代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 链式队列
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("请输入测试数组类似5 4 3");
            string[] s = Console.ReadLine().Split(' ');
            int[] nums = new int[s.Length];
            for (int i = 0; i < s.Length; i++)
            {
                nums[i] = Convert.ToInt32(s[i]);
            }
            Console.WriteLine("将测试数组入队");
            MyQueue<int> queue = new MyQueue<int>(nums);
            Console.WriteLine("输出队列");
            Console.WriteLine(queue.ToString());
            Console.WriteLine("将首元素出队并显示");
            Console.WriteLine(queue.Peek());
            Console.WriteLine("将首元素移除并显示队列");
            queue.DeQueue();
            Console.WriteLine(queue.ToString());
            Console.WriteLine("输出队列长度");
            Console.WriteLine(queue.Count);
            Console.WriteLine("再次入队999");
            queue.EnQueue(999);
            //queue.EnQueue(77);
            Console.WriteLine("显示队列");
            Console.WriteLine(queue.ToString());
            Console.Read();
        }
    }
}

结果如图:


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值