欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Quene)實(shí)例詳解

 更新時(shí)間:2015年11月27日 14:55:06   作者:Jimmy.Yang  
這篇文章主要介紹了C#數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Quene),結(jié)合實(shí)例形式較為詳細(xì)的講述了隊(duì)列的功能、原理與C#實(shí)現(xiàn)隊(duì)列的相關(guān)技巧,需要的朋友可以參考下

本文實(shí)例講述了C#數(shù)據(jù)結(jié)構(gòu)之隊(duì)列(Quene)。分享給大家供大家參考,具體如下:

隊(duì)列(Quene)的特征就是“先進(jìn)先出”,隊(duì)列把所有操作限制在"只能在線(xiàn)性結(jié)構(gòu)的兩端"進(jìn)行,更具體一點(diǎn):添加元素必須在線(xiàn)性表尾部進(jìn)行,而刪除元素只能在線(xiàn)性表頭部進(jìn)行。

先抽象接口IQuene<T>

namespace 棧與隊(duì)列
{
  public interface IQuene<T>
  {
    /// <summary>
    /// 取得隊(duì)列實(shí)際元素的個(gè)數(shù)
    /// </summary>
    /// <returns></returns>
    public int Count();
    /// <summary>
    /// 判斷隊(duì)列是否為空
    /// </summary>
    /// <returns></returns>
    public bool IsEmpty();
    /// <summary>
    /// 清空隊(duì)列
    /// </summary>
    public void Clear();
    /// <summary>
    /// 入隊(duì)(即向隊(duì)列尾部添加一個(gè)元素)
    /// </summary>
    /// <param name="item"></param>
    public void Enquene(T item);
    /// <summary>
    /// 出隊(duì)(即從隊(duì)列頭部刪除一個(gè)元素)
    /// </summary>
    /// <returns></returns>
    public T Dequene();
    /// <summary>
    /// 取得隊(duì)列頭部第一元素
    /// </summary>
    /// <returns></returns>
    public T Peek();
  }
}

下面是基于數(shù)組實(shí)現(xiàn)的示意圖:

實(shí)現(xiàn)思路:用一個(gè)數(shù)組存放所有元素,同時(shí)設(shè)置二個(gè)關(guān)鍵變量front與rear用于記錄隊(duì)列“頭”與“尾”的元素下標(biāo),當(dāng)有元素入列時(shí)rear加1,當(dāng)有元素出隊(duì)時(shí)front+1,而rear-front即為隊(duì)列實(shí)際元素的總數(shù).

但有一種“隊(duì)列偽滿(mǎn)”的特殊情況要注意,如下圖:

這張圖上面的部分:假設(shè)經(jīng)過(guò)入隊(duì)、出隊(duì)一番折騰后,rear已經(jīng)指向數(shù)組的下標(biāo)最大值,而front指向在中間(即front之間的元素已經(jīng)出隊(duì)不用考慮了,相當(dāng)于front下標(biāo)前面的內(nèi)存區(qū)域空閑),如果這時(shí)再有一個(gè)元素入列,rear+1就超出數(shù)組下標(biāo)的最大值了,但是從圖上一眼就能看出,實(shí)際上front前面還空著一堆位置可以重復(fù)利用,隊(duì)列并非真正的“滿(mǎn)”--這種情況稱(chēng)為偽滿(mǎn),為了解決這個(gè)問(wèn)題,我們可以把數(shù)組想象為首尾相接的循環(huán)結(jié)構(gòu),即圖中下面部分,這時(shí)候可以讓rear重新指向到0,以便重復(fù)利用空閑的位置。

所以:入列時(shí)rear++的操作,應(yīng)該稍做修正,當(dāng)rear到數(shù)組下標(biāo)最大值時(shí),讓它置0,以便能循環(huán)利用 (見(jiàn)后面的代碼)

另外還有一個(gè)問(wèn)題:最開(kāi)始時(shí)front與rear都為-1,即front==rear時(shí)表示隊(duì)列為空,改成循環(huán)以后,有可能會(huì)出現(xiàn)rear在循環(huán)過(guò)程中碰到front的情況,即真正意義的上"滿(mǎn)"狀態(tài),這時(shí)rear也同樣等于front,這樣就無(wú)法單純的用rear==front來(lái)判斷是滿(mǎn),還是空?這時(shí)可以浪費(fèi)一個(gè)元素的位置,認(rèn)為當(dāng)rear+1==front時(shí),隊(duì)列就已經(jīng)滿(mǎn)了,雖然犧牲了一個(gè)元素的空間,但卻換來(lái)了邏輯的正確性,還是值得的。

完整實(shí)現(xiàn)如下:

using System;
using System.Text;
namespace 棧與隊(duì)列
{
  /// <summary>
  /// 循環(huán)順序隊(duì)列
  /// </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) //如果已經(jīng)有元素出隊(duì)過(guò)
      {
        return (rear + 1) % maxsize == front;//為了區(qū)分與IsEmpty的區(qū)別,有元素出隊(duì)過(guò)以后,就只有浪費(fèi)一個(gè)位置來(lái)保持邏輯正確性.
      }
      else
      {
        return rear == maxsize - 1;
      }      
    }
    public void Enqueue(T item) 
    {
      if (IsFull()) 
      {
        Console.WriteLine("Queue is full");
        return;
      }
      if (rear == maxsize - 1) //如果rear到頭了,則循環(huán)重來(lái)(即解決偽滿(mǎn)問(wèn)題)
      {
        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(',');
    }
  }
}

測(cè)試代碼片段:

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();

當(dāng)然,隊(duì)列也可以用鏈表來(lái)實(shí)現(xiàn),相對(duì)要容易很多。

先定義鏈表中的節(jié)點(diǎn)Node.cs

namespace 棧與隊(duì)列
{
  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; }
    }
  }
}

為了方便,定義了很多構(gòu)造函數(shù)的重載版本,當(dāng)然這些只是浮云,重點(diǎn)是理解結(jié)構(gòu):data用來(lái)保存數(shù)據(jù),next指出下一個(gè)節(jié)點(diǎn)是誰(shuí)
鏈?zhǔn)疥?duì)列的完整實(shí)現(xiàn)LinkQueue.cs

using System;
using System.Text;
namespace 棧與隊(duì)列
{
  public class LinkQueue:IQueue
  {
    private Node front;//隊(duì)列頭
    private Node rear;//隊(duì)列尾
    private int num;//隊(duì)列元素個(gè)數(shù)
    /// 
    /// 構(gòu)造器
    /// 
    public LinkQueue() 
    {
      //初始時(shí)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);
    }
    //入隊(duì)
    public void Enqueue(T item) 
    {
      Node q = new Node(item);
      if (rear == null)//第一個(gè)元素入列時(shí)
      {
        front = rear = q;
      }
      else
      {
        //把新元素掛到鏈尾
        rear.Next = q;
        //修正rear指向?yàn)樽詈笠粋€(gè)元素
        rear = q;
      }
      //元素總數(shù)+1
      num++;
    }
    //出隊(duì)
    public T Dequeue() 
    {
      if (IsEmpty()) 
      {
        Console.WriteLine("Queue is empty!");
        return default(T);
      }
      //取鏈?zhǔn)自?
      Node p = front;
      //鏈頭指向后移一位
      front = front.Next;
      //如果此時(shí)鏈表為空,則同步修正rear
      if (front == null) 
      {
        rear = null;
      }
      num--;//個(gè)數(shù)-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(',');
    }
  }
}

希望本文所述對(duì)大家C#程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • C#中winform實(shí)現(xiàn)自動(dòng)觸發(fā)鼠標(biāo)、鍵盤(pán)事件的方法

    C#中winform實(shí)現(xiàn)自動(dòng)觸發(fā)鼠標(biāo)、鍵盤(pán)事件的方法

    這篇文章主要介紹了C#中winform實(shí)現(xiàn)自動(dòng)觸發(fā)鼠標(biāo)、鍵盤(pán)事件的方法,是C#程序設(shè)計(jì)中非常實(shí)用的功能,需要的朋友可以參考下
    2014-08-08
  • C#泛型運(yùn)作原理的深入理解

    C#泛型運(yùn)作原理的深入理解

    這篇文章主要給大家介紹了關(guān)于C#泛型運(yùn)作原理的深入理解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • C#編寫(xiě)的生辰八字計(jì)算程序

    C#編寫(xiě)的生辰八字計(jì)算程序

    這篇文章主要介紹了C#編寫(xiě)的生辰八字計(jì)算程序,假設(shè)一個(gè)人的公歷出生時(shí)間,范圍必須要在2012-2015年之間,因?yàn)楸臼纠绦蛑惶峁┝诉@幾年的農(nóng)歷數(shù)據(jù),小伙伴們參考下,可以自由擴(kuò)展
    2015-03-03
  • 用 C# 編寫(xiě)一個(gè)停放在任務(wù)欄上的圖標(biāo)程序

    用 C# 編寫(xiě)一個(gè)停放在任務(wù)欄上的圖標(biāo)程序

    用 C# 編寫(xiě)一個(gè)停放在任務(wù)欄上的圖標(biāo)程序...
    2007-03-03
  • Unity實(shí)現(xiàn)打磚塊游戲

    Unity實(shí)現(xiàn)打磚塊游戲

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)打磚塊游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • c#讀取文件詳談

    c#讀取文件詳談

    你平時(shí)是怎么讀取文件的?使用流讀取。是的沒(méi)錯(cuò),C#給我們提供了非常強(qiáng)大的類(lèi)庫(kù)(又一次吹捧了.NET一番)
    2013-09-09
  • C#簡(jiǎn)單讀取、改變文件的創(chuàng)建、修改及訪(fǎng)問(wèn)時(shí)間的方法

    C#簡(jiǎn)單讀取、改變文件的創(chuàng)建、修改及訪(fǎng)問(wèn)時(shí)間的方法

    這篇文章主要介紹了C#簡(jiǎn)單讀取、改變文件的創(chuàng)建、修改及訪(fǎng)問(wèn)時(shí)間的方法,涉及C#文件類(lèi)SetCreationTime、SetLastWriteTime及SetLastAccessTime的相關(guān)使用技巧,需要的朋友可以參考下
    2015-07-07
  • C#繪制橢圓的方法

    C#繪制橢圓的方法

    這篇文章主要介紹了C#繪制橢圓的方法,涉及C#圖形繪制的相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • C#中緩存的基本使用方法

    C#中緩存的基本使用方法

    項(xiàng)目開(kāi)發(fā)過(guò)程中緩存的應(yīng)用到處可見(jiàn),下面這篇文章主要給大家介紹了關(guān)于C#中緩存的基本使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • C#編程自學(xué)之?dāng)?shù)據(jù)類(lèi)型和變量一

    C#編程自學(xué)之?dāng)?shù)據(jù)類(lèi)型和變量一

    本節(jié)課我們將學(xué)習(xí)C#編程語(yǔ)言的數(shù)據(jù)類(lèi)型,數(shù)據(jù)類(lèi)型可以分為值類(lèi)型和引用類(lèi)型,接著介紹變量的使用方法和作用域等內(nèi)容,為了方便大家理解,我們還會(huì)舉一些小例子作為說(shuō)明。
    2015-10-10

最新評(píng)論