好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C#数据结构之队列(Quene)实例详解

本文实例讲述了C#数据结构之队列(Quene)。分享给大家供大家参考,具体如下:

队列(Quene)的特征就是[ 先进先出 ],队列把所有操作限制在" 只能在线性结构的两端 "进行,更具体一点: 添加元素必须在线性表尾部进行 ,而 删除元素只能在线性表头部进行 。

先抽象接口IQuene<T>

?

namespace 栈与队列

{

   public interface IQuene<T>

   {

     /// <summary>

     /// 取得队列实际元素的个数

     /// </summary>

     /// <returns></returns>

     public int Count();

     /// <summary>

     /// 判断队列是否为空

     /// </summary>

     /// <returns></returns>

     public bool IsEmpty();

     /// <summary>

     /// 清空队列

     /// </summary>

     public void Clear();

     /// <summary>

     /// 入队(即向队列尾部添加一个元素)

     /// </summary>

     /// <param name="item"></param>

     public void Enquene(T item);

     /// <summary>

     /// 出队(即从队列头部删除一个元素)

     /// </summary>

     /// <returns></returns>

     public T Dequene();

     /// <summary>

     /// 取得队列头部第一元素

     /// </summary>

     /// <returns></returns>

     public T Peek();

   }

}

下面是基于数组实现的示意图:

实现思路:用一个数组存放所有元素,同时设置二个关键变量front与rear用于记录队列[头]与[尾]的元素下标,当有元素入列时rear加1,当有元素出队时front+1,而rear-front即为队列实际元素的总数.

但有一种[队列伪满]的特殊情况要注意,如下图:

这张图上面的部分:假设经过入队、出队一番折腾后,rear已经指向数组的下标最大值,而front指向在中间(即front之间的元素已经出队不用考虑了,相当于front下标前面的内存区域空闲),如果这时再有一个元素入列,rear+1就超出数组下标的最大值了,但是从图上一眼就能看出,实际上front前面还空着一堆位置可以重复利用, 队列并非真正的[满]--这种情况称为 伪满 ,为了解决这个问题,我们可以把数组想象为首尾相接的循环结构,即图中下面部分,这时候可以让rear重新指向到0,以便重复利用空闲的位置。

所以:入列时rear++的操作,应该稍做修正,当rear到数组下标最大值时,让它置0,以便能循环利用 (见后面的代码)

另外还有一个问题:最开始时front与rear都为-1,即front==rear时表示队列为空,改成循环以后,有可能会出现rear在循环过程中碰到front的情况,即真正意义的上"满"状态,这时rear也同样等于front,这样就无法单纯的用rear==front来判断是满,还是空?这时可以浪费一个元素的位置,认为当rear+1==front时,队列就已经满了,虽然牺牲了一个元素的空间,但却换来了逻辑的正确性,还是值得的。

完整实现如下:

?

using System;

using System.Text;

namespace 栈与队列

{

   /// <summary>

   /// 循环顺序队列

   /// </summary>

   /// <typeparam name="T"></typeparam>

   public class CSeqQueue<T>:IQueue<T>

   {

     private int maxsize;

     private T[] data;

     private int front;

     private int rear;   

     public CSeqQueue( int size)

     {

       data = new T[size];

       maxsize = size;

       front = rear = -1;

     }

     public int Count()    

     {

       if (rear > front)

       {

         return rear - front;

       }

       else

       {

         return (rear - front + maxsize) % maxsize;

       }

     }

     public void Clear()

     {

       front = rear = -1;

     }

     public bool IsEmpty()

     {

       return front == rear;     

     }

     public bool IsFull()

     {     

       if (front != -1) //如果已经有元素出队过

       {

         return (rear + 1) % maxsize == front; //为了区分与IsEmpty的区别,有元素出队过以后,就只有浪费一个位置来保持逻辑正确性.

       }

       else

       {

         return rear == maxsize - 1;

       }     

     }

     public void Enqueue(T item)

     {

       if (IsFull())

       {

         Console.WriteLine( "Queue is full" );

         return ;

       }

       if (rear == maxsize - 1) //如果rear到头了,则循环重来(即解决伪满问题)

       {

         rear = 0;

       }

       else

       {

         rear++;

       }

       data[rear] = item;

     }

     public T Dequeue()

     {     

       if (IsEmpty())

       {

         Console.WriteLine( "Queue is empty" );

         return default (T);

       }

       if (front == maxsize - 1) //如果front到头了,则重新置0

       {

         front = 0;

       }

       else

       {

         front++;

       }     

       return data[front];

     }

     public T Peek()

     {

       if (IsEmpty())

       {

         Console.WriteLine( "Queue is empty!" );

         return default (T);

       }

       return data[(front + 1) % maxsize];     

     }

     public override string ToString()

     {

       if (IsEmpty()) { return "queue is empty." ; }

       StringBuilder sb = new StringBuilder();

       if (rear > front)

       {

         for ( int i = front + 1; i <= rear; i++)

         {

           sb.Append( this .data[i].ToString() + "," );

         }

       }

       else

       {

         for ( int i = front + 1; i < maxsize; i++)

         {

           sb.Append( this .data[i].ToString() + "," );

         }

         for ( int i = 0; i <= rear; i++)

         {

           sb.Append( this .data[i].ToString() + "," );

         }

       }

       return "front = " + this .front + " \t rear = " + this .rear + "\t count = " + this .Count() + "\t data = " + sb.ToString().Trim( ',' );

     }

   }

}

测试代码片段:

?

CSeqQueue< int > queue = new CSeqQueue< int >(5);

queue.Enqueue(1);

queue.Enqueue(2);

queue.Enqueue(3);

queue.Enqueue(4);

Console.WriteLine(queue); //front = -1    rear = 3    count = 4    data = 1,2,3,4

queue.Dequeue();

Console.WriteLine(queue); //front = 0    rear = 3    count = 3    data = 2,3,4

queue.Dequeue();

Console.WriteLine(queue); //front = 1    rear = 3    count = 2    data = 3,4

queue.Enqueue(5);

Console.WriteLine(queue); //front = 1    rear = 4    count = 3    data = 3,4,5

queue.Enqueue(6);

Console.WriteLine(queue); //front = 1    rear = 0    count = 4    data = 3,4,5,6

queue.Enqueue(7);    //Queue is full

Console.WriteLine(queue); //front = 1    rear = 0    count = 4    data = 3,4,5,6

queue.Dequeue();

queue.Enqueue(7);

Console.WriteLine(queue); //front = 2    rear = 1    count = 4    data = 4,5,6,7

queue.Clear();

Console.WriteLine(queue); //queue is empty.

queue.Enqueue(1);

queue.Enqueue(2);

queue.Enqueue(3);

queue.Enqueue(4);

Console.WriteLine(queue); //front = -1    rear = 3    count = 4    data = 1,2,3,4

queue.Enqueue(5);

Console.WriteLine(queue); //front = -1    rear = 4    count = 5    data = 1,2,3,4,5

queue.Enqueue(6);    //Queue is full

Console.WriteLine(queue); //front = -1    rear = 4    count = 5    data = 1,2,3,4,5

queue.Dequeue();

queue.Dequeue();

queue.Dequeue();

queue.Dequeue();

Console.WriteLine(queue); //front = 3    rear = 4    count = 1    data = 5

queue.Dequeue();

Console.WriteLine(queue); //queue is empty.

queue.Enqueue(0);

queue.Enqueue(1);

queue.Enqueue(2);

queue.Enqueue(3);

queue.Enqueue(4);    //Queue is full

Console.WriteLine(queue); //front = 4    rear = 3    count = 4    data = 0,1,2,3

Console.WriteLine(queue.Peek()); //0

queue.Dequeue();

Console.WriteLine(queue); //front = 0    rear = 3    count = 3    data = 1,2,3

queue.Dequeue();

Console.WriteLine(queue); //front = 1    rear = 3    count = 2    data = 2,3

queue.Dequeue();

Console.WriteLine(queue); //front = 2    rear = 3    count = 1    data = 3

queue.Dequeue();

Console.WriteLine(queue); //queue is empty.

queue.Enqueue(9);

Console.WriteLine(queue); //front = 3    rear = 4    count = 1    data = 9

Console.ReadLine();

当然,队列也可以用链表来实现,相对要容易很多。

先定义链表中的节点Node.cs

?

namespace 栈与队列

{

   public class Node<T>

   {

     private T data;

     private Node<T> next;

     public Node(T data, Node<T> next)

     {

       this .data = data;

       this .next = next;

     }

     public Node(Node<T> next)

     {

       this .next = next;

       this .data = default (T);

     }

     public Node(T data)

     {

       this .data = data;

       this .next = null ;

     }

     public Node()

     {

       this .data = default (T);

       this .next = null ;

     }

     public T Data {

       get { return this .data; }

       set { this .data = value; }

     }

     public Node<T> Next

     {

       get { return next; }

       set { next = value; }

     }

   }

}

为了方便,定义了很多构造函数的重载版本,当然这些只是浮云,重点是理解结构:data用来保存数据,next指出下一个节点是谁
链式队列的完整实现LinkQueue.cs

?

using System;

using System.Text;

namespace 栈与队列

{

   public class LinkQueue:IQueue

   {

     private Node front; //队列头

     private Node rear; //队列尾

     private int num; //队列元素个数

     ///

     /// 构造器

     ///

     public LinkQueue()

     {

       //初始时front,rear置为null,num置0

       front = rear = null ;

       num = 0;

     }

     public int Count()

     {

       return this .num;

     }

     public void Clear()

     {

       front = rear = null ;

       num = 0;

     }

     public bool IsEmpty()

     {

       return (front == rear && num == 0);

     }

     //入队

     public void Enqueue(T item)

     {

       Node q = new Node(item);

       if (rear == null ) //第一个元素入列时

       {

         front = rear = q;

       }

       else

       {

         //把新元素挂到链尾

         rear.Next = q;

         //修正rear指向为最后一个元素

         rear = q;

       }

       //元素总数+1

       num++;

     }

     //出队

     public T Dequeue()

     {

       if (IsEmpty())

       {

         Console.WriteLine( "Queue is empty!" );

         return default (T);

       }

       //取链首元素

       Node p = front;

       //链头指向后移一位

       front = front.Next;

       //如果此时链表为空,则同步修正rear

       if (front == null )

       {

         rear = null ;

       }

       num--; //个数-1

       return p.Data;

     }

     public T Peek()

     {

       if (IsEmpty())

       {

         Console.WriteLine( "Queue is empty!" );

         return default (T);

       }

       return front.Data;

     }

     public override string ToString()

     {

       if (IsEmpty()) {

         Console.WriteLine( "Queue is empty!" );

       }

       StringBuilder sb = new StringBuilder();

       Node node = front;

       sb.Append(node.Data.ToString());

       while (node.Next!= null )

       {

         sb.Append( "," + node.Next.Data.ToString());

         node = node.Next;

       }

       return sb.ToString().Trim( ',' );

     }

   }

}

希望本文所述对大家C#程序设计有所帮助。

dy("nrwz");

查看更多关于C#数据结构之队列(Quene)实例详解的详细内容...

  阅读:91次