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

16 篇文章 0 订阅

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

转自:http://blog.csdn.net/m13666368773/article/details/7530196

五一回老家待了几天,昨天晚上回来看见有很多网友留言,谢谢支持,继续写点东东奉献给大家

 

可能大家都知道,线性表的变种非常非常多,比如今天讲的“队列”,灰常有意思啊。

 

一:概念

          队列是一个”先进先出“的线性表,牛X的名字就是“First in First Out(FIFO)”,

      生活中有很多这样的场景,比如读书的时候去食堂打饭时的”排队“。当然我们拒绝插队。

 

二:存储结构

         前几天也说过,线性表有两种”存储结构“,① 顺序存储,②链式存储。当然“队列”也脱离

     不了这两种服务,这里我就分享一下“顺序存储”。

     顺序存储时,我们会维护一个叫做”head头指针“和”tail尾指针“,分别指向队列的开头和结尾。

 

代码段如下:

复制代码
[csharp]  view plain  copy
  1. #region 队列的数据结构  
  2.      /// <summary>  
  3.  /// 队列的数据结构  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.      public class SeqQueue<T>  
  7.      {  
  8.          private const int maxSize = 100;  
  9.    
  10.          public int MaxSize  
  11.          {  
  12.              get { return maxSize; }  
  13.          }  
  14.    
  15.          /// <summary>  
  16.  /// 顺序队列的存储长度  
  17.  /// </summary>  
  18.          public T[] data = new T[maxSize];  
  19.    
  20.          //头指针  
  21.          public int head;  
  22.    
  23.          //尾指针  
  24.          public int tail;  
  25.    
  26.      }  
  27.      #endregion  

 

 

三:常用操作

      队列的操作一般分为:

      ①: 初始化队列。

      ②:   出队。

      ③: 入队。

      ④: 获取队头。

      ⑤: 获取队长。

 

1:初始化队列

        这个很简单,刚才也说过了,队列是用一个head和tail的指针来维护。分别设置为0即可。

 

2:出队

       看着“队列”的结构图,大家都知道,出队肯定跟head指针有关,需要做两件事情,

       第一: 判断队列是否为空,这个我想大家都知道。

       第二: 将head头指针向后移动一位,返回head移动前的元素,时间复杂度为O(1)。

   

代码段如下:

复制代码 
[csharp]  view plain  copy
  1. #region 队列元素出队  
  2.          /// <summary>  
  3.  /// 队列元素出队  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="seqQueue"></param>  
  7.  /// <returns></returns>  
  8.          public T SeqQueueOut<T>(SeqQueue<T> seqQueue)  
  9.          {  
  10.              if (SeqQueueIsEmpty(seqQueue))  
  11.                  throw new Exception("队列已空,不能进行出队操作");  
  12.    
  13.              var single = seqQueue.data[seqQueue.head];  
  14.    
  15.              //head指针自增  
  16.              seqQueue.data[seqQueue.head++] = default(T);  
  17.    
  18.              return single;  
  19.    
  20.          }  
  21.          #endregion  



3:入队

      这个跟”出队“的思想相反,同样也是需要做两件事情。

      第一:判断队列是否已满。

      第二:将tail指针向后移动一位,时间复杂度为O(1)。

代码段如下:

复制代码
[csharp]  view plain  copy
  1. #region 队列元素入队  
  2.          /// <summary>  
  3.  /// 队列元素入队  
  4.  /// </summary>  
  5.  /// <typeparam name="T"></typeparam>  
  6.  /// <param name="seqQueue"></param>  
  7.  /// <param name="data"></param>  
  8.  /// <returns></returns>  
  9.          public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)  
  10.          {  
  11.              //如果队列已满,则不能进行入队操作  
  12.              if (SeqQueueIsFull(seqQueue))  
  13.                  throw new Exception("队列已满,不能入队操作");  
  14.    
  15.              //入队操作  
  16.              seqQueue.data[seqQueue.tail++] = data;  
  17.    
  18.              return seqQueue;  
  19.          }  
  20.          #endregion  


4: 获取队头

       知道”出队“和”入队“的原理,相信大家都懂的如何进行”获取队头“操作,唯一不一样的就是

       他是只读操作,不会破坏”队列“结构,时间复杂度为O(1)。

 

代码段如下:

复制代码
[csharp]  view plain  copy
  1. #region 获取队头元素  
  2.         /// <summary>  
  3.         /// 获取队头元素  
  4.         /// </summary>  
  5.         /// <typeparam name="T"></typeparam>  
  6.         /// <param name="seqQueue"></param>  
  7.         /// <returns></returns>  
  8.         public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)  
  9.         {  
  10.             if (SeqQueueIsEmpty(seqQueue))  
  11.                 throw new Exception("队列已空,不能进行出队操作");  
  12.   
  13.             return seqQueue.data[seqQueue.head];  
  14.         }  
  15.         #endregion  


5: 获取队长

       大家都知道,我们是用数组来实现队列,所以千万不要想当然的认为数组长度是XXX,

       我们维护的是一个head和tail的指针,所以长度自然就是tail-head咯,时间复杂度为O(1)。

代码段如下:

复制代码
[csharp]  view plain  copy
  1. /// <summary>  
  2.  /// 获取队列长度  
  3.  /// </summary>  
  4.  /// <typeparam name="T"></typeparam>  
  5.  /// <param name="seqQueue"></param>  
  6.  /// <returns></returns>  
  7.          public int SeqQueueLen<T>(SeqQueue<T> seqQueue)  
  8.          {  
  9.              return seqQueue.tail - seqQueue.head;  
  10.          }  

 

然后上一下总的运行代码:

[csharp]  view plain  copy
  1. View Code   
  2.  using System;  
  3.  using System.Collections.Generic;  
  4.  using System.Linq;  
  5.  using System.Text;  
  6.    
  7.  namespace SeqQueue  
  8.  {  
  9.      public class Program  
  10.      {  
  11.          static void Main(string[] args)  
  12.          {  
  13.              SeqQueue<Student> seqQueue = new SeqQueue<Student>();  
  14.    
  15.              SeqQueueClass queueManage = new SeqQueueClass();  
  16.    
  17.              Console.WriteLine("目前队列是否为空:" + queueManage.SeqQueueIsEmpty(seqQueue) + "\n");  
  18.    
  19.              Console.WriteLine("将ID=1和ID=2的实体加入队列");  
  20.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 1, Name = "hxc520", Age = 23 });  
  21.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 2, Name = "一线码农", Age = 23 });  
  22.    
  23.              Display(seqQueue);  
  24.    
  25.              Console.WriteLine("将队头出队");  
  26.              //将队头出队  
  27.              var student = queueManage.SeqQueueOut(seqQueue);  
  28.    
  29.              Display(seqQueue);  
  30.    
  31.              //获取队顶元素  
  32.              student = queueManage.SeqQueuePeek(seqQueue);  
  33.    
  34.              Console.Read();  
  35.          }  
  36.          //展示队列元素  
  37.          static void Display(SeqQueue<Student> seqQueue)  
  38.          {  
  39.              Console.WriteLine("******************* 链表数据如下 *******************");  
  40.    
  41.              for (int i = seqQueue.head; i < seqQueue.tail; i++)  
  42.                  Console.WriteLine("ID:" + seqQueue.data[i].ID +  
  43.                                    ",Name:" + seqQueue.data[i].Name +  
  44.                                    ",Age:" + seqQueue.data[i].Age);  
  45.    
  46.              Console.WriteLine("******************* 链表数据展示完毕 *******************\n");  
  47.          }  
  48.      }  
  49.   
  50.      #region 学生数据实体  
  51.      /// <summary>  
  52.  /// 学生数据实体  
  53.  /// </summary>  
  54.      public class Student  
  55.      {  
  56.          public int ID { getset; }  
  57.    
  58.          public string Name { getset; }  
  59.    
  60.          public int Age { getset; }  
  61.      }  
  62.      #endregion  
  63.   
  64.      #region 队列的数据结构  
  65.      /// <summary>  
  66.  /// 队列的数据结构  
  67.  /// </summary>  
  68.  /// <typeparam name="T"></typeparam>  
  69.      public class SeqQueue<T>  
  70.      {  
  71.          private const int maxSize = 100;  
  72.    
  73.          public int MaxSize  
  74.          {  
  75.              get { return maxSize; }  
  76.          }  
  77.    
  78.          /// <summary>  
  79.  /// 顺序队列的存储长度  
  80.  /// </summary>  
  81.          public T[] data = new T[maxSize];  
  82.    
  83.          //头指针  
  84.          public int head;  
  85.    
  86.          //尾指针  
  87.          public int tail;  
  88.    
  89.      }  
  90.      #endregion  
  91.   
  92.      #region 队列的基本操作  
  93.      /// <summary>  
  94.  /// 队列的基本操作  
  95.  /// </summary>  
  96.      public class SeqQueueClass  
  97.      {  
  98.          #region 队列的初始化操作  
  99.          /// <summary>  
  100.  /// 队列的初始化操作  
  101.  /// </summary>  
  102.  /// <typeparam name="T"></typeparam>  
  103.  /// <param name="seqQueue"></param>  
  104.          public SeqQueue<T> SeqQueueInit<T>(SeqQueue<T> seqQueue)  
  105.          {  
  106.              seqQueue.head = 0;  
  107.              seqQueue.tail = 0;  
  108.    
  109.              return seqQueue;  
  110.          }  
  111.          #endregion  
  112.   
  113.          #region 队列是否为空  
  114.          /// <summary>  
  115.  /// 队列是否为空  
  116.  /// </summary>  
  117.  /// <typeparam name="T"></typeparam>  
  118.  /// <param name="seqQueue"></param>  
  119.  /// <returns></returns>  
  120.          public bool SeqQueueIsEmpty<T>(SeqQueue<T> seqQueue)  
  121.          {  
  122.              //如果两指针重合,说明队列已经清空  
  123.              if (seqQueue.head == seqQueue.tail)  
  124.                  return true;  
  125.              return false;  
  126.          }  
  127.          #endregion  
  128.   
  129.          #region 队列是否已满  
  130.          /// <summary>  
  131.  /// 队列是否已满  
  132.  /// </summary>  
  133.  /// <typeparam name="T"></typeparam>  
  134.  /// <param name="seqQueue"></param>  
  135.  /// <returns></returns>  
  136.          public bool SeqQueueIsFull<T>(SeqQueue<T> seqQueue)  
  137.          {  
  138.              //如果尾指针到达数组末尾,说明队列已经满  
  139.              if (seqQueue.tail == seqQueue.MaxSize)  
  140.                  return true;  
  141.              return false;  
  142.          }  
  143.          #endregion  
  144.   
  145.          #region 队列元素入队  
  146.          /// <summary>  
  147.  /// 队列元素入队  
  148.  /// </summary>  
  149.  /// <typeparam name="T"></typeparam>  
  150.  /// <param name="seqQueue"></param>  
  151.  /// <param name="data"></param>  
  152.  /// <returns></returns>  
  153.          public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)  
  154.          {  
  155.              //如果队列已满,则不能进行入队操作  
  156.              if (SeqQueueIsFull(seqQueue))  
  157.                  throw new Exception("队列已满,不能入队操作");  
  158.    
  159.              //入队操作  
  160.              seqQueue.data[seqQueue.tail++] = data;  
  161.    
  162.              return seqQueue;  
  163.          }  
  164.          #endregion  
  165.   
  166.          #region 队列元素出队  
  167.          /// <summary>  
  168.  /// 队列元素出队  
  169.  /// </summary>  
  170.  /// <typeparam name="T"></typeparam>  
  171.  /// <param name="seqQueue"></param>  
  172.  /// <returns></returns>  
  173.          public T SeqQueueOut<T>(SeqQueue<T> seqQueue)  
  174.          {  
  175.              if (SeqQueueIsEmpty(seqQueue))  
  176.                  throw new Exception("队列已空,不能进行出队操作");  
  177.    
  178.              var single = seqQueue.data[seqQueue.head];  
  179.    
  180.              //head指针自增  
  181.              seqQueue.data[seqQueue.head++] = default(T);  
  182.    
  183.              return single;  
  184.    
  185.          }  
  186.          #endregion  
  187.   
  188.          #region 获取队头元素  
  189.          /// <summary>  
  190.  /// 获取队头元素  
  191.  /// </summary>  
  192.  /// <typeparam name="T"></typeparam>  
  193.  /// <param name="seqQueue"></param>  
  194.  /// <returns></returns>  
  195.          public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)  
  196.          {  
  197.              if (SeqQueueIsEmpty(seqQueue))  
  198.                  throw new Exception("队列已空,不能进行出队操作");  
  199.    
  200.              return seqQueue.data[seqQueue.head];  
  201.          }  
  202.          #endregion  
  203.    
  204.          /// <summary>  
  205.  /// 获取队列长度  
  206.  /// </summary>  
  207.  /// <typeparam name="T"></typeparam>  
  208.  /// <param name="seqQueue"></param>  
  209.  /// <returns></returns>  
  210.          public int SeqQueueLen<T>(SeqQueue<T> seqQueue)  
  211.          {  
  212.              return seqQueue.tail - seqQueue.head;  
  213.          }  
  214.      }  
  215.      #endregion  
  216.  }  

 

 

 

三:顺序队列的缺陷

大家看这张图,不知道可有什么异样的感觉,在这种状态下,我入队操作,发现程序提示队列

已满,但是tnd我这个数组还有一个空间啊,是的,这就是所谓的“假溢出”

 

四:循环队列

 

俗话说的好啊,“没有跨不过的坎”。

 

1: 概念

       之所以叫“循环”,得益于神奇的“%”。他让队列的首位进行相连,形成了一个我们思维中的

       “圈圈”。

 

2:循环公式

      tail=(tail+1)%array.Length;

      多看几眼,大家就看通了其中循环的道理,我要做成如下的图:

 

3:对循环的改造

      先前看了一些资料,有的压根就是错的,有的说想要循环,就要牺牲一个单位的空间。

      我觉得没必要。我既要循环又不牺牲空间,所以反射了一下framework中的Queue类。

      改造后代码如下:

 

[csharp]  view plain  copy
  1. View Code   
  2.  using System;  
  3.  using System.Collections.Generic;  
  4.  using System.Linq;  
  5.  using System.Text;  
  6.    
  7.  namespace SeqQueue  
  8.  {  
  9.      public class Program  
  10.      {  
  11.          static void Main(string[] args)  
  12.          {  
  13.              SeqQueue<Student> seqQueue = new SeqQueue<Student>();  
  14.    
  15.              SeqQueueClass queueManage = new SeqQueueClass();  
  16.    
  17.              Console.WriteLine("目前队列是否为空:" + queueManage.SeqQueueIsEmpty(seqQueue) + "\n");  
  18.    
  19.              Console.WriteLine("将ID=1,2,3的实体加入队列\n");  
  20.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 1, Name = "hxc520", Age = 23 });  
  21.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 2, Name = "一线码农", Age = 23 });  
  22.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 3, Name = "51cto", Age = 23 });  
  23.    
  24.              Console.WriteLine("\n当前队列个数:" + queueManage.SeqQueueLen(seqQueue) + "");  
  25.    
  26.              Console.WriteLine("\n*********************************************\n");  
  27.    
  28.              Console.WriteLine("我要出队了\n");  
  29.              queueManage.SeqQueueOut(seqQueue);  
  30.    
  31.              Console.WriteLine("哈哈,看看跟顺序队列异样之处,我再入队,看是否溢出\n");  
  32.              queueManage.SeqQueueIn(seqQueue, new Student() { ID = 4, Name = "博客园", Age = 23 });  
  33.              Console.WriteLine("\n....一切正常,入队成功");  
  34.    
  35.              Console.WriteLine("\n当前队列个数:" + queueManage.SeqQueueLen(seqQueue) + "");  
  36.    
  37.              Console.Read();  
  38.          }  
  39.      }  
  40.   
  41.      #region 学生数据实体  
  42.      /// <summary>  
  43.  /// 学生数据实体  
  44.  /// </summary>  
  45.      public class Student  
  46.      {  
  47.          public int ID { getset; }  
  48.    
  49.          public string Name { getset; }  
  50.    
  51.          public int Age { getset; }  
  52.      }  
  53.      #endregion  
  54.   
  55.      #region 队列的数据结构  
  56.      /// <summary>  
  57.  /// 队列的数据结构  
  58.  /// </summary>  
  59.  /// <typeparam name="T"></typeparam>  
  60.      public class SeqQueue<T>  
  61.      {  
  62.          private const int maxSize = 3;  
  63.    
  64.          public int MaxSize  
  65.          {  
  66.              get { return maxSize; }  
  67.          }  
  68.    
  69.          /// <summary>  
  70.  /// 顺序队列的存储长度  
  71.  /// </summary>  
  72.          public T[] data = new T[maxSize];  
  73.    
  74.          //头指针  
  75.          public int head;  
  76.    
  77.          //尾指针  
  78.          public int tail;  
  79.    
  80.          //队列中有效的数字个数  
  81.          public int size;  
  82.      }  
  83.      #endregion  
  84.   
  85.      #region 队列的基本操作  
  86.      /// <summary>  
  87.  /// 队列的基本操作  
  88.  /// </summary>  
  89.      public class SeqQueueClass  
  90.      {  
  91.          #region 队列的初始化操作  
  92.          /// <summary>  
  93.  /// 队列的初始化操作  
  94.  /// </summary>  
  95.  /// <typeparam name="T"></typeparam>  
  96.  /// <param name="seqQueue"></param>  
  97.          public SeqQueue<T> SeqQueueInit<T>(SeqQueue<T> seqQueue)  
  98.          {  
  99.              seqQueue.size = seqQueue.head = seqQueue.tail = 0;  
  100.    
  101.              return seqQueue;  
  102.          }  
  103.          #endregion  
  104.   
  105.          #region 队列是否为空  
  106.          /// <summary>  
  107.  /// 队列是否为空  
  108.  /// </summary>  
  109.  /// <typeparam name="T"></typeparam>  
  110.  /// <param name="seqQueue"></param>  
  111.  /// <returns></returns>  
  112.          public bool SeqQueueIsEmpty<T>(SeqQueue<T> seqQueue)  
  113.          {  
  114.              //如果两指针重合,说明队列已经清空  
  115.              if (seqQueue.size == 0)  
  116.                  return true;  
  117.              return false;  
  118.          }  
  119.          #endregion  
  120.   
  121.          #region 队列是否已满  
  122.          /// <summary>  
  123.  /// 队列是否已满  
  124.  /// </summary>  
  125.  /// <typeparam name="T"></typeparam>  
  126.  /// <param name="seqQueue"></param>  
  127.  /// <returns></returns>  
  128.          public bool SeqQueueIsFull<T>(SeqQueue<T> seqQueue)  
  129.          {  
  130.              //采用循环队列后,头指针  
  131.              if (seqQueue.size == seqQueue.MaxSize)  
  132.                  return true;  
  133.              return false;  
  134.          }  
  135.          #endregion  
  136.   
  137.          #region 队列元素入队  
  138.          /// <summary>  
  139.  /// 队列元素入队  
  140.  /// </summary>  
  141.  /// <typeparam name="T"></typeparam>  
  142.  /// <param name="seqQueue"></param>  
  143.  /// <param name="data"></param>  
  144.  /// <returns></returns>  
  145.          public SeqQueue<T> SeqQueueIn<T>(SeqQueue<T> seqQueue, T data)  
  146.          {  
  147.              //如果队列已满,则不能进行入队操作  
  148.              if (SeqQueueIsFull(seqQueue))  
  149.                  throw new Exception("队列已满,还入啥队列啊!");  
  150.    
  151.              //采用循环队列,必须先赋值,在自增tail指针  
  152.              seqQueue.data[seqQueue.tail] = data;  
  153.              seqQueue.tail = (seqQueue.tail + 1) % seqQueue.MaxSize;  
  154.    
  155.              //队列实际元素增加  
  156.              seqQueue.size++;  
  157.    
  158.              return seqQueue;  
  159.          }  
  160.          #endregion  
  161.   
  162.          #region 队列元素出队  
  163.          /// <summary>  
  164.  /// 队列元素出队  
  165.  /// </summary>  
  166.  /// <typeparam name="T"></typeparam>  
  167.  /// <param name="seqQueue"></param>  
  168.  /// <returns></returns>  
  169.          public T SeqQueueOut<T>(SeqQueue<T> seqQueue)  
  170.          {  
  171.              if (SeqQueueIsEmpty(seqQueue))  
  172.                  throw new Exception("队列已空,大哥,不要在出队了!");  
  173.    
  174.              //循环队列出队,展现的是head的灵活性  
  175.              seqQueue.head = (seqQueue.head + 1) % seqQueue.MaxSize;  
  176.    
  177.              //队列实际元素递减  
  178.              seqQueue.size--;  
  179.    
  180.              return seqQueue.data[seqQueue.head];  
  181.          }  
  182.          #endregion  
  183.   
  184.          #region 获取队头元素  
  185.          /// <summary>  
  186.  /// 获取队头元素  
  187.  /// </summary>  
  188.  /// <typeparam name="T"></typeparam>  
  189.  /// <param name="seqQueue"></param>  
  190.  /// <returns></returns>  
  191.          public T SeqQueuePeek<T>(SeqQueue<T> seqQueue)  
  192.          {  
  193.              if (SeqQueueIsEmpty(seqQueue))  
  194.                  throw new Exception("队列已空,不能进行出队操作");  
  195.    
  196.              return seqQueue.data[seqQueue.head];  
  197.          }  
  198.          #endregion  
  199.   
  200.          #region 获取队列长度  
  201.          /// <summary>  
  202.  /// 获取队列长度  
  203.  /// </summary>  
  204.  /// <typeparam name="T"></typeparam>  
  205.  /// <param name="seqQueue"></param>  
  206.  /// <returns></returns>  
  207.          public int SeqQueueLen<T>(SeqQueue<T> seqQueue)  
  208.          {  
  209.              return seqQueue.size;  
  210.          }  
  211.          #endregion  
  212.      }  
  213.      #endregion  
  214.  }  

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值