1. 程式人生 > >棧和隊列

棧和隊列

-1 關系 數組 出棧 入棧 必須 ise pub 通過

棧和隊列:

棧和隊列是非常重要的兩種數據結構,在軟件設計中應用很多。棧和隊列也是線性結構,線性表、棧和隊列這三種數據結構的數據元素以及數據元素間的邏輯關系完全相同,差別是線性表的操作不受限制,而棧和隊列的操作受到限制。棧的操作只能在表的一端進行,隊列的插入操作在表的一端進行而其它操作在表的另一端進行,所以,把棧和隊列稱為操作受限的線性表。

棧(Stack)是操作限定在表的尾端進行的線性表。表尾由於要進行插入、刪除等操作,所以,它具有特殊的含義,把表尾稱為棧頂( Top),另一端是固定的,叫棧底( Bottom)。當棧中沒有數據元素時叫空棧(Empty Stack)。
棧通常記為: S
= (a1,a2,…,an),S是英文單詞stack的第 1 個字母。a1為棧底元素,an為棧頂元素。這n個數據元素按照a1,a2,…,an的順序依次入棧,而出棧的次序相反,an第一個出棧,a1最後一個出棧。所以,棧的操作是按照後進先出(Last In First Out,簡稱LIFO)或先進後出(First In Last Out,簡稱FILO)的原則進行的,因此,棧又稱為LIFO表或FILO表。棧的操作示意圖如圖所示。

技術分享

BCL中的棧:

C#2.0 一下版本只提供了非泛型的Stack類(存儲object類型)

C#2.0 提供了泛型的Stack<T>類

重要的方法如下
1,Push()入棧(添加數據) 2,Pop()出棧(刪除數據,返回被刪除的數據) 3,Peek()取得棧頂的數據,不刪除 4,Clear()清空所有數據 4,Count取得棧中數據的個數

棧的接口定義:

public interface IStack<T> {
        int Count{get;}
int GetLength(); //求棧的長度
bool IsEmpty(); //判斷棧是否為空
void Clear(); //清空操作
void Push(T item); //入棧操作
T Pop(); //出棧操作
T Peek(); //取棧頂元素
}

棧的存儲和代碼實現-1.1,順序棧:

用一片連續的存儲空間來存儲棧中的數據元素(使用數組),這樣的棧稱為順序棧(Sequence Stack)。類似於順序表,用一維數組來存放順序棧中的數據元素。棧頂指示器 top 設在數組下標為 0 的端, top 隨著插入和刪除而變化,當棧為空時,top=-1。下圖是順序棧的棧頂指示器 top 與棧中數據元素的關系圖。

技術分享

棧的存儲和代碼實現-1.2,順序棧:

class SeqStack<T>:IStack<T>

    {

        private T[] data;

        private int top;



        public SeqStack(int size)

        {

            data = new T[size];

            top = -1;

        }



        //默認構造數組的最大容量為10

        public SeqStack():this(10)

        {

        } 



        public int GetLength()

        {

            return top + 1;

        }



        public int Count

        {

            get

            {

                return GetLength();

            }

        }



        public bool IsEmpty()

        {

            return top <= -1;

        }



        public void Clear()

        {

            top = -1;

            Array.Clear(data,0,data.Length);

        }



        public void Push(T item)

        {

            data[top + 1] = item;

            top++;

        }

        /// <summary>

        /// 出棧

        /// </summary>

        /// <returns></returns>

        public T Pop()

        {

            T temp = data[top];

            top--;

            return temp;

        }



        public T Peek()

        {

            return data[top];

        }

    }

棧的存儲和代碼實現-2.1,鏈棧:

棧的另外一種存儲方式是鏈式存儲,這樣的棧稱為鏈棧(Linked Stack)。鏈棧通常用單鏈表來表示,它的實現是單鏈表的簡化。所以,鏈棧結點的結構與單鏈表結點的結構一樣,如圖 3.3 所示。由於鏈棧的操作只是在一端進行,為了操作方便,把棧頂設在鏈表的頭部,並且不需要頭結點。

2.2,鏈棧-鏈棧結點實現:

public class Node<T>
{
    private T data; //數據域
    private Node<T> next; //引用域
//構造器
    public Node(T val, Node<T> p)
    {
        data = val;
        next = p;
    }

//構造器
    public Node(Node<T> p)
    {
        next = p;
    }

//構造器
    public Node(T val)
    {
        data = val;
        next = null;
    }

//構造器
    public Node()
    {
        data = default(T);
        next = null;
    }

//數據域屬
    public T Data
    {
        get { return data; }
        set { data = value; }
    }
//引用域屬性
    public Node<T> Next
    {
        get { return next; }
        set { next = value; }
    }
}

2.3,鏈棧-代碼實現:

技術分享

把鏈棧看作一個泛型類,類名為 LinkStack<T>。 LinkStack<T>類中有一個字段 top 表示棧頂指示器。由於棧只能訪問棧頂的數據元素,而鏈棧的棧頂指示器又不能指示棧的數據元素的個數。所以,求鏈棧的長度時,必須把棧中的數據元素一個個出棧,每出棧一個數據元素,計數器就增加 1,但這樣會破壞棧的結構。為保留棧中的數據元素,需把出棧的數據元素先壓入另外一個棧,計算完長度後,再把數據元素壓入原來的棧。但這種算法的空間復雜度和時間復雜度都很高,所以,以上兩種算法都不是理想的解決方法。理想的解決方法是 LinkStack<T>類增設一個字段 num 表示鏈棧中結點的個數。

隊列:

隊列(Queue)是插入操作限定在表的尾部而其它操作限定在表的頭部進行的線性表。把進行插入操作的表尾稱為隊尾(Rear),把進行其它操作的頭部稱為隊頭(Front)。當隊列中沒有數據元素時稱為空隊列(Empty Queue)。
隊列通常記為: Q= (a1,a2,…,an),Q是英文單詞queue的第 1 個字母。a1為隊頭元素,an為隊尾元素。這n個元素是按照a1,a2,…,an的次序依次入隊的,出對的次序與入隊相同,a1第一個出隊,an最後一個出隊。所以,對列的操作是按照先進先出(First In First Out)或後進後出( Last In Last Out)的原則進行的,因此,隊列又稱為FIFO表或LILO表。隊列Q的操作示意圖如圖所示。
在實際生活中有許多類似於隊列的例子。比如,排隊取錢,先來的先取,後來的排在隊尾。
隊列的操作是線性表操作的一個子集。隊列的操作主要包括在隊尾插入元素、在隊頭刪除元素、取隊頭元素和判斷隊列是否為空等。與棧一樣,隊列的運算是定義在邏輯結構層次上的,而運算的具體實現是建立在物理存儲結構層次上的。因此,把隊列的操作作為邏輯結構的一部分,每個操作的具體實現只有在確定了隊列的存儲結構之後才能完成。隊列的基本運算不
是它的全部運算,而是一些常用的基本運算。

技術分享

BCL 中的隊列:

C#2.0 以下版本提供了非泛型的Queue類

C#2.0 提供了泛型Queue<T>類
方法
1,Enqueue()入隊(放在隊尾)
2,Dequeue()出隊(移除隊首元素,並返回被移除的元素)
3,Peek()取得隊首的元素,不移除
4,Clear()清空元素
屬性
5,Count獲取隊列中元素的個數

隊列接口定義:

public interface IQueue<T> {
        int Count{get;}//取得隊列長度的屬性
int GetLength(); //求隊列的長度
bool IsEmpty(); //判斷對列是否為空
void Clear(); //清空隊列
void Enqueue(T item); //入隊
T Dequque(); //出隊
T Peek(); //取隊頭元素
}

1.1 順序隊列:

用一片連續的存儲空間來存儲隊列中的數據元素,這樣的隊列稱為順序隊列(Sequence Queue)。類似於順序棧,用一維數組來存放順序隊列中的數據元素。隊頭位置設在數組下標為 0 的端,用 front 表示;隊尾位置設在數組的另一端,用 rear 表示。 front 和 rear 隨著插入和刪除而變化。當隊列為空時, front=rear=-1。

圖是順序隊列的兩個指示器與隊列中數據元素的關系圖。

技術分享

1.2 順序隊列-(循環順序隊列):

如果再有一個數據元素入隊就會出現溢出。但事實上隊列中並未滿,還有空閑空間,把這種現象稱為“假溢出”。這是由於隊列“隊尾入隊頭出”的操作原則造成的。解決假溢出的方法是將順序隊列看成是首尾相接的循環結構,頭尾指示器的關系不變,這種隊列叫循環順序隊列(Circular sequence Queue)。循環隊列如圖所示。

技術分享

1.3 順序隊列-代碼實現:

把循環順序隊列看作是一個泛型類,類名叫 CSeqStack<T>,“ C”是英文單詞 circular 的第 1 個字母。 CSeqStack<T>類實現了接口 IQueue<T>。用數組來存儲循環順序隊列中的元素,在 CSeqStack<T>類中用字段 data 來表示。用字段maxsize 表示循環順序隊列的容量, maxsize 的值可以根據實際需要修改,這通過CSeqStack<T>類的構造器中的參數 size 來實現,循環順序隊列中的元素由 data[0]開始依次順序存放。字段 front 表示隊頭, front 的範圍是 0 到 maxsize-1。字段 rear表示隊尾,rear 的範圍也是 0 到 maxsize-1。如果循環順序隊列為空,front=rear=-1。當執行入隊列操作時需要判斷循環順序隊列是否已滿,如果循環順序隊列已滿,(rear + 1) % maxsize==front , 循 環 順 序 隊 列 已 滿 不 能 插 入 元 素 。 所 以 ,CSeqStack<T>類除了要實現接口 IQueue<T>中的方法外,還需要實現判斷循環順序隊列是否已滿的成員方法。

2.1鏈隊列:

隊列的另外一種存儲方式是鏈式存儲,這樣的隊列稱為鏈隊列(Linked Queue)。同鏈棧一樣,鏈隊列通常用單鏈表來表示,它的實現是單鏈表的簡化。所以,鏈隊列的結點的結構與單鏈表一樣,如圖所示。由於鏈隊列的操作只是在一端進行,為了操作方便,把隊頭設在鏈表的頭部,並且不需要頭結點。

2.2鏈隊列-鏈隊列結點類:

技術分享

public class Node<T>
{
private T data; //數據域
private Node<T> next; //引用域
//構造器
public Node(T val, Node<T> p)
{
    data = val;
    next = p;
}
//構造器
public Node(Node<T> p)
{
    next = p;
}
//構造器
public Node(T val)
{
    data = val;
    next = null;
}
//構造器
public Node()
{
    data = default(T);
    next = null;
}
//數據域屬性
public T Data
{
get
{
return data;
}
set
{
data = value;
}
}
//引用域屬性
public Node<T> Next
{
get
{
return next;
}
set
{
next = value;
}
}
}

2.3鏈隊列-代碼實現:

把鏈隊列看作一個泛型類,類名為 LinkQueue<T>。 LinkQueue<T>類中有兩個字段 front 和 rear,表示隊頭指示器和隊尾指示器。由於隊列只能訪問隊頭的數據元素,而鏈隊列的隊頭指示器和隊尾指示器又不能指示隊列的元素個數,所以,與鏈棧一樣,在 LinkQueue<T>類增設一個字段 num 表示鏈隊列中結點的個數。

棧和隊列的應用舉例:

編程判斷一個字符串是否是回文。回文是指一個字符序列以中間字符為基準兩邊字符完全相同,如字符序列“ ACBDEDBCA”是回文。

算法思想:判斷一個字符序列是否是回文,就是把第一個字符與最後一個字符相比較,第二個字符與倒數第二個字符比較,依次類推,第 i 個字符與第 n-i個字符比較。如果每次比較都相等,則為回文,如果某次比較不相等,就不是回文。因此,可以把字符序列分別入隊列和棧,然後逐個出隊列和出棧並比較出隊列的字符和出棧的字符是否相等,若全部相等則該字符序列就是回文,否則就不是回文。

棧和隊列