栈
一.基本介绍
(1)定义:栈是限定仅在表头进行插入和删除操作的线性
(2)特点:LIFO(Last In First Out->后进先出)
二.分类
(一)顺序栈
I.基本介绍
说明:top和base在初始时均指向栈底,base指针一直指向栈底,如果有元素进栈,top就向上移动,如果有元素出栈,top指针下移。
优点:查询速度快
缺点:存储空间需要事先分配,可能会出现溢出问题
存储结构
#define MAXSIZE 100
typedef struct{
SElemType *base; //栈底指针
SElemType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
II.基本操作
初始化
具体代码:
Status InitStack(SqStack &S){
S.base =new SElemType[MAXSIZE];
//为顺序栈动态分配一个容量为MAXSIZE的数组空间
if(!S.base)exit(OVERFLOW); //存储分配失败
S.top=S.base; //top初始化为base(空栈)
S.stacksize=MAXSIZE; //stacksize置为栈的最大容量MAXSIZE
return OK;
}
入栈
具体代码:
Status Push(SqStack &S,SElemType e){
//插入元素e为新的元素
if(S.top-S.base=S.stacksize) return ERROR;//栈满
*S.top++=e; //元素e压入栈顶,栈顶指针加1
return OK;
}
出栈
具体代码
Status Pop(SqStack &S,SElemType &e){
if(S.top==S.base)return ERROR;//栈空
e=*--S.top; //栈指针减1,将栈顶指针赋值给e
return OK;
}
取栈顶
SElemType GetTop(SqStack &S){
//返回S的栈顶元素,不修改栈顶指针
if(S.top!=S.base) //栈非空
return *(S.top-1);//返回栈顶元素的值,栈顶指针不变
}
(二) . 链栈
I.基本介绍
说明:结点结构和线性表的单链表的结点结构是一样的,由于栈是一种后进先出的结构,所以在存储时,新的结点的指针域指向的是上一个结点。
存储结构:
typedef struct StackNode{
ElemType data; //数据域
struct StackNode *next; //指针域
}StackNode,*Linktack;
II.基本操作
初始化
Status InitStack(){
//构造一个空栈
S=NULL;
return OK;
}
入栈
具体代码:
Status Push(LinkStack &S,SelemType){
//在栈顶插入元素e
p=new StackNode; //生成新结点
p->data=e; //初始化数据域
p->next =S; //将新结点插入栈顶
S=p; //修改栈顶指针为p
}
出栈
Status Pop(LinkStack &S ,SElemType &e){
//删除S的栈顶元素,用e返回其值
if(S==NULL)return ERROR;
e=S->data;
p=S;//用p临时保存栈顶元素空间,已备释放
S=S->next;//修改栈顶指针
delete p;//释放原栈顶的元素
return OK;
}
取栈顶
SElemType GetTop(LinkStack S){
if(S!=NULL) //栈非空
return S->data; //返回栈顶元素的值,栈顶指针不变
}
总结:
栈的引入简化了程序设计的问题,划分了不同关注层次,式的思考范围缩小,更加聚焦于要解决问题的核心。反之,像数组等,因为要分散精力去考虑数组的下标增减等细节问题,反而掩盖了问题的本质。
三.栈的应用
(一)递归
把一个直接调用自己或通过一系列的调用语句间接调用自己的函数,称为递归函数。
经典实例:(1)斐波那契数列
(2)汉诺塔问题
(3)N皇后问题
(4)全排列
详细内容参考:https://blog.51cto.com/u_15314328/4928741
顺序栈实现代码如下:
package stack;
import java.util.Scanner;
/**
* @author Jin
* @ Date 2022年06月2022/6/30日19:26
*/
public class ArrayStack {
public static void main(String[] args) {
Stack stack=new Stack(4);
String key="";
boolean loop=true;
//控制是否退出菜单
Scanner scanner=new Scanner(System.in);
while(loop){
System.out.println("show:表示显示栈");
System.out.println("exit:退出程序");
System.out.println("push:表示添加数据到栈(入栈)");
System.out.println("pop:表示从栈中取出数据(出栈)");
System.out.println("请输入你的选择:");
key=scanner.next();
switch(key){
case"show":
stack.showStack();
break;
case"push":
System.out.println("请输入一个数:");
int value =scanner.nextInt();
stack.push(value);
break;
case"pop":
try{
int res =stack.pop();
System.out.printf("出栈的数据是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
//打印出异常信息
}
break;
case"exit":
scanner.close();
loop=false;
//退出循环
break;
default:break;
}
}
}
}
class Stack{
private int maxSize;
private int[]stack;
private int top=-1;
/**构造器*/
public Stack(int maxSize){
this.maxSize=maxSize;
stack=new int[maxSize];
}
/**(1)判断栈是否满*/
public boolean isFull(){
return top==maxSize-1;
}
/**(2)判断栈空*/
public boolean isEmpty(){
return top==-1;
}
/**(3)入栈(将数据压入栈顶)*/
public void push(int value){
if(isFull()){
System.out.println("栈已经满,无法进行添加新元素!!");
}else{
top++;
stack[top]=value;
}
}
/**(4)出栈(将栈顶的元素取出)*/
public int pop(){
if(isEmpty()){
throw new RuntimeException("栈空,没有数据!");
}else{
int middle =stack[top];
top--;
return middle;
}
}
/**(5)遍历栈中元素(从栈顶到栈底开始遍历)*/
public void showStack(){
if(isEmpty()){
System.out.println("栈空,没有数据~~");
return;
}
for (int i = top; i >=0 ; i--) {
System.out.printf("stack[%d]=%d\n",i,stack[i]);
}
}
}
链栈的代码实现如下:
package stack;
import java.sql.SQLOutput;
import java.util.Scanner;
/**
* @author Jin
* @ Date 2022年06月2022/6/30日20:13
* 目标:完成链式存储结构的添加、删除、取栈顶、遍历、退出程序等基本功能
*/
public class LinkedStack {
public static void main(String[] args) {
LinkStack stack1=new LinkStack();
String key="";
boolean loop=true;
//控制是否退出菜单
Scanner scanner=new Scanner(System.in);
while(loop){
System.out.println("show:表示显示栈");
System.out.println("exit:退出程序");
System.out.println("push:表示添加数据到栈(入栈)");
System.out.println("pop:表示从栈中取出数据(出栈)");
System.out.println("head:表示获取栈顶元素的值");
System.out.println("请输入你的选择:");
key=scanner.next();
switch(key){
case"show":
stack1.showStack();
break;
case"push":
System.out.println("请输入一个数:");
int value =scanner.nextInt();
stack1.addNode(value);
break;
case"pop":
try{
int res =stack1.popNode();
System.out.printf("出栈的数据是%d\n",res);
} catch (Exception e) {
System.out.println(e.getMessage());
//打印出异常信息
}
break;
case"exit":
scanner.close();
loop=false;
//退出循环
break;
case"head":
int t=stack1.getHead();
System.out.printf("栈顶元素的值为%d\n",t);
break;
default:break;
}
}
}
}
class LinkStack{
private Stack1 head=new Stack1(0);
public Stack1 S=head;
public LinkStack(){
}
/**(1)入栈*/
public void addNode(int key){
Stack1 t1=new Stack1(key);
t1.data=key;
t1.next=S;
S=t1;
}
/**(2)出栈
* @return*/
public int popNode(){
if(S.next==null){
throw new RuntimeException("栈已空,无法删除");
}else{
int key=S.data;
S=S.next;
//栈顶指针下移
return key;
}
}
/**(3)遍历栈*/
public void showStack(){
Stack1 cur=S;
if(cur.next==null){
System.out.println("栈已经空,无法取出元素");
}
while(cur.next!=null){
System.out.printf("栈中的元素为:%d\n",cur.data);
cur=cur.next;
}
}
/**(4)获取栈顶元素*/
public int getHead(){
if(S.next==null){
System.out.println("栈已空,不存在栈顶元素!!");
}else{
return S.data;
}
return 0;
}
}
class Stack1{
public int data;
/**存储数据*/
public Stack1 next;
/**存储下一个节点的地址*/
/**构造器*/
public Stack1(int data){
this.data=data;
this.next=null;
}
@Override
/**重写toString()方法*/
public String toString() {
return "Stack1{" +
"data=" + data +
", next=" + next +
'}';
}
}