源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

算法系列15天速成 第九天 队列

  • 时间:2022-07-08 05:25 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:算法系列15天速成 第九天 队列
一:概念           队列是一个”先进先出“的线性表,牛X的名字就是“First in First Out(FIFO)”,生活中有很多这样的场景,比如读书的时候去食堂打饭时的”排队“。当然我们拒绝插队。 二:存储结构          前几天也说过,线性表有两种”存储结构“,① 顺序存储,②链式存储。当然“队列”也脱离不了这两种服务,这里我就分享一下“顺序存储”。      顺序存储时,我们会维护一个叫做”head头指针“和”tail尾指针“,分别指向队列的开头和结尾。 [img]http://files.jb51.net/file_images/article/201311/201311151612399.png[/img] 代码段如下:
[u]复制代码[/u] 代码如下:
#region 队列的数据结构     /// <summary> /// 队列的数据结构 /// </summary> /// <typeparam name="T"></typeparam>     public class SeqQueue<T>     {         private const int maxSize = 100;         public int MaxSize         {             get { return maxSize; }         }         /// <summary> /// 顺序队列的存储长度 /// </summary>         public T[] data = new T[maxSize];         //头指针         public int head;         //尾指针         public int tail;     }     #endregion
三:常用操作       队列的操作一般分为:       ①: 初始化队列。       ②:   出队。       ③: 入队。       ④: 获取队头。       ⑤: 获取队长。 1:初始化队列         这个很简单,刚才也说过了,队列是用一个head和tail的指针来维护。分别设置为0即可。 2:出队        看着“队列”的结构图,大家都知道,出队肯定跟head指针有关,需要做两件事情,        第一: 判断队列是否为空,这个我想大家都知道。        第二: 将head头指针向后移动一位,返回head移动前的元素,时间复杂度为O(1)。 [img]http://files.jb51.net/file_images/article/201311/2013111516123910.png[/img] 代码段如下:
[u]复制代码[/u] 代码如下:
#region 队列元素出队         /// <summary> /// 队列元素出队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public T SeqQueueOut<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,不能进行出队操作");             var single = seqQueue.data[seqQueue.head];             //head指针自增             seqQueue.data[seqQueue.head++] = default(T);             return single;         }         #endregion
3:入队       这个跟”出队“的思想相反,同样也是需要做两件事情。       第一:判断队列是否已满。       第二:将tail指针向后移动一位,时间复杂度为O(1)。 代码段如下:
[u]复制代码[/u] 代码如下:
#region 队列元素入队         /// <summary> /// 队列元素入队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <param name="data"></param> /// <returns></returns>         public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)         {             //如果队列已满,则不能进行入队操作             if (SeqQueueIsFull(seqQueue))                 throw new Exception("队列已满,不能入队操作");             //入队操作             seqQueue.data[seqQueue.tail++] = data;             return seqQueue;         }         #endregion
4: 获取队头        知道”出队“和”入队“的原理,相信大家都懂的如何进行”获取队头“操作,唯一不一样的就是        他是只读操作,不会破坏”队列“结构,时间复杂度为O(1)。   代码段如下:
[u]复制代码[/u] 代码如下:
#region 获取队头元素         /// <summary>         /// 获取队头元素         /// </summary>         /// <typeparam name="T"></typeparam>         /// <param name="seqQueue"></param>         /// <returns></returns>         public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,不能进行出队操作");             return seqQueue.data[seqQueue.head];         }         #endregion
5: 获取队长        大家都知道,我们是用数组来实现队列,所以千万不要想当然的认为数组长度是XXX,        我们维护的是一个head和tail的指针,所以长度自然就是tail-head咯,时间复杂度为O(1)。 [img]http://files.jb51.net/file_images/article/201311/2013111516123912.png[/img] 代码段如下:
[u]复制代码[/u] 代码如下:
/// <summary> /// 获取队列长度 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public int SeqQueueLen<T>(SeqQueue<T> seqQueue)         {             return seqQueue.tail - seqQueue.head;         }
然后上一下总的运行代码:
[u]复制代码[/u] 代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SeqQueue {     public class Program     {         static void Main(string[] args)         {             SeqQueue<Student> seqQueue = new SeqQueue<Student>();             SeqQueueClass queueManage = new SeqQueueClass();             Console.WriteLine("目前队列是否为空:" + queueManage.SeqQueueIsEmpty(seqQueue) + "\n");             Console.WriteLine("将ID=1和ID=2的实体加入队列");             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 1, Name = "hxc520", Age = 23 });             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 2, Name = "一线码农", Age = 23 });             Display(seqQueue);             Console.WriteLine("将队头出队");             //将队头出队             var student = queueManage.SeqQueueOut(seqQueue);             Display(seqQueue);             //获取队顶元素             student = queueManage.SeqQueuePeek(seqQueue);             Console.Read();         }         //展示队列元素         static void Display(SeqQueue<Student> seqQueue)         {             Console.WriteLine("******************* 链表数据如下 *******************");             for (int i = seqQueue.head; i < seqQueue.tail; i++)                 Console.WriteLine("ID:" + seqQueue.data[i].ID +                                   ",Name:" + seqQueue.data[i].Name +                                   ",Age:" + seqQueue.data[i].Age);             Console.WriteLine("******************* 链表数据展示完毕 *******************\n");         }     }     #region 学生数据实体     /// <summary> /// 学生数据实体 /// </summary>     public class Student     {         public int ID { get; set; }         public string Name { get; set; }         public int Age { get; set; }     }     #endregion     #region 队列的数据结构     /// <summary> /// 队列的数据结构 /// </summary> /// <typeparam name="T"></typeparam>     public class SeqQueue<T>     {         private const int maxSize = 100;         public int MaxSize         {             get { return maxSize; }         }         /// <summary> /// 顺序队列的存储长度 /// </summary>         public T[] data = new T[maxSize];         //头指针         public int head;         //尾指针         public int tail;     }     #endregion     #region 队列的基本操作     /// <summary> /// 队列的基本操作 /// </summary>     public class SeqQueueClass     {         #region 队列的初始化操作         /// <summary> /// 队列的初始化操作 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param>         public SeqQueue<T> SeqQueueInit<T>(SeqQueue<T> seqQueue)         {             seqQueue.head = 0;             seqQueue.tail = 0;             return seqQueue;         }         #endregion         #region 队列是否为空         /// <summary> /// 队列是否为空 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public bool SeqQueueIsEmpty<T>(SeqQueue<T> seqQueue)         {             //如果两指针重合,说明队列已经清空             if (seqQueue.head == seqQueue.tail)                 return true;             return false;         }         #endregion         #region 队列是否已满         /// <summary> /// 队列是否已满 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public bool SeqQueueIsFull<T>(SeqQueue<T> seqQueue)         {             //如果尾指针到达数组末尾,说明队列已经满             if (seqQueue.tail == seqQueue.MaxSize)                 return true;             return false;         }         #endregion         #region 队列元素入队         /// <summary> /// 队列元素入队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <param name="data"></param> /// <returns></returns>         public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)         {             //如果队列已满,则不能进行入队操作             if (SeqQueueIsFull(seqQueue))                 throw new Exception("队列已满,不能入队操作");             //入队操作             seqQueue.data[seqQueue.tail++] = data;             return seqQueue;         }         #endregion         #region 队列元素出队         /// <summary> /// 队列元素出队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public T SeqQueueOut<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,不能进行出队操作");             var single = seqQueue.data[seqQueue.head];             //head指针自增             seqQueue.data[seqQueue.head++] = default(T);             return single;         }         #endregion         #region 获取队头元素         /// <summary> /// 获取队头元素 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,不能进行出队操作");             return seqQueue.data[seqQueue.head];         }         #endregion         /// <summary> /// 获取队列长度 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public int SeqQueueLen<T>(SeqQueue<T> seqQueue)         {             return seqQueue.tail - seqQueue.head;         }     }     #endregion }
[img]http://files.jb51.net/file_images/article/201311/2013111516123915.png[/img] 三:顺序队列的缺陷 [img]http://files.jb51.net/file_images/article/201311/2013111516123916.png[/img] 大家看这张图,不知道可有什么异样的感觉,在这种状态下,我入队操作,发现程序提示队列 已满,但是tnd我这个数组还有一个空间啊,是的,这就是所谓的“假溢出”。 四:循环队列   俗话说的好啊,“没有跨不过的坎”。 1: 概念        之所以叫“循环”,得益于神奇的“%”。他让队列的首位进行相连,形成了一个我们思维中的        “圈圈”。   2:循环公式       tail=(tail+1)%array.Length;       多看几眼,大家就看通了其中循环的道理,我要做成如下的图: 3:对循环的改造       先前看了一些资料,有的压根就是错的,有的说想要循环,就要牺牲一个单位的空间。       我觉得没必要。我既要循环又不牺牲空间,所以反射了一下framework中的Queue类。       改造后代码如下:
[u]复制代码[/u] 代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace SeqQueue {     public class Program     {         static void Main(string[] args)         {             SeqQueue<Student> seqQueue = new SeqQueue<Student>();             SeqQueueClass queueManage = new SeqQueueClass();             Console.WriteLine("目前队列是否为空:" + queueManage.SeqQueueIsEmpty(seqQueue) + "\n");             Console.WriteLine("将ID=1,2,3的实体加入队列\n");             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 1, Name = "hxc520", Age = 23 });             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 2, Name = "一线码农", Age = 23 });             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 3, Name = "51cto", Age = 23 });             Console.WriteLine("\n当前队列个数:" + queueManage.SeqQueueLen(seqQueue) + "");             Console.WriteLine("\n*********************************************\n");             Console.WriteLine("我要出队了\n");             queueManage.SeqQueueOut(seqQueue);             Console.WriteLine("哈哈,看看跟顺序队列异样之处,我再入队,看是否溢出\n");             queueManage.SeqQueueIn(seqQueue, new Student() { ID = 4, Name = "博客园", Age = 23 });             Console.WriteLine("\n....一切正常,入队成功");             Console.WriteLine("\n当前队列个数:" + queueManage.SeqQueueLen(seqQueue) + "");             Console.Read();         }     }     #region 学生数据实体     /// <summary> /// 学生数据实体 /// </summary>     public class Student     {         public int ID { get; set; }         public string Name { get; set; }         public int Age { get; set; }     }     #endregion     #region 队列的数据结构     /// <summary> /// 队列的数据结构 /// </summary> /// <typeparam name="T"></typeparam>     public class SeqQueue<T>     {         private const int maxSize = 3;         public int MaxSize         {             get { return maxSize; }         }         /// <summary> /// 顺序队列的存储长度 /// </summary>         public T[] data = new T[maxSize];         //头指针         public int head;         //尾指针         public int tail;         //队列中有效的数字个数         public int size;     }     #endregion     #region 队列的基本操作     /// <summary> /// 队列的基本操作 /// </summary>     public class SeqQueueClass     {         #region 队列的初始化操作         /// <summary> /// 队列的初始化操作 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param>         public SeqQueue<T> SeqQueueInit<T>(SeqQueue<T> seqQueue)         {             seqQueue.size = seqQueue.head = seqQueue.tail = 0;             return seqQueue;         }         #endregion         #region 队列是否为空         /// <summary> /// 队列是否为空 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public bool SeqQueueIsEmpty<T>(SeqQueue<T> seqQueue)         {             //如果两指针重合,说明队列已经清空             if (seqQueue.size == 0)                 return true;             return false;         }         #endregion         #region 队列是否已满         /// <summary> /// 队列是否已满 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public bool SeqQueueIsFull<T>(SeqQueue<T> seqQueue)         {             //采用循环队列后,头指针             if (seqQueue.size == seqQueue.MaxSize)                 return true;             return false;         }         #endregion         #region 队列元素入队         /// <summary> /// 队列元素入队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <param name="data"></param> /// <returns></returns>         public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)         {             //如果队列已满,则不能进行入队操作             if (SeqQueueIsFull(seqQueue))                 throw new Exception("队列已满,还入啥队列啊!");             //采用循环队列,必须先赋值,在自增tail指针             seqQueue.data[seqQueue.tail] = data;             seqQueue.tail = (seqQueue.tail + 1) % seqQueue.MaxSize;             //队列实际元素增加             seqQueue.size++;             return seqQueue;         }         #endregion         #region 队列元素出队         /// <summary> /// 队列元素出队 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public T SeqQueueOut<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,大哥,不要在出队了!");             //循环队列出队,展现的是head的灵活性             seqQueue.head = (seqQueue.head + 1) % seqQueue.MaxSize;             //队列实际元素递减             seqQueue.size--;             return seqQueue.data[seqQueue.head];         }         #endregion         #region 获取队头元素         /// <summary> /// 获取队头元素 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)         {             if (SeqQueueIsEmpty(seqQueue))                 throw new Exception("队列已空,不能进行出队操作");             return seqQueue.data[seqQueue.head];         }         #endregion         #region 获取队列长度         /// <summary> /// 获取队列长度 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="seqQueue"></param> /// <returns></returns>         public int SeqQueueLen<T>(SeqQueue<T> seqQueue)         {             return seqQueue.size;         }         #endregion     }     #endregion }
[img]http://files.jb51.net/file_images/article/201311/2013111516123918.png[/img]
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部