54.【数据结构--- 栈与队列】

(一)、栈

1.栈的定义(Stack):

在这里插入图片描述

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。(先进后出)

2.栈链式储存结构的进栈出栈

链式栈的基本思路:是把添加的元素直接放在链表的第一个节点。出栈的时候也是直接把第一个节点进行出栈
在这里插入图片描述

设置链表:

  public class Node {
        Node next;
        T item;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }

压栈:(压栈压的是头节点的下一个结点)

  public void push(T t) {
        Node Insert = new Node(t, null);
        if (this.size == 0) {
            this.head.next = Insert;
        } else {
            //获取原先的第一个结点
            Node before = this.head.next;
            //开始进行链接
            this.head.next = Insert;
            Insert.next = before;
        }
        this.size++;
    }

出栈:(不用this.size-- 操作)

    public T pop() {   //出栈的话不用--
        //获取第一个结点
        Node first = this.head.next;
        if (this.size == 1) {
            return first.item;
        } else {
            //获取第二个结点
            Node second = first.next;
            //开始断链
            this.head.next = second;
            //进行数量控制:
            return first.item;
        }
    }

类方法:

public class LinkeStack<T> {
    public class Node {
        Node next;
        T item;

        public Node(T item, Node next) {
            this.item = item;
            this.next = next;
        }
    }
    Node head;
    int size;

    public LinkeStack() {
        this.size = 0;
        this.head = new Node(null, null);
    }
    //获取个数
    public int getSize() {
        return this.size;
    }
    //进行压栈操作(实际上就是直接压入头节点的下一个结点)
    public void push(T t) {
        Node Insert = new Node(t, null);
        if (this.size == 0) {
            this.head.next = Insert;
        } else {
            //获取原先的第一个结点
            Node before = this.head.next;
            //开始进行链接
            this.head.next = Insert;
            Insert.next = before;
        }
        this.size++;
    }
    //进行出栈的操作:
    public T pop() {   //出栈的话不用--
        //获取第一个结点
        Node first = this.head.next;
        if (this.size == 1) {
            return first.item;
        } else {
            //获取第二个结点
            Node second = first.next;
            //开始断链
            this.head.next = second;
            //进行数量控制:
            return first.item;
        }
    }
}

在这里插入图片描述

3.栈顺序储存结构的出栈和进栈

类方法:(继承了顺序表的函数)

import java.util.ArrayList;

public class SquenceStack<T> extends SquenceLisr {
    public SquenceStack(int capacity){
        super(capacity);
    }
    //进行入栈
    public void push(T t){
        Insert(t);
    }
    //进行出栈
    public T pop(){
      return (T)remove(getLength()-1);
    }
}

主方法:

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello  {
    public static void main(String []avgs) {
    SquenceStack<String> stack=new SquenceStack<>(10);
    stack.push("aa");
    stack.push("bb");
    stack.push("cc");
    stack.push("dd");
    for(int i=0;i<4;i++){
        System.out.println(stack.pop());
    }
    }
}

在这里插入图片描述

4.栈的实践操作(计算器)

4.1基础操作(两数相加)

在这里插入图片描述
在这里插入图片描述

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
        //设置表达式
      String express="7)8";
      //进行分步取解
        //获取数字1;
        char numStr1=express.charAt(0);
        //获取第二个数字:
        char numStr2=express.charAt(2);
        //获取中间的字符
        char operation=express.charAt(1);
        //进行字符串的转换
        int num1=Integer.parseInt(numStr1+"");  //只能转换字符串,所以这样做
        int num2=Integer.parseInt(numStr2+"");
        try {
           int reuult= Caluat(num1,num2,operation);
            System.out.println(reuult);
        } catch (Exception e) {
            System.out.println("输入的符号有错");
        }
    }
    public static int Caluat(int num1,int num2,char operation){
        switch(operation){
            case '+':
                return num1+num2;
            case '-':
                return num1-num2;
            case '*':
                return num1*num2;
            case '/':
                return num1/num2;
            default:
                return -0;
        }
    }
}
4.2进阶操作(10以内的,多数相加)

基本思路:创建两个栈、一个是数字栈、另一个是字符栈。然后通过对字符串的遍历得到对应的字符,然后通过判断字符,如果是逻辑表达式,那么就进入字符栈,如果是数字字符,那么就进入数字栈。然后再进行对最后进入的三个字符进行依次出栈,得到结果后,再进行入栈操作。直到最后字符栈为空就最后一次数字出栈。
在这里插入图片描述
在这里插入图片描述

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
        String express="1+2+3+5";
        //设置数字栈
      Stack<Integer> nums=new Stack<>();
      //设置字符栈
       Stack<Character> operation=new Stack();
       //进行压栈操作:
       for(int i=0;i<express.length();i++) {
           char ch=express.charAt(i);
           if (Judge(ch)){  //压入符号栈
               operation.push(ch);
           }else{  //压入数字栈
               nums.push(Integer.parseInt(ch+""));
           }
       }
       //进行出栈的操作

        while (!operation.empty()) {
            int num1=nums.pop();  //出栈数字1
            int num2=nums.pop();  //出栈数字2
            char operation1=operation.pop();  //出栈字符
            nums.push(Caluat(num1,num2, operation1));  //得出结果再入栈
        }
        System.out.println(nums.pop());
    }
    public static boolean Judge(char ch){
        return ch=='+'||ch=='-'||ch=='*'||ch=='/';
    }
    public static int Caluat(int num1,int num2,char operation){
        switch(operation){
            case '+':
                return num1+num2;
            case '-':
                return num1-num2;
            case '*':
                return num1*num2;
            case '/':
                return num1/num2;
            default:
                return -0;
        }
    }
}
4.3进阶操作(10以内的±/*)

在这里插入图片描述
基本思路:
首先在2的基础上添加一个操作,在操作运算符的时候。进行判断加入话:优先级高的话,那么就直接在添加运算的时候就进行出栈和入栈的操作。然后继续正常操作。

peek(),进行查看前一个栈顶元素.

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
        String express="2*2/3*5+6";
        //设置数字栈
      Stack<Integer> nums=new Stack<>();
      //设置字符栈
       Stack<Character> operation=new Stack();
       //进行压栈操作:
       for(int i=0;i<express.length();i++) {
           char ch=express.charAt(i);
           if (Judge(ch)){  //压入符号栈
               if(operation.empty()){
               operation.push(ch);}else{
                   char c=operation.peek();   //获取已经插入栈顶的符号,但是不是出栈
                   if(Grade(ch)<=Grade(c)) {  //假如说栈顶的优先级低于栈底
                       char operation4=operation.pop(); //那么取出栈顶元素(并不是待插入的栈顶元素)
                       int num3 = nums.pop();
                       int num4 = nums.pop();
                       //得出结果
                       int result = Caluat(num4, num3, operation4);
                       //把结果进行压栈操作
                       nums.push(result);
                   }operation.push(ch);
               }

           }else{  //压入数字栈
               nums.push(Integer.parseInt(ch+""));
           }
       }
       //进行出栈的操作
        while (!operation.empty()) {
            int num1=nums.pop();  //出栈数字1
            int num2=nums.pop();  //出栈数字2
            char operation1=operation.pop();  //出栈字符
            nums.push(Caluat(num2,num1, operation1));  //得出结果再入栈
        }
        System.out.println(nums.pop());
    }
    public static boolean Judge(char ch){
        return ch=='+'||ch=='-'||ch=='*'||ch=='/';
    }
    public static int Caluat(int num1,int num2,char operation){
        switch(operation){
            case '+':
                return num1+num2;
            case '-':
                return num1-num2;
            case '*':
                return num1*num2;
            case '/':
                return num1/num2;
            default:
                return -0;
        }
    }
    public static int Grade(char ch){
        if(ch=='+'||ch=='-')return 1;
        else if (ch=='*'||ch=='/')return 2;
       else return 0;
    }
}

在这里插入图片描述

(二)、队列

1.队列的定义:

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。(前端(队尾)删除 后端(队头)插入).------(先进先出)
在这里插入图片描述

2.顺序队列

在这里插入图片描述
基本思路:头标和尾标初始位置都为0,每次插入一个元素的时候尾标就会后移一格,删除一个元素的时候就会后移一格。
类文件:

public class Front <T>{
    //定义队列数组
    T [] elem;
    //定义头部游标
    int head;
    //定义尾部游标:
    int tail;
    //定义队列的长度:
    int size;
    //定义队列的容量:
    int capctity;
    //进行初始化:
    public Front(int capctity){
        this.elem=(T[])new Object[capctity];
        this.size=0;
        //初始化游标的位置
        this.head=0;
        this.tail=0;
    }
    //进行入队列的操作
    public  boolean offer(T item){
            //直接把添加的元素放在队尾的位置
            elem[this.tail]=item;
             this.tail++;   //当插入的之后尾下标需要后移
            this.size++;
            if(this.tail==capctity){return false;}
            return true;
    }
    //进行出队的操作:
    public T leave(){
        if(this.size==0){return null;}
        T item=elem[this.head];
        this.size--;
        this.head++;    //当删除的时候头部下标会后裔
        return item;
    } public int size(){
        return this.size;
    }
}

测试类:

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
     Front<String> s=new Front<>(10);
     s.offer("aa");
     s.offer("bb");
     s.offer("cc");
        while (s.size()>0) {  //因为这里是出队,出队之后个数会减少。并不是顺序表中的遍历
            System.out.println(s.leave());
        }
    }
}

3.线性队列:

基本思路:头指针和尾指针,初始化是在第一个结点,并不是头节点。插入元素的时候,插入的位置是尾标的下一位。插入之后需要把尾标移动到新插入的元素下面。在出队的时候,
在这里插入图片描述

JavaBean类:

public class Front <T>{
   class Node{
       Node next;
       T item;
       public Node(T item,Node next){
           this.item=item;
           this.next=next;
       }
   }
    Node head;
   int size;
   Node tail;
   public Front(){
       this.size=0;
   }
   public boolean offer(T t){
       Node node=new Node(t,null);
       if(size==0){ //假如说是第一个
           this.tail=node;  //在这初始化
           this.head=node;
       }else {
           this.tail.next = node;  //尾标的后一个添加
           this.tail=node;   //然后把尾标指向添加的这个位置
       }
       this.size++;
       return true;
   }
   public T leave(){
       if(this.head==null){   //假如说没有了
           throw new RuntimeException("没有元素了");
       }
    Node node=this.head;
    //移动头坐标到下一位
    this.head=this.head.next;
    if(node.next==null){ //假如说node 后面没有了
        this.tail=null;
    }
    this.size--;
    return node.item;
   }
}

测试类:

import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
    Front<String> s=new Front<>();
    s.offer("aa");
    s.offer("bb");
    s.offer("cc");
    while (s.size>0){
        System.out.println(s.leave());
    }
    }
}

在这里插入图片描述

4.循环队列:

基本思路:当添加的受taill后移,取出的时候head后移。然后0和1的位置被控出来了。然后通过借助0和1的位置进行添加元素。
在这里插入图片描述

JavaBean类

public class Dui <T>{
    T []elem;
    int size;
    int head;
    int tail;
    int capitcy;
    public Dui(int capitcy){
        elem=(T[])new Object[capitcy];  //千万不能写this.
        this.head=0;
        this.size=0;
        this.tail=0;
        this.capitcy=capitcy;
    }
    public boolean add(T t){
        if(this.size==this.capitcy){
            throw new RuntimeException("循环队列已满");
        }
        //添加元素
        elem[this.tail]=t;
        this.tail++;
        //取模求循环后的个数,当取出来的时候就空出来了
        this.tail=this.tail%this.capitcy;
        this.size++;
        return true;
    }
    //进行出队
    public T remove(){
        if(this.size==0){
            throw new RuntimeException("队列中已经没有元素了");
        }
        T s=elem[this.head];
        this.head++;
        this.head=this.head%this.capitcy;
        this.size--;
        return s;
    }
}

主类:

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.sql.SQLOutput;
import java.util.*;
import java.awt.*;
import java.lang.Math;
public class hello {
    public static void main(String[] avgs) {
    Dui<String> s=new Dui<>(3);
    s.add("aa");
    s.add("bb");
    s.add("cc");
    while(s.size>0){
        System.out.println(s.remove());
    }
    s.add("dd");
        System.out.println(s.remove());
    }
}

在这里插入图片描述

  • 74
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 53
    评论
评论 53
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉士先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值