在之前的线性表的存储结构中,会有顺序存储结构和链式存储结构,对于栈来说,也是一样的。
- 对于栈,是限定仅在表尾进行插入和删除操作的线性表。把允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom)。栈又称为后进先出(Last In First Out)的线性表,简称LIFO结构。
- 对于队列,是只允许在一端进行插入操作,在另一端进行删除操作的线性表。
栈的顺序存储结构
我们先来看看我们所写栈的Stack接口。
package DS01.动态数组;
/**
* @author 七夏
* 线性表的一种特殊情况
* ArrayStack
*/
public interface Stack<E> extends Iterable<E>{
//获取栈中元素的个数
int getsize();
//判空
boolean isEmpty();
//元素e进栈
void push(E e);
//弹栈一个元素e
E pop();
//查看当前栈顶元素
E peek();
//清空当前栈
void clear();
}
在栈的顺序存储结构中,我们可以使用之前已经编写好的ArrayList的顺序存储的线性表来表示栈的顺序存储结构,即ArrayList是该栈的底层实现。
package DS01.动态数组;
import java.util.Iterator;
/**
* @author 七夏
* @param <E>
* @version 1.0
* 顺序栈内部是由顺序表实现的
*/
public class ArrayStack<E> implements Stack<E>{
private ArrayList<E> list;
public ArrayStack(){
list = new ArrayList<>();
}
//指定大小的栈
public ArrayStack(int capacity){
list = new ArrayList<>(capacity);
}
}
我们只需要利用ArrayList类中编写好的方法就可以了,其中主要有:入栈(ArrayList中的addLast)和弹栈(ArrayList中的removeLast)。
- 入栈
入栈,在栈的一端进行“插入”即,先进后出(因为每次的入栈是在栈的顶入“插入”)。
ArrayList类中的函数:
@Override
public void addLast(E e) {
add(size,e);
}
MyStack类中的函数:
@Override
public void push(E e) {
list.addLast(e);
}
- 弹栈
这样,对于弹栈也是一样的,只不过在顺序线性表的头部进行删除就可以了。
ArrayList类中的函数:
@Override
public E removeLast() {
return remove(size-1);
}
ArrayStack类中的函数:
@Override
public E pop() {
return list.removeLast();
}
接下来,就是我们顺序栈中的其他方法了。
这里面的迭代器我们直接调用ArrayList中已经写好的方法即可。
@Override
public int getsize() {
return list.getSize();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public E peek() {
return list.getLast();
}
@Override
public void clear() {
list.clear();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("ArrayStack: %d/%d \n",getsize(),list.getCapacity()));
sb.append('[');
if(isEmpty()){
sb.append(']');
}else{
for (int i = 0; i < getsize(); i++) {
sb.append(list.get(i));
if(i == getsize()-1){
sb.append(']');
}else{
sb.append(',');
}
}
}
return sb.toString();
}
栈的链式存储结构
栈的链式存储结构,简称链栈。
我们和上面的顺序存储结构一样,底层也是利用LinkedList类来实现的。所以就不过多介绍,主要来看下面的代码。
对于链栈的存储结构代码如下:
package DS02.动态链表;
import DS01.动态数组.Stack;
import java.util.Iterator;
/**
* @author 七夏
* @param <E>
* 链栈
*/
public class LinkedStack<E> implements Stack<E> {
private LinkedList<E> list;
public LinkedStack(){
list = new LinkedList();
}
}
我们将链栈的存储代码编写完成后,就要考虑对链栈的操作了。
最主要的还是链栈中的入栈和弹栈。
入栈:
@Override
public void push(E e) {
list.addFirst(e);
}
弹栈:
@Override
public E pop() {
return list.removeFirst();
}
链栈的其他方法如下:
@Override
public E peek() {
return list.getFirst();
}
@Override
public void clear() {
list.clear();
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}