数据结构与算法之队列
前言:我写数据结构与算法这几篇博文的目的是为了让大家对数据结构与算法有一个基础的认知。想更上一层楼的还须各位自学。
一、什么是队列?
队列是数据结构的一种。他的原理是先进先出(后进后出),和栈,表一样,队列也分为顺序队列和链队列。如图:
顺序栈最开始时:
顺序队列插入元素后:
顺序队列删除元素后:
总结顺序队列的特点: 顺序队列有一个队首front和对尾rear,在最开始的时候他们都是-1,不指向任何存储单元。队尾可以执行并且只能执行插入操作,队首可以执行删除或者查询操作,换句话说只要不是插入操作都可以在队首执行。还有一个指向问题,关于这个问题我在查资料的时候发现他们并没有标准。所以大家就按照我的思路就好。等你们懂了以后自然就知道里面的奥秘。大家可以看到,rear是一直指向队尾元素的存储单元的(前提是队列里面有元素),而front是一直指向队首元素的前一个存储单元。这个概念一定要看懂,不然下面的代码你会理解的很困难。
链队列开始时:
链队列插入元素后:
链队列删除元素后:
链队列总结:基本原理同上
二、为什么要学队列?队列的用处。
先举几个例子吧,生活中最经典的例子就是排队啦,排队的时候是不是先来的先办事呢?按理说肯定是的,但是现实生活中往往有些人不按规矩的插队,他们或许真有急事又或许故意的为之,反正现在敢于说“不!”的人已经不多了。我在这没有其他的意思,包括我自己有时候也插队,有时候被人插队的时候也是没有勇气去说人家。。。
另外一个例子,就是敲键盘,你敲abcd他就出来abcd,假如你和你的女朋友聊天,你本来想说你是我的god,按照队列的思想你女朋友收到的肯定是god,因为先进先出嘛,如果键盘不按照队列办事的话你女朋友可能收到的是dog,好了,等着挨揍吧。
在遇到问题时如果你想这个问题必须按照顺序来执行,不能插队也不能有例外,就用队列吧。
三、代码怎么实现?
首先呢,我们来看看对列在BCL中是怎么实现的 :
1 namespace 队列 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 Queue<int> queue=new Queue<int>(); //Queue是队列的关键字 8 queue.Enqueue(3); 9 queue.Enqueue(8); 10 Console.WriteLine(queue.Count); 11 Console.WriteLine(queue.Peek()); 12 Console.WriteLine(queue.Dequeue()); 13 Console.WriteLine(queue.Count); 14 Console.ReadLine(); 15 } 16 } 17 }
来看看运行结果:
新建一个接口,这个接口顺序队列和链队列都会用到
1 namespace 队列 2 { 3 interface IQueue<T> 4 { 5 int Count{get;} //属性 6 void Enqueue(T item); 7 T Dequeue(); 8 T Peek(); 9 } 10 }
我这写的方法少,其他的方法大家自己去看看
顺序队列的实现
新建一个类:
1 namespace 队列 2 { 3 class MyQueue<T>:IQueue<T> 4 { 5 private T[] data; 6 private int count;//表示当前有多少个元素 7 private int front;//队首,默认是-1; 8 private int rear;//队尾,默认是-1; 9 10 public MyQueue(int size) 11 { 12 data = new T[size]; 13 count = 0; 14 front = -1; 15 rear = -1; 16 } 17 public MyQueue() :this(10) //这个构造函数的意思就是调用了含有一个参数的构造并且传递10进去 18 { 19 20 } 21 22 public int Count 23 { 24 get {return count; } 25 } 26 27 public void Enqueue(T item) 28 { 29 if (count == data.Length) 30 { 31 Console.WriteLine("队列已经满了,不能添加数据了"); 32 } 33 else 34 { 35 data[rear + 1] = item; 36 rear++; 37 count++; 38 } 39 } 40 41 public T Dequeue() 42 { 43 if (count>0) 44 { 45 T temp = data[front+1]; 46 front++; 47 count--; 48 return temp; 49 } 50 else 51 { 52 Console.WriteLine("队列是空的,无法取得队首数据"); 53 return default(T); //T是泛型,T是int类型就返回0,T是string类型就返回"" 54 } 55 56 } 57 58 public T Peek() 59 { 60 if (count>0) 61 { 62 return data[front+1]; 63 } 64 else 65 { 66 Console.WriteLine("队列是空的,无法取得队首数据"); 67 return default(T); 68 } 69 70 } 71 } 72 }
下面来控制台看看效果:
namespace 队列 { class Program { static void Main(string[] args) { MyQueue<int> queue = new MyQueue<int>(); queue.Enqueue(3); queue.Enqueue(8); Console.WriteLine(queue.Count); Console.WriteLine(queue.Peek()); Console.WriteLine(queue.Dequeue()); Console.WriteLine(queue.Count); Console.ReadLine(); } } }
效果是一样的。
链队列:
链队列和顺序队列不同的地方就在于顺序队列内部使用的是数组,而链队列使用的是节点,所以咱们要先写一个节点类:
1 namespace 队列 2 { 3 class Node<T> 4 { 5 private T data; 6 7 public T Data 8 { 9 get { return data; } 10 set { data = value; } 11 } 12 private Node<T> next; 13 14 public Node<T> Next 15 { 16 get { return next; } 17 set { next = value; } 18 } 19 20 21 public Node(T data) //构造 22 { 23 this.data = data; 24 this.next = null; 25 } 26 27 } 28 }
链队列的类:
1 namespace 队列 2 { 3 class ListQueue<T>:IQueue<T> 4 { 5 private int count; 6 private Node<T> front; 7 private Node<T> rear; 8 9 public ListQueue() 10 { 11 count = 0; 12 front = null; 13 rear = null; 14 } 15 16 public int Count 17 { 18 get { return count; } 19 } 20 21 public void Enqueue(T item) 22 { 23 Node<T> newNode = new Node<T>(item); 24 if (count == 0) 25 { 26 front = newNode; 27 rear = newNode; 28 count = 1; 29 } 30 else 31 { 32 rear.Next = newNode; 33 rear = newNode; 34 count++; 35 } 36 } 37 38 public T Dequeue() 39 { 40 if (count == 0) 41 { 42 return default(T); 43 } 44 else 45 { 46 if (count==1) 47 { 48 T newData = front.Data; 49 front = null; 50 rear = null; 51 count = 0; 52 return newData; 53 } 54 else 55 { 56 T newData = front.Data; 57 front = front.Next; 58 count--; 59 return newData; 60 } 61 } 62 } 63 64 public T Peek() 65 { 66 if (count==0) 67 { 68 return default(T); 69 } 70 else 71 { 72 return front.Data; 73 } 74 75 } 76 } 77 }
在控制台看看效果:
namespace 队列 { class Program { static void Main(string[] args) { ListQueue <int> queue = new ListQueue<int>(); queue.Enqueue(3); queue.Enqueue(8); Console.WriteLine(queue.Count); Console.WriteLine(queue.Peek()); Console.WriteLine(queue.Dequeue()); Console.WriteLine(queue.Count); Console.ReadLine(); } } }
效果都是一样的,说明链队列也成功了。
四、队列的几个主要方法
1 Queue<int> queue=new Queue<int>(); 2 queue.Enqueue(3); //在队尾插入一个元素,无返回值 3 queue.Dequeue(); //在队首取得队首元素并返回,然后删除队首元素 4 queue.Peek(); //在队首取得队首元素并返回 5 queue.Count; //队列里面的元素个数,无返回值 6 queue.Clear(); //清空队列 7
五、后记
如果大家有什么疑问可以给我留言或者在新浪微博上 @蜀云泉 就能找到我了。