堆栈(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#语言版)》 清华大学出版社!!!