栈的定义
栈的英文名称为Stack。人们把栈的顶端称为栈顶,栈顶的第一个元素称为栈顶元素。又称为栈帧。相对的栈的底部被称为栈底。向一个栈插入新元素称为压栈/入栈,英文叫做Push,它是把该元素放到栈顶元素的上面,使之称为新的栈顶元素。从一个栈删除元素称为弹栈,英文叫做Pop,它是把栈顶元素删除掉,使其下面的相邻元素成为新的栈底元素。
由于栈的插入和删除运算仅在栈顶一端进行,后进栈元素必定先出栈,所以我们又把栈称为后进先出表LIFO(Last In First Out)。栈的特点就是先进后出、后进先出。
一、用数组实现栈
①存储结构
public class ArrayStack<T> {
private Object[] datas; //表示存储对象的数组
private int top; //定义栈帧,永远指向顶部元素
}
②栈的初始化
public ArrayStack() {
datas = new Object[4]; //随便给一个16长度
//规定空栈的时候指向-1
//这样在有第一个元素入栈的时候栈顶指针就可以通过自加指向0元素,从而避免其它判断。
top = -1;
}
③判断是否为空
public boolean isEmpty() {
return top == -1;
}
④获取栈的元素个数
public int size(){
return top++;
}
⑤压栈
public void push(T value) {
if(top == datas.length - 1){
//创建一个两倍大的数组长度
Object newArr[] = new Object[(top + 1) * 2];
//将原数组元素拷贝到新数组
for(int i = 0;i < top + 1;i++){
newArr[i] = datas[i];
}
top++;
newArr[top] = value;
datas = newArr;
}else{
top++;
datas[top] = value;
}
}
⑥弹栈
public T pop() {
//如果栈顶元素位置不为0就可以弹出元素
if(top > -1){
//将当前数组下标元素提出来
T a = (T)datas[top];
//再将该下标元素置为null
datas[top] = null;
//然后栈顶元素位置-1
top = top - 1;
return a;
//如果栈顶元素位置为起始值即栈空,返回null
}else{
return null;
}
}
⑦获取栈顶元素
public T top() {
if(top > -1){
return (T)datas[top];
}else{
return null;
}
}
二、用链表实现栈
①存储结构
public class LinkedStack<T> implements Iterable<T>{
private Node head;//记录首结点(在栈的顶部)
private int N;//栈中元素个数
//结点内部类
private class Node{
T item;//存储数据
Node next;//指向下一个结点
public Node(T item, Node next){
this.item = item;
this.next = next;
}
}
@Override
public Iterator<T> iterator() {
return new SIterator();
}
private class SIterator implements Iterator{
private Node n;
public SIterator(){
this.n = head;
}
@Override
public boolean hasNext() {
return n.next != null;
}
@Override
public Object next() {
n = n.next;
return n.item;
}
}
}
②栈的初始化
public LinkedStack(){
//头结点的指针域与数据域皆为null
this.head = new Node(null,null);
this.N = 0;
}
③判断是否为空
public boolean isEmpty(){
return N == 0;
}
④获取栈的元素个数
public int size(){
return N;
}
⑤压栈
public void push(T t){
//找到首结点指向的第一个结点
Node oldNode = head.next;
//创建新结点
Node newNode = new Node(t,null);
//让首结点指向新结点
head.next = newNode;
//让新结点指向原来的第一个结点
newNode.next = oldNode;
N++;
}
⑥弹栈
public T pop(){
//找到首结点指向的第一个结点
Node oldNode = head.next;
if(oldNode == null) return null;
//让首结点指向原来第一个结点的下一个结点
head.next = oldNode.next;
N--;
return oldNode.item;
}