栈是仅在表尾进行插入或删除操作的线性表,又称 后进先出 的线性表
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();
}
}
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();
}
}
队列的入队和出队
链队的入队和常规的后插法链表的添加一样,每次出队是将头节点的后继结点删除(先进先出)