参考:《数据结构--java语言描述》
栈是仅限在表尾(也就是栈顶)进行插入和删除操作的线性表。
允许插入和删除操作的一端称为栈顶(top),另一端称之为栈底(button)
不含任何元素的栈称之为空栈。
遵循后进先出(LIFO, last in first out)的原则
入栈和出栈是栈的两个主要操作,如下图,实现栈的时候,需要一个栈顶指针top来表示栈顶的当前位置
栈的基本操作:
- 初始化 --构造一个空栈
- 入栈 -- 在栈顶的位置插入一个新的元素
- 出栈 -- 删除栈顶元素
- 获取 -- 获取栈顶元素
- 判空 -- 判断当前栈是否为空
- 求长度 -- 求出栈中数据元素的个数
- 正序遍历 -- 依次访问栈中每一个元素并输出
- 销毁 -- 销毁一个已存在的栈
栈接口定义代码如下:
public interface SequenceStack<T> {
//入栈
public void push(T obj);
//出栈
public T pop();
//获取栈顶信息
public T getHead();
//判空
public boolean isEmpty();
//求长度
public int size();
//正序遍历
public void nextOrder();
//销毁
public void clear();
}
顺序表实现
顺序栈:利用一组地址连续的存储单元依次存放自栈底至栈顶的数据元素,把数组中下标为0的一端作为栈底。为了指示栈中元素的位置,定义变量top来指示栈顶元素在顺序表中的位置
上图是栈顶指针top指向栈顶元素时对应的入栈和出栈的关系
深入理解顺序栈的top指针(实现顺序栈的关键)
top的初始值为-1,指向栈底,表明该栈为一个空栈。入栈操作,top指针的值加1,入栈元素放到top指针指向的位置。出栈操作,先删除栈顶元素,top指针的值减去1
1、初始化
top初始化值为-1,指向栈底,当top==-1时,表明该栈为一个空栈。
public class ArraySequenceStack<T> implements SequenceStack<T> {
public final int maxSize=10; //无参构造时,数组的默认长度
private int top; //top指针
private T[] arrayStack; //使用数组声明栈
public ArraySequenceStack() {
top=-1;
arrayStack=(T[])new Object[maxSize];
}
public ArraySequenceStack(int n) {
if(n<=0){
System.out.println("数组的长度大于0,否则退出程序");
System.exit(1);
}
this.top = -1;
arrayStack=(T[])new Object[n];
}
2、入栈
入栈算法:
- 如果栈满,需对数组进行扩容,长度原来的两倍。
- 定义一个长度为原数组长度两倍的数组
- 把原数组中的值复制到新定义的数组当中
- 把指向原数组的指针指向新的数组
- top值加1
- 把入栈元素插入top指针指向的位置
public void push(T obj) {
if(top+1==arrayStack.length){
T[] p=(T[])new Object[(top+1)*2];
for(int i=0;i<arrayStack.length;i++){
p[i]=arrayStack[i];
}
arrayStack=p;
}
top++;
arrayStack[top]=obj;
}
3、出栈
出栈算法
- 如果为空栈,则无法进行出栈操作
- 备份栈顶元素
- 删除栈顶元素,top减去1,同时返回备份的栈顶元素
public T pop() {
if(isEmpty()){
System.out.println("空栈,出栈操作失败");
return null;
}
T pop=arrayStack[top]; //备份栈顶元素
arrayStack[top]=null; //移除栈顶数据元素,方便已移除数据进行垃圾回收
top--;
return pop;
}
4、获取栈顶元素
栈空,获取失败,返回null。不为空,返回栈顶元素
public T getHead() {
if(isEmpty()){
System.out.println("空栈,获取栈顶元素失败");
return null;
}
return arrayStack[top];
}
5、判空
当top==-1时。为空栈
public boolean isEmpty() {
return top==-1;
}
6、获取数组长度
数组长度为top+1。不要以为长度为top+2。当元素入栈时,top会加1,指向栈顶元素
public int size() {
return top+1;
}
7、正序遍历
依次输出数组中的值,队尾元素对应栈顶元素
public void nextOrder() {
for(int i=0;i<=top;i++){
System.out.print(arrayStack[i]+" ");
}
System.out.println();
}
8、销毁
top设置为-1,同时数组设置为null
public void clear() {
top=-1;
arrayStack=null;
}
链表实现
链栈:栈的连接存储结构。对于链式栈,无满栈问题,空间可扩充,插入与删除操作仅在栈顶执行,链式栈的栈顶在链头。
链栈的链表示意图
由于栈只能对栈顶元素(p)进行操作。所以入栈操作为:p.next=top;top=p; 出栈操作为:p=top;top=top.next;
栈的链表实现类泛型定义如下:
public class LinkedSequenceStack<T> implements SequenceStack<T> {
public Node<T> top;
public int length;
public LinkedSequenceStack() {
this.top = null;
this.length = 0;
}
class Node<T>{
T obj;
Node<T> next;
public Node(T obj, Node<T> next) {
this.obj = obj;
this.next = next;
}
public Node(T obj){
this.obj=obj;
this.next=null;
}
}
@Override
public void push(T obj) { //入栈
top=new Node<T>(obj,top);
length++;
}
@Override
public T pop() { //出栈
if(length==0){
System.out.println("空栈,出栈操作失败");
return null;
}
T obj=top.obj;
top=top.next;
length--;
return obj;
}
@Override
public T getHead() { //获取头节点
if(length==0){
System.out.println("空栈,获取栈顶元素操作失败");
return null;
}
return top.obj;
}
@Override
public boolean isEmpty() { //判空
return length==0;
}
@Override
public int size() { //求长度
return length;
}
@Override
public void nextOrder() { //正序遍历
Node<T> temp=top;
for(int i=0;i<length;i++){
System.out.print(temp.obj+" ");
temp=temp.next;
}
System.out.println();
}
@Override
public void clear() { //销毁
length=0;
top=null;
}
public static void main(String[] args) {
//数组反转
String str="abcdefg";
char[] strChar=str.toCharArray();
LinkedSequenceStack stack=new LinkedSequenceStack();
for(int i=0;i<strChar.length;i++){ //依次字符串的字符压入栈中
stack.push(strChar[i]);
}
for(int i=0;i<strChar.length;i++){ //栈中的元素依次出栈
strChar[i]=(char)stack.pop();
}
String str1=new String(strChar);
System.out.println(str1);
}
}