C#数据结构_栈和队列
栈:先进后出,只能在栈顶进行操作。
栈的操作主要包括在栈顶插入元素和删除元素、取栈顶元素和判断栈是否为空等。
栈的接口定义:
public interface IStack<T> { int GetLength(); //求栈的长度 bool IsEmpty(); //判断栈是否为空 void Clear(); //清空操作 void Push(T item); //入栈操作 T Pop(); //出栈操作 T GetTop(); //取栈顶元素 }
字段 top 表示栈顶,top 的范围是0 到 maxsize-1,如果顺序栈为空,top=-1
顺序栈类 SeqStack<T>的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class SeqStack<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 SeqStack(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 item) { if (IsFull()) { return; } data[++top] = item; } //出栈 public T Pop() { T tmp = default(T); if (IsEmpty()) { return tmp; } tmp = data[top]; --top; return tmp; } //获取栈顶元素 public T GetTop() { if (IsEmpty()) { return default(T); } return data[top]; } }
链栈 通常用单链表来表示,栈顶设在链表的头部,并且不需要头结点
链栈结点类(Node<T>)的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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; } //数据域属性 public T Data { get { return data; } set { data = value; } } //引用域 public Node<T> Next { get { return next; } set { next = value; } } }
链栈类 LinkStack<T>的实现: LinkStack<T>类增 设一个字段 num 表示链栈中结点的个数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class LinkStack<T> : IStack<T> { private Node<T> top; //栈顶指示器 private int num; //栈中结点的个数 //栈顶指示器属性 public Node<T> Top { get { return top; } set { top = value; } } //元素个数属性 public int Num { get { return num; } set { num = value; } } //构造器 public LinkStack() { Top = null; num = 0; } //求链栈的长度 public int GetLength() { return num; } //清空链栈 public void Clear() { top = null; num = 0; } //判断链栈是否为空 public bool IsEmpty() { if ((top == null) && (num == 0)) { return true; } else { return false; } } //入栈 public void Push() { Node<T> q = new Node<T>(item); if (top == null) { top = q; } else { q.Next = top; top = q; } ++num; } //出栈 public T Pop() { if (IsEmpty()) { return default(T); } Node<T> p = top; top = top.Next; --num; return p.Data; } //取栈顶结点的值 public T GetTop() { if (IsEmpty()) { return default(T); } return top.Data; } }
进制转换:将一个十进制数 N 转换为八进制数:利用辗转相 除法,转换得到的八进制数各个数位
算法思想如下:当 N>0 时,重复步骤 1 和步骤 2。
步骤 1:若 N≠0,则将 N%8 压入栈中,执行步骤 2;若 N=0。则将栈的内 容依次出栈,算法结束。
步骤 2:用 N/8 代替 N,返回步骤 1。
算法实现如下:
public void Conversion(int n) { LinkStack<int> s = new LinkStack<int>(); while(n > 0) { s.Push(n%8);//余数入栈 n = n/8; } while(!s.IsEmpty()) { n = s.Pop(); } }
括号匹配
算法思想:如果括号序列不为空,重复步骤 1。
步骤 1:从括号序列中取出 1 个括号,分为三种情况:
a) 如果栈为空,则将括号入栈;
b) 如果括号与栈顶的括号匹配,则将栈顶括号出栈。
c) 如果括号与栈顶的括号不匹配,则将括号入栈。
步骤 2:如果括号序列为空并且栈为空则括号匹配,否则不匹配。
用顺序栈实现算法:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public bool MatchBracket(char[] charlist) { SeqStack<char> s = new SeqStack<char>(50); int len = charlist.Length; for (int i = 0; i < len; ++i) { if (s.IsEmpty()) { s.Push(charlist[i]); } else if(((s.GetTop()=="(")&&(charlist[i]==")")))||(s.GetTop()=="[" && charlist[i]=="]")) { s.Pop(); } else { s.Push(charlist[i]); } } if (s.IsEmpty()) { return true; } else { return false; } }
队列(Queue)是插入操作限定在表的尾部,其它操作限定在表的头部进行的线性表。
队列的操作主要包括:在队尾插入元素、在队头删除元素、取队头元素和判断队列是否为空等。
队列“队尾入 队头出”的操作造成“假溢出”,解决假溢出的方法:将顺序队列看成是首尾相接的循环结构,头尾指示器的关系不变,这种队列叫循环顺序队列。
front 表示队头,front 的范围是 0 到 maxsize-1。 rear 表示队尾,rear 的范围也是 0 到 maxsize-1。
如果循环顺序队列为空,front=rear=-1。 当执行入队列操作时需要判断循环顺序队列是否已满。
如果循环顺序队列已满, (rear + 1) % maxsize==front ,循环顺序队列已满不能插入元素。
求循环队列中数据元素的个数:(rear-front+maxsize)%maxsize
循环顺序队列类 CSeqQueue<T>的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public 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(int size) { data = new T[size]; maxsize = size; front = rear = -1; } //求循环队列长度 public int GetLength() { return (rear - front + maxsize) % maxsize; } //清空循环队列 public void Clear() { front = rear = -1; } //判断循环队列是否为空 public bool IsEmpty() { if (front == rear) { return true; } else { return false; } } //判断循环顺序队列是否为满 public bool IsFull() { if ((rear + 1) % maxsize == front) { return true; } else { return false; } } //入队 public void In(T item) { if (IsFull()) { return; } else { data[++rear] = item; } } //出队 public T Out() { T tmp = default(T); if (IsEmpty()) { return tmp; } tmp = data[++front]; return tmp; } //获取队头数据元素 public T GetFront() { if (IsEmpty()) { return default(T); } return data[++front]; } }
链队列
队列结点类(Node<T>)的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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; } } }
链队列类 LinkQueue<T>的实现:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class LinkQueue<T> : IQueue<T> { private Node<T> front; //队列头指示器 private Node<T> rear; //队列尾指示器 private int num; //队列结点个数 //队头属性 public Node<T> Front { get{return front;} set{front=value;} } //队尾属性 public int Rear { get { return rear; } set { rear = value; } } //结点的个数 public int Num { get{return num;} set{num=value;} } //构造器 public LinkQueue(int size) { front=rear=-1; num=0; } //求循环队列长度 public int GetLength() { return num; } //清空循环队列 public void Clear() { front = rear = null; num=0; } //判断循环队列是否为空 public bool IsEmpty() { if (front == rear)&&(num==0) { return true; } else { return false; } } //入队 public void In(T item) { Node<T> q = new Node<T>(item); if (rear == null) { rear=q; } else { rear.Next=q; rear=q; } ++num; } //出队 public T Out() { if (IsEmpty()) { return default(T); } Node<T> p = front; front = front.Next; if(front == null) { rear=null; } --num; return p.Data; } //获取队头数据元素 public T GetFront() { if (IsEmpty()) { return default(T); } return front.Data; } }
判断一个字符串是否是回文:采用循环顺序队列和顺序栈 来实现
public bool Main() { SeqStack<char> s = new SeqStack<char>(50); CSeqQueue<char> q = new CSeqQueue<char>(50); string str = Console.ReadLine(); for(int i = 0; i < str.Length; ++i) { s.Push(str[i]); q.In(str[i]); } while(!s.IsEmpty() && !q.IsEmpty()) { if(s.Pop() != q.Out()) { return false; } } return true; }