栈介绍
概念
栈是一种只允许在一端进行插入或删除的线性表。
- 栈的操作端通常被称为栈顶,另一端被称为栈底。
- 栈的插入操作称为进栈(压栈|push);栈删除操作称为出栈(弹栈|pop)。
特点
栈就像一个杯子,我们只能从杯口放和取,所以栈中的元素是“先进后出”的特点。
存储结构
顺序存储的栈称为顺序栈;链式存储的栈称为链式栈。
我们可以围绕栈的4个元素来实现栈:
-
2状态:是否栈空;是否栈满。
-
2操作:压栈push;进栈pop。
顺序栈
具体实现
package 一.数组实现顺序栈;
/**
*
* @author JHL
*顺序栈(SqStack)一般用数组来实现,主要有四个元素:2状态2操作。
* 2状态:栈空?;栈满?
* 2操作:压栈push;弹栈pop。
* @param <T>
*/
public class SqStack<T>{
T data[];//用数组表示栈元素
int maxSize;//栈空间大小(常量)
int top;//栈顶指针(指向栈顶元素)
public SqStack(int maxSize) {
this.maxSize=maxSize;
//泛型数组不能直接new创建,需要使用Object来创建(其实一开始也可以直接使用Object来代替泛型)
this.data=(T[]) new Object[maxSize];
//有的书中使用0,但这样会占用一个内存
this.top=-1;
}
//判断栈是否为空
public boolean isNull() {
boolean flag=this.top<=-1?true:false;
return flag;
}
//判断是否栈满
public boolean isFull(){
boolean flag = this.top==this.maxSize-1?true:false;
return flag;
}
//压栈
public boolean push(T vaule){
if(isFull()){
//栈满
return false;
}else{
data[++top] = vaule;//栈顶指针加1并赋值
return true;
}
}
//弹栈
public T pop(){
if(isNull()){
//栈为空
return null;
}else{
T value = data[top];//取出栈顶元素
--top;//栈顶指针-1
return value;
}
}
//测试
public static void main(String[] args) {
//初始化栈(char类型)
SqStack<Character> stack = new SqStack<Character>(10);
//2状态
System.out.println("栈是否为空:"+stack.isNull());
System.out.println("栈是否已满:"+stack.isFull());
//2操作
//依次压栈
stack.push('a');
stack.push('b');
stack.push('c');
//依次弹栈
System.out.println("弹栈顺序:");
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
}
}
链栈
具体实现
package 二.链实现栈;
/**
* @author JHL
@Description TODO:
*链栈(LinkStack)用链表来实现,主要有四个元素:2状态2操作。
* 2状态:栈空?;栈满(逻辑上永远都不会栈满,除非你的电脑没内存了^_^)。
* 2操作:压栈push;弹栈pop。
* @param <T>
*/
class LinkStack<T>{
//栈顶节点
private LinkNode<T> top;
//初始化1
public LinkStack(){
this.top = new LinkNode<T>();
}
//初始化栈
public void initStack(){
this.top.setData(null);
this.top.setNext(null);
}
//是否栈空
public boolean isNull(){
boolean flag = top.getNext()==null?true:false;
return flag;
}
//压栈
public void push(LinkNode<T> node){
if(isNull()){
//栈空,即第一次插入
top.setNext(node);
node.setNext(null);//该句可以省略(首次插入的元素为栈底元素)
}else{
node.setNext(top.getNext());
top.setNext(node);
}
}
//弹栈
public LinkNode<T> pop(){
if(isNull()){
//栈空无法弹栈
return null;
}else{
LinkNode<T> delNode = top.getNext();//取出删除节点
top.setNext(top.getNext().getNext());//删除节点
return delNode;
}
}
//测试
public static void main(String[] args) {
LinkStack<Character> ls = new LinkStack<Character>();
//1状态
System.out.println("栈是否为空:"+ls.isNull());
//2操作
//依次压栈
ls.push(new LinkNode<Character>('a'));
ls.push(new LinkNode<Character>('b'));
ls.push(new LinkNode<Character>('c'));
//依次弹栈
System.out.println("弹栈顺序:");
System.out.println(ls.pop().getData());
System.out.println(ls.pop().getData());
System.out.println(ls.pop().getData());
}
}
//链式栈节点(外部类实现,也可以使用内部类)
class LinkNode<T>{
private T data;//数据域
private LinkNode<T> next;//指针域
//初始化1
public LinkNode(){
this.data = null;
this.next = null;
}
//初始化2
public LinkNode(T data) {
super();
this.data = data;
this.next = null;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public LinkNode<T> getNext() {
return next;
}
public void setNext(LinkNode<T> next) {
this.next = next;
}
}
栈的应用
栈结构是很基本的一种数据结构,所以栈的应用也很常见,根据栈结构“先进后出”的特点,我们可以在很多场景中使用栈,下面我们就是使用上面我们已经实现的栈进行一些常见的应用:十进制转N进制、行编辑器、校验括号是否匹配、中缀表达式转后缀表达式、表达式求值等。