C# 數據結構 之 堆棧和隊列


堆棧(Stack)是一種特殊的線性表,是一種操作只允許在尾端進行插入或刪除等操作的線性表。表尾允許進行插入刪除操作,稱為棧頂(Top),另一端是固定的,稱為棧底(Bottom).棧的操作使按照先進后出或后進先出的原則進行的。

用一片連續的存儲空間來存儲棧中的數據元素,稱為順序棧(Sequence Stack)。類似於順序表,用一維數組來存放棧中的數據元素。缺點:浪費存儲空間。

用鏈式存儲結構來存儲的棧為鏈棧(Linked Stack).鏈棧通常用單鏈表來表示。

Stack
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DataStructure
{

    interface IStack<T>
    {
        void Push(T item);           //入棧操作
        T Pop();                     //出棧操作
        T GetTop();                  //取棧頂元素
        int GetLength();             //求棧的長度
        bool IsEmpty();              //判斷棧是否為空
        void Clear();                //清空操作
    }
    /// <summary>
    /// 順序棧
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class SequenceStack<T> : IStack<T>
    {
        private int maxsize;       //順序棧的容量
        private T[] data;          //數組,用於存儲順序棧中的數據元素
        private int top;           //指示順序棧的棧頂

        //索引器
        public T this[int index]
        {
            get { return data[index]; }
            set { data[index] = value; }
        }

        //容量屬性
        public int Maxsize
        {
            get { return maxsize; }
            set { maxsize = value; }
        }

        //棧頂屬性
        public int Top
        {
            get
            {
                return top;
            }
        }

        public SequenceStack(int size)
        {
            data = new T[size];
            maxsize = size;
            top = -1;
        }

        //求棧的長度
        public int GetLength()
        {
            return top + 1;
        }
        //清空順序棧
        public void Clear()
        {
            top = -1;
        }
        //判斷順序棧是否為空
        public bool IsEmpty()
        {
            if (top == -1)
            {
                return true;
            }
            else
                return false;
        }
        //判斷棧是否為滿
        public bool IsFull()
        {
            if (top == maxsize - 1)
            {
                return true;
            }
            else
                return false;
        }

        //入棧
        public void Push(T elem)
        {
            if (IsFull())
            {
                Console.WriteLine("Stack is Full !");
                return;
            }
            data[++top] = elem;
 
        }

        //出棧
        public T Pop()
        {
            T tem = default(T);
            if (IsEmpty())
            {
                Console.WriteLine("Stack is Empty !");
                return default(T);
            }
            tem = data[top];
            --top;
            return tem;
        }

        //獲取棧頂元素
        public T GetTop()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Stack is Empty !");
                return default(T);
            }
            return data[top];
        }

    }

    /// <summary>
    /// 用順序棧解決火車車廂重排問題
    /// </summary>
    class TrainArrangwBySeqStack
    {
        //車廂重排算法,K個緩沖鐵軌,車廂初始排序存放在P中
        public  bool RailRoad(int[] p, int n, int k)
        {
            //創建與緩沖鐵軌對應的堆棧
            SequenceStack<int>[] H;
            H = new SequenceStack<int>[k + 1];
            for (int i = 0; i <= k; i++)
                H[i] = new SequenceStack<int>(p.Length);
            int NowOut = 1;     //下次要輸出的車廂
            int minH = n + 1;   //緩沖鐵軌中編號最小的車廂
            int minS = 0;       //minH號車廂對應的緩沖鐵軌

            //車廂重排
            for (int i = 0; i < n; i++)
            {
                if (p[i] == NowOut)
                {
                    Console.WriteLine("Move car {0} from input to output", p[i]);
                    NowOut++;
                    //從緩沖鐵軌中輸出
                    while (minH == NowOut)
                    {
                        Output(ref minH, ref minS, ref H, k, n);
                        NowOut++;
                    }
                }
                else
                {
                    if (!Hold(p[i], ref minH, ref minS, ref H, k, n))
                    {
                        return false;
                    }
                }
            }
                return true;
        }

        //在一個緩沖區中放入車廂C
        public bool Hold(int c, ref int minH, ref int minS, ref SequenceStack<int>[] H, int k, int n)
        {
            //如果沒有可用的緩沖鐵軌,則返回false
            //否則返回true
            //為車廂c尋找最優的鐵軌
            //初始化

            int BestTrack = 0;       //目前最優的鐵軌
            int BestTop = n + 1;     //最優鐵軌上的頭輛車廂
            int x;                   //車廂索引

            //掃描緩沖鐵軌
            for (int i = 1; i <= k; i++)//!!!i=1
            {
                if (!H[i].IsEmpty())
                {
                    //鐵軌i不為空
                    x = H[i][H[i].Top];
                    if (c < x && x < BestTop)
                    {
                        //鐵軌i頂部的車廂編號最小
                        BestTop = x;
                        BestTrack = i;
                    }
                }
                else//鐵軌i為空
                {
                    if (BestTrack == 0)
                    {
                        BestTrack = i;
                    }
                    break;
                }
            }
            if (BestTrack == 0)
                return false;//沒有可用鐵軌
           
            //把車廂c送入緩沖鐵軌
            H[BestTrack].Push(c);
            Console.WriteLine("Move car{0} from input to holding track {1}", c, BestTrack);
            //必要時修改minH minS
            if (c < minH)
            {
                minH = c;
                minS = BestTrack;
            }
            return true;
        }

        //把車廂從緩沖區鐵軌送至出軌處,同時修改minH minS
        public void Output(ref int minH, ref int minS, ref SequenceStack<int>[] H, int k, int n)
        {
            int c;//車廂索引
            //從堆棧minS中刪除編寫、好最小的車廂minH
            c = H[minS].Pop();
            Console.WriteLine("Move car{0} from holding track {1} to output", minH, minS);
            //通過檢查所有的棧頂,搜索新的minH minS
            minH = n + 2;
            for (int i = 1; i <= k; i++)
            {
                if (!H[i].IsEmpty() && (c = H[i][H[i].Top]) < minH)
                {
                    minH = c;
                    minS = i;
                }
            }
        }
    }

    /// <summary>
    /// 鏈棧結點
    /// </summary>
    class StackNode<T>
    {
        private T data;               //數據域
        private StackNode<T> next;    //引用域

        public StackNode()
        {
            data = default(T);
            next = null;
        }

        public StackNode(T val)
        {
            data = val;
            next = null;
        }

        public StackNode(T val, StackNode<T> p)
        {
            data = val;
            next = p;
        }

        //數據域屬性
        public T Data
        {
            get { return data; }
            set { data = value; }
        }

        //引用域屬性
        public StackNode<T> Next
        {
            get { return next; }
            set { next = value; }
        }



    }

    /// <summary>
    /// 鏈棧
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class LinkStack<T> : IStack<T>
    {
        private StackNode<T> top;     //棧頂指示器
        private int size;             //棧中元素的個數

        //棧頂指示器屬性
        public StackNode<T> Top
        {
            get { return top; }
            set { top = value; }
        }

        //元素個數屬性
        public int Size
        {
            get { return size; }
            set { size = value; }
        }

        public LinkStack()
        {
            top = null;
            size = 0;
        }


        //判斷鏈棧是否為空
        public bool IsEmpty()
        {
            if ((top == null) && (size == 0))
                return true;
            else
                return false;
        }


        public int GetLength()
        {
            return size;
        }

        public void Clear()
        {
            top = null;
            size = 0;
        }

        //入棧操作
        //在單鏈表的起始處插入一個結點
        public void Push(T item)
        {
            StackNode<T> q = new StackNode<T>(item);
            if (top == null)
            {
                top = q;
            }
            else
            {
                //將新結點的next指向棧頂指示器top所指向的結點
                q.Next = top;
                //將棧頂指示器top指向新結點
                top = q;
            }
            ++size;
        }

        //出棧操作
        public T Pop()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Stack is empty !");
                return default(T);
            }
            StackNode<T> p = top;
            top = top.Next;
            --size;
            return p.Data;
        }

        //獲取棧頂結點的值
        public T GetTop()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Stack is empty !");
                return default(T);
            }
            return top.Data;
        }
    }

    /// <summary>
    /// 用鏈棧解決火車車廂重排問題
    /// </summary>
    class TrainArrangeByLinkStack
    {
        //k個緩沖鐵軌,車廂初始排序存儲在p中
        public bool RailRoad(int[] p, int n, int k)
        {
            //創建與緩沖鐵軌對應的堆棧
            LinkStack<int>[] H;
            H = new LinkStack<int>[k + 1];
            for (int i = 1; i <= k; i++)
            {
                H[i] = new LinkStack<int>();
            }

            int NowOut = 1;     //下一次要輸出的車廂
            int minH = n + 1;   //緩沖鐵軌中編號最小的車廂
            int minS = 0;       //minH號車廂對應的緩沖鐵軌

            //車廂重排
            for (int i = 0; i < n; i++)
            {
                if (p[i] == NowOut)
                {
                    Console.WriteLine("Move car {0} from input to output", p[i]);
                    NowOut++;

                    //從緩沖鐵軌中輸出
                    while (minH == NowOut)
                    {
                        Output(ref minH, ref minS, ref H, k, n);
                        NowOut++;
                    }
                }
                else
                {
                    //將p[i]送入緩沖鐵軌
                    if (!Hold(p[i], ref minH, ref minS, ref H, k, n))
                        return false;
                }
            }
            return true;
        }

        //在一個緩沖鐵軌中放入車廂c
        public bool Hold(int c, ref int minH, ref int minS, ref LinkStack<int>[] H, int k, int n)
        {
            //如果沒有可用緩沖鐵軌,則返回false
            //否則返回true
            //為車廂c尋找最優的緩沖鐵軌
            //初始化
            int BestTrack = 0;             //目前最優的鐵軌
            int BestTop = n + 1;           //最優鐵軌上的頭輛車廂
            int x;                         //車廂索引

            //掃描緩沖鐵軌
            for (int i = 1; i <= k; i++)
            {
                if (!H[i].IsEmpty())
                {
                    //鐵軌不為空
                    x = H[i].Top.Data;
                    if (c < x && x < BestTop)
                    {
                        BestTop = x;
                        BestTrack = i;
                    }
                }
                else
                {
                    if (BestTrack == 0)
                        BestTrack = i;
                    break;
                }
            }
            if (BestTrack == 0)
                return false;//沒有可用鐵軌
            //把車廂c送入緩沖鐵軌
            H[BestTrack].Push(c);
            Console.WriteLine("Move car {0} from input to holding track {1}", c, BestTrack);

            if (c < minH)
            {
                minH = c;
                minS = BestTrack;
            }
            return true;
        }

        //把車廂從緩沖鐵軌送至出軌處,同時修改minH minS
        public void Output(ref int minH,ref int minS ,ref LinkStack <int>[] H,int k,int n)
        {
            int c;         //車廂索引
            c = H[minS].Pop();
            Console.WriteLine("Move car {0} form holding track {1} to output", minH, minS);
            //通過檢查所有的棧頂,搜索新的minH和minS
            minH = n + 2;
            for (int i = 1; i <= k; i++)
            {
                if (!H[i].IsEmpty() && (c = H[i].Top.Data) < minH)
                {
                    minH = c;
                    minS = i;
                }
            }
        }
    }

    class Stack
    {

        static void Main()
        {
            int[] p = new int[] { 3, 6, 9, 2, 4, 7, 1, 8, 5 };
            int k = 3;


            //用順序棧解決火車車廂重排問題
            TrainArrangwBySeqStack tas = new TrainArrangwBySeqStack();
            bool results;
            results = tas.RailRoad(p, p.Length, k);
            do
            {
                if (results == false)
                {
                    Console.WriteLine("need more holding track, please enter additional number:");
                    k = k + Convert.ToInt32(Console.ReadLine());
                    results = tas.RailRoad(p, p.Length, k);
                }
            } while (results == false);
                Console.ReadLine();


            //用鏈棧解決火車車廂重排問題
            TrainArrangeByLinkStack ta = new TrainArrangeByLinkStack();
            bool result;
            result = ta.RailRoad(p, p.Length, k);
            do
            {
                if (result == false)
                {
                    Console.WriteLine("need more holding track,please enter additional number:");
                    k = k + Convert.ToInt32(Console.ReadLine());
                    result = ta.RailRoad(p, p.Length, k);
                }
            } while (result == false);
            Console.ReadLine();
        }
    }
}

隊列(Queue)是插入操作限定在表的尾部而其他操作限定在表的頭部進行的線性表。把進行插入操作的表尾稱為隊尾(Rear).把進行其他操作的頭部稱為隊頭(Front).

隊列的操作使按照先進先出后進后出的原則進行的。

用一片連續的存儲空間來存儲隊列中的數據元素,稱為順序隊列(Sequence Queue)。類似於順序表,用一維數組來存放隊列中的數據元素。

解決順序隊列的假溢出的方法是將順序隊列看成是首位相接的循環結構,叫循環順序隊列(Circular sequence Queue)

隊列的另外一種存儲方式是鏈式存儲,稱為鏈隊列(Linked Queue)。通常用單鏈表表示。

Queue
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace DataStructure
{
    /// <summary>
    /// 隊列接口
    /// </summary>
    interface IQueue<T>
    {
        void EnQueue(T elem);         //入隊列操作
        T DeQueue();                  //出隊列操作
        T GetFront();                 //取對頭元素
        int GetLength();              //求隊列的長度
        bool IsEmpty();               //判斷隊列是否為空
        void Clear();                 //清空隊列
        bool IsFull();                //判斷隊列是否為滿
    }

    /// <summary>
    /// 銀行隊列接口
    /// </summary>
    interface IBankQueue : IQueue<int>
    {
        int GetCallnumber();          //獲取服務號碼
    }


    /// <summary>
    /// 循環順序隊列
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class CSeqQueue<T> : IQueue<T>
    {
        private int maxsize;       //循環順序隊列的容量
        private T[] data;          //數組,用於存儲循環順序隊列中的數據元素
        private int front;         //指示最近一個已經離開隊列的元素所占有的位置 循環順序隊列的對頭
        private int rear;          //指示最近一個進入隊列的元素的位置           循環順序隊列的隊尾

        public T this[int index]
        {
            get { return data[index]; }
            set { data[index] = value; }
        }

        //容量屬性
        public int Maxsize
        {
            get { return maxsize; }
            set { maxsize = value; }
        }

        //對頭指示器屬性
        public int Front
        {
            get { return front; }
            set { front = value; }
        }

        //隊尾指示器屬性
        public int Rear
        {
            get { return rear; }
            set { rear = value; }
        }

        public CSeqQueue()
        {
 
        }

        public CSeqQueue(int size)
        {
            data = new T[size];
            maxsize = size;
            front = rear = -1;
        }

        //判斷循環順序隊列是否為滿
        public bool IsFull()
        {
            if ((front == -1 && rear == maxsize - 1) || (rear + 1) % maxsize == front)
                return true;
            else
                return false;
        }

        //清空循環順序列表
        public void Clear()
        {
            front = rear = -1;
        }

        //判斷循環順序隊列是否為空
        public bool IsEmpty()
        {
            if (front == rear)
                return true;
            else
                return false;
        }

        //入隊操作
        public void EnQueue(T elem)
        {
            if (IsFull())
            {
                Console.WriteLine("Queue is Full !");
                return;
            }
            rear = (rear + 1) % maxsize;
            data[rear] = elem;
        }

        //出隊操作
        public T DeQueue()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is Empty !");
                return default(T);
            }
            front = (front + 1) % maxsize;
            return data[front];
        }

        //獲取對頭數據元素
        public T GetFront()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is Empty !");
                return default(T);
            }
            return data[(front + 1) % maxsize];//front從-1開始
        }

        //求循環順序隊列的長度
        public int GetLength()
        {
            return (rear - front + maxsize) % maxsize;
        }
    }

    /// <summary>
    /// 鏈隊列結點類
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class QueueNode<T>
    {
        private T data;                   //數據域
        private QueueNode<T> next;        //引用域

        public QueueNode(T val, QueueNode<T> p)
        {
            data = val;
            next = p;
        }

        public QueueNode(QueueNode<T> p)
        {
            next = p;
        }

        public QueueNode(T val)
        {
            data = val;
            next = null;
        }

        public QueueNode()
        {
            data = default(T);
            next = null;
        }

        //數據域屬性
        public T Data
        {
            get { return data; }
            set { data = value; }
        }

        //引用域屬性
        public QueueNode<T> Next
        {
            get { return next; }
            set { next = value; }
        }
    }

    /// <summary>
    /// 鏈隊列類
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class LinkQueue<T> : IQueue<T>
    {
        private QueueNode<T> front;    //隊列頭指示器
        private QueueNode<T> rear;     //隊列尾指示器
        private int size;              //隊列結點個數

        //隊列屬性
        public QueueNode<T> Front
        {
            get { return front; }
            set { front = value; }
        }

        public QueueNode<T> Rear
        {
            get { return rear; }
            set { rear = value; }
        }

        public int Size
        {
            get { return size; }
            set { size = value; }
        }

        //初始化鏈隊列
        public LinkQueue()
        {
            front = rear = null;
            size = 0;
        }

        public int GetLength()
        {
            return size;
        }

        public void Clear()
        {
            front = rear = null;
            size = 0;
        }

        public bool IsEmpty()
        {
            if ((front == rear) && (size == 0))
                return true;
            else
                return false;

        }

        //鏈隊列沒有容量限制 返回false
        public bool IsFull()
        {
            return false;
        }

        //入隊操作
        public void EnQueue(T item)
        {
            QueueNode<T> q = new QueueNode<T>(item);
            if (IsEmpty())
            {
                front = q;
                rear = q;
            }
            else
            {
                rear.Next = q;
                rear = q;
            }
            ++size;
        }

        //出對操作
        public T DeQueue()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is Empty !");
                return default(T);
            }
            QueueNode<T> p = front;
            front = front.Next;

            if (front == null)
            {
                rear = null;
            }
            --size;
            return p.Data;
        }

        //獲取鏈隊列頭結點的值
        public T GetFront()
        {
            if (IsEmpty())
            {
                Console.WriteLine("Queue is Empty !");
                return default(T);
            }
            return front.Data;
        }
 
    }


    /// <summary>
    /// 銀行叫號鏈隊列類
    /// </summary>
    class LinkBankQueue : LinkQueue<int>, IBankQueue
    {
        private int callnumber;

        public int Callnumber
        {
            get { return callnumber; }
            set { callnumber = value; }
        }

        //獲取服務號碼
        public int GetCallnumber()
        {
            if ((IsEmpty()) && callnumber == 0)
            {
                callnumber = 1;
            }
            else
                callnumber++;
            return callnumber;
        }
    }

    /// <summary>
    /// 銀行叫號順序隊列類
    /// </summary>
    class CSeqBankQueue : CSeqQueue<int>, IBankQueue
    {
        private int callnumber;  //記錄系統自動產生的新來顧客的服務號碼

        public int Callnumber
        {
            get { return callnumber; }
            set { callnumber = value; }
        }

        public CSeqBankQueue()
        {
 
        }

        public CSeqBankQueue(int size)
            : base(size)
        {
 
        }

        //獲得服務號碼
        public int GetCallnumber()
        {
            if ((IsEmpty()) && callnumber == 0)
            {
                callnumber = 1;
            }
            else
            {
                callnumber++;
            }
            return callnumber;
        }
    }

    /// <summary>
    /// 服務窗口類
    /// </summary>
    class ServiceWindow
    {
        IBankQueue bankQ;

        //服務隊列屬性
        public IBankQueue BankQ
        {
            get { return bankQ; }
            set { bankQ = value; }
        }

        public void Service()
        {
            while (true)
            {
                Thread.Sleep(10000);
                if (!bankQ.IsEmpty())
                {
                    Console.WriteLine();
                    lock (bankQ)
                    {
                        Console.WriteLine("請{0}號到{1}號窗口!", bankQ.DeQueue(), Thread.CurrentThread.Name);
                    }
                }
            }
        }
    }

    class Queue
    {

        static void Main()
        {
            IBankQueue bankQueue = null;
            Console.WriteLine("請選擇存儲結構的類型:1.順序隊列 2.鏈隊列:");
            char selectFlag = Convert.ToChar(Console.ReadLine());
            switch (selectFlag)
            {
                /*初始化順序隊列*/
                case '1':
                    int count;             //接受循環順序隊列的容量
                    Console.WriteLine("請輸入隊列可容納的人數:");
                    count = Convert.ToInt32(Console.ReadLine());
                    bankQueue = new CSeqBankQueue(count);
                    break;
                /*初始化鏈隊列*/
                case '2':
                    bankQueue = new LinkBankQueue();
                    break;

            }
            int windowcount = 4;       //設置銀行櫃台的服務窗口數

            ServiceWindow[] sw = new ServiceWindow[windowcount];
            Thread[] swt = new Thread[windowcount];
            for (int i = 0; i < windowcount; i++)
            {
                sw[i] = new ServiceWindow();
                sw[i].BankQ = bankQueue;
                swt[i] = new Thread(new ThreadStart(sw[i].Service));
                swt[i].Name = "" + (i + 1);
                swt[i].Start();
            }
            while (true)
            {
                Console.WriteLine("請點擊觸摸屏獲取號碼:");
                Console.ReadLine();

                int callnumber;
                if (!bankQueue.IsFull())
                {
                    callnumber = bankQueue.GetCallnumber();
                    Console.WriteLine("您的號碼是:{0},您前面有{1}位,請等待!", callnumber, bankQueue.GetLength());
                    bankQueue.EnQueue(callnumber);
                }
                else
                    Console.WriteLine("現在業務繁忙,請稍后再來!");
                Console.WriteLine();
            }
        }
    }
}

注:本文整理自《數據結構(C#語言版)》 清華大學出版社!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM