栈
栈是仅在表尾进行插入或删除操作的线性表,又称 后进先出 的线性表
- 栈接口设计
interface Stack <T>{ void destroyStack(); boolean isEmpty(); int stackLength(); T getTop(); //取栈顶元素 void Push(T element); //进栈操作 T Pop(); //出栈操作 void stackTraverse(); }
顺序栈
以顺序表基础的栈实现
- 实现代码
public class SqStack<T> implements Stack<T> { private final int MAX_SIZE = 10; //栈的最大容量 private Object[] array; //基于数组的顺序栈 private int length; //栈内元素个数 private int top; //栈顶标识 private int base;//栈底标识 public SqStack() { //初始化栈 array = new Object[MAX_SIZE]; //初始化栈的最大容量 length = 0; top = 0; base = 0; } @Override public void destroyStack() { // TODO Auto-generated method stub top = 0; length = 0; } @Override public boolean isEmpty() { // TODO Auto-generated method stub if(this.length == 0) return true; else return false; } @Override public int stackLength() { // TODO Auto-generated method stub return length; } @Override public T getTop() { //去栈顶元素 // TODO Auto-generated method stub return (T)array[top - 1]; //返回栈顶元素 } @Override public void Push(T element) { //进栈操作 // TODO Auto-generated method stub array[top++] = element; length++; } @Override public T Pop() {//出栈操作 // TODO Auto-generated method stub length--; return (T) array[--top]; //返回栈顶元素,top减一 } @Override public void stackTraverse() { //从栈底依次向栈顶遍历 // TODO Auto-generated method stub for(int i = base; i< top; i++) { System.out.print(array[i] + " "); } System.out.println(); } }
- 代码解析
- 顺序栈的长度就是top标识的索引值,length属性可有可无。
- 出栈操作先返回栈顶元素,再top–而代码中为
return (T) array[--top];
因为数组中的元素为 array[0]~array[top-1]
链式栈
以链表为基础的栈实现
- 代码实现
class LinkStack<T> implements Stack<T> { private class Node{ //节点类 private Node next; //后继引用 private T dataElement; public Node() { //构造头节点 // TODO Auto-generated constructor stub this.next = null; //节点中的next(连接下一个节点) this.dataElement = null; } public Node(T dataElement) { //构造尾节点 // TODO Auto-generated constructor stub this.next = null; this.dataElement = dataElement; } } private Node top;//栈顶结点 private Node base;//栈底结点(这里栈底结点就是头节点) private int length; public LinkStack() { // TODO Auto-generated constructor stub base = new Node(); //初始化栈底结点 top = base; length = 0; } @Override public void destroyStack() { //重置栈 // TODO Auto-generated method stub top = base; length = 0; } @Override public boolean isEmpty() { // TODO Auto-generated method stub if(this.length == 0) return true; else return false; } @Override public int stackLength() { // TODO Auto-generated method stub return length; } @Override public T getTop() { // TODO Auto-generated method stub return top.dataElement; } @Override public void Push(T element) { //进栈操作 // TODO Auto-generated method stub //链栈所构造的链表是一个倒过来的常规单向链表 Node newNode = new Node(element); newNode.next = top; top = newNode; length++; } @Override public T Pop() { //出栈操作 // TODO Auto-generated method stub T data = top.dataElement; top = top.next; length--; return data; } @Override public void stackTraverse() { //遍历 // TODO Auto-generated method stub Node currentNode = top; while(currentNode.next != null) { System.out.print( currentNode.dataElement + " "); currentNode = currentNode.next; } System.out.println(); } }
- 代码解析
-
栈的push操作
栈的进栈操作将新结点新结点的后继引用指向top结点,而base结点为最底层的头节点,所以链栈实际上的一个倒过来的常规单向链表,最上层为新进结点。
-
栈的出栈操作
将top结点返回,并将top重置为top的后继结点
-
队列
队列是一种先进先出的线性表
- 队列接口设计
interface Queue<T> { void destroy();//重置队列 boolean isEmpty(); int queueLength(); T getHead();//去对头元素 void enQueue(T element); //进队列 T deQueue();//出队列 void queueTraverse(); //队列的遍历 }
顺序队列
以顺序表为基础实现的队列
- 代码实现
class SqQueue<T> implements Queue<T> { private final int MAX_SIZE = 10; //队列的最大容量 private Object[] array; //数组容器 private int front;//队头 private int rear;//对尾 public SqQueue() { //初始化队列 // TODO Auto-generated constructor stub array = new Object[MAX_SIZE]; front = rear = 0; } @Override public void destroy() { //重置队列 // TODO Auto-generated method stub rear = front; //当队尾等于对头时,队列就为空队列 } @Override public boolean isEmpty() { // TODO Auto-generated method stub if(front == rear) return true; else return false; } @Override public int queueLength() {//取队列长度 // TODO Auto-generated method stub return (rear - front + MAX_SIZE) % MAX_SIZE;//队列长度算法 } @Override public T getHead() { // TODO Auto-generated method stub return (T) array[front]; } @Override public void enQueue(T element) { //添加数据 // TODO Auto-generated method stub if((rear + 1) % MAX_SIZE == front) //判断队列是否已满 System.out.println("队列已满,无法添加"); else { array[rear] = element;//数据入队 rear = (rear + 1) % MAX_SIZE; //队尾往后移动一位 } } @Override public T deQueue() { //返回对头元素,并删除 // TODO Auto-generated method stub if( isEmpty() ) System.out.println("队列为空,无法删除"); else { T temp = (T) array[front];//数据出队 front = (front + 1) % MAX_SIZE; //队头往后移动一位 return temp; } return null; } @Override public void queueTraverse() { //遍历 // TODO Auto-generated method stub int temp = front; //不能直接对front操作(影响结果) while(temp != rear) { System.out.print(array[temp] + " "); temp = (temp + 1) % MAX_SIZE; } System.out.println(); } }
- 代码解析
-
队列的front,rear移动问题
相较于栈添加和删除元素只有栈顶top移动不同,队列进队时rear向后移动,出队时front向后移动,所以当front向后移动时之前的内存就会出现浪费所以为了使rear到达数组最大值时能重新从0开始继续向后移动直到rear等于front时才达到队满状态,当进队时时应该为
rear = (rear + 1) % MAX_SIZE;
出队时应该为front = (front + 1) % MAX_SIZE;
-
队列的队空和队满的判断
对空:
front == rear
队满:(rear + 1) % MAX_SIZE == front
-
链式队列
以链表为基础实现的队列
- 代码实现
class LinkQueue<T> implements Queue<T> { private class Node{ //节点类 private Node next; private T dataElement; public Node() { //构造头节点 // TODO Auto-generated constructor stub this.next = null; //节点中的next(连接下一个节点) this.dataElement = null; } public Node(T dataElement) { //构造尾节点 // TODO Auto-generated constructor stub this.next = null; this.dataElement = dataElement; } } private Node front;//队头结点 private Node rear; //队尾结点 private int length; public LinkQueue() { //初始化队列 // TODO Auto-generated constructor stub front = new Node(); rear = front; length = 0; } @Override public void destroy() {//重置结点 // TODO Auto-generated method stub rear = front; length = 0; } @Override public boolean isEmpty() { // TODO Auto-generated method stub if(rear == front) return true; else return false; } @Override public int queueLength() { // TODO Auto-generated method stub return length; } @Override public T getHead() { // TODO Auto-generated method stub return front.next.dataElement; } @Override public void enQueue(T element) {//进队 // TODO Auto-generated method stub Node newNode = new Node(element); rear.next = newNode; rear = newNode; } @Override public T deQueue() {//出队 // TODO Auto-generated method stub //出队操作相当于删除头节点的后驱结点 T temp = front.next.dataElement; front.next = front.next.next; return temp; } @Override public void queueTraverse() { //遍历 // TODO Auto-generated method stub Node curentNode = front; while(curentNode != rear) { System.out.print( curentNode.next.dataElement + " "); curentNode = curentNode.next; } System.out.println(); } }
- 代码解析
-
队列的入队和出队
链队的入队和常规的后插法链表的添加一样,每次出队是将头节点的后继结点删除(先进先出)
-
总结
- 栈后进先出,队列先进先出
- 对于顺序栈base对应的是第一个元素top-1对应最后一个元素,对于链栈base.next对应第一个元素top对应最后一个元素,队列同理