栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

栈和队列的进阶

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

栈和队列的进阶

一.栈 1.什么是栈

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

2.栈的示意图

 3.栈在生活中的例子

给枪上膛,或者后吃的东西先吐出来。

4.栈在Java中的定义和使用

栈继承Vector类,底层还是连续的存储空间,和ArrayList底层都是数组。

 

(1)常用方法

 (2)栈的常用操作练习
import java.util.Stack;

public class StackDemo {
    public static void main(String[] args) {
        Stack st = new Stack<>();
        st.push(1);
        st.push(2);
        st.push(3);
        st.push(4);
        System.out.println(st.pop());//4弹出
        System.out.println(st.peek());//查看栈顶元素
        System.out.println(st.size());

    }
}
5.栈的模拟实现 (1)问题分析

首先需要一个数组,然后再需要一个size来判断栈空间是否以满,通过上面分析,可以知道栈理解为对数组进行尾插和尾删的操作。这里还实现了一个动态扩容的方法,每次以原数组2倍的方式进行扩容。

(2)代码实现
import java.util.Arrays;
import java.util.EmptyStackException;

public class MyStack {
    public static void main(String[] args) {
        Stack st = new Stack<>();
        System.out.println(st.isEmpty());
        st.push("111");
        st.push("222");
        st.push("333");
        st.push("444");
        System.out.println(st.getSize());
        System.out.println(st.isEmpty());
        System.out.println(st.peek());
        System.out.println(st.pop());
        System.out.println(st.peek());

        st.pop();
        st.pop();
        st.pop();
        st.pop();
        System.out.println(st.getSize());


    }
}
class Stack{
    E[] array;
   private int size;//统计栈中元素
    public Stack(){
        array= (E[])new Object[2];
    }
    //获取栈中元素的个数
    public int getSize(){
        return size;
    }
    public boolean isEmpty(){
        if(size==0){
            return true;
        }
        return false;
    }
    public E pop(){
    if(size>0){
        size--;
        return array[size];
    }
    throw new EmptyStackException();
    }
    public E push(E ele){
        //确保是否可以添加
        ensureCapacity(size);
        array[size]= ele;
        size++;
        return array[size-1];
    }
    //查看栈顶元素
    public E peek(){
        if(size>0){
            return array[size-1];
        }
        throw new EmptyStackException();//栈为空异常
    }
    //扩容
    private void ensureCapacity(int size){
        if(size==array.length){
            array = Arrays.copyOf(array,size*2);
        }
    }

}

6.栈的简单应用(习题) (1)简单的括号匹配

问题:给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。

匹配的时候 

不符合的情况: 

 

 

 代码实现:

    public boolean isValid(String s) {
                //遇到左括号进栈,遇到右括号出栈匹配
                Stack st = new Stack<>();
                for(int i=0;i 
(2)逆波兰表达式求值 

逆波兰表达式就是后缀表达式,我们平时的在数学中的加减乘除就是一种中缀表达式,为了使计算机可以计算,所有就有了逆波兰表达式,目的就是让计算机好识别。

题目:有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

举例:((2 + 1) * 3) = 9    ------》逆波兰表达式: ["2","1","+","3","*"]

我们用代码实现就是将字符串中的逆波兰求出结果

示意图:

 代码实现:

    public int evalRPN(String[] tokens) {
        Stack st = new Stack<>();
        for(int i=0;i 
7.递归与栈的关系 
(1)关系说明 

由于Java中存在虚拟机栈,而递归和栈的后进后出关系相同,我们可以将递归转化用栈来进行实现。

(2)栈,虚拟机栈,栈帧的区别

栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作

虚拟机栈:是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型

栈帧:每个栈帧都对应一个被调用的方法,可以理解为方法的运行空间

二.队列 1.队列概念

队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的特点。其中进行插入操作的一端称为队尾(Tail/Rear) 出队列,进行删除操作的一端称为队头。

图解:

 

 2.Java中队列的实现

底层是接口,需要借助链表linkedList来进行实现,而链表又是根据双向链表进行实现的,下面我们会自己实现一个简单的队列

3.常用方法
方法功能
boolean offer(E e)入队列
E poll()出队列
peek()获取队头元素
int size()获取队列中有效元素个数
boolean isEmpty()检测队列是否为空
 4.队列常用操作练习
import java.util.linkedList;
import java.util.Queue;

public class QueueDemo {
    public static void main(String[] args) {
        Queue queue = new linkedList<>();
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        queue.offer(4);
        queue.offer(5);
        System.out.println(queue.size());
        System.out.println(queue.poll());//出队列
        System.out.println(queue.peek());//查看队头元素

    }
}
5.队列的模拟实现 (1)问题分析

队列一个队头标记,一个队尾标记,其中队尾添加相当于一个尾插,队头出队相当于为头删,其中还有一个size来标记队列中有多少个元素,从而进行判断队列是否为空,并且通过双向链表进行实现。

(2)代码实现
public class MyQueue {
    public static void main(String[] args) {
    Queue st=  new Queue<>();
//        System.out.println(st.poll());
        System.out.println(st.getSize());
        st.offer("111");
        st.offer("222");
        st.offer("333");
        System.out.println(st.getSize());
        System.out.println(st.peek());
        System.out.println(st.poll());
        System.out.println(st.peek());
        st.poll();
//        st.poll();
        System.out.println(st.peek());
//        System.out.println(st.poll());

    }
}
//原队列是接口,借助链表来进行实现
class Queue{
    Node first;//队头
    Node last;//队尾
    private int size;
    public int getSize(){
        return size;
    }
    //队尾中插入元素
    public E offer(E ele){
        //链表尾插
        Node newNode= new Node<>(ele);
        if(first==null){
            first=newNode;
            last=newNode;
        }else{
            Node cur=first;
            while(cur.next!=null){
                cur=cur.next;
            }
            cur.next=newNode;
            newNode.prev=cur;
            last=newNode;
        }
        size++;
        return  last.value;
    }
    //队头移除元素
    public E poll(){
        if(first==null){
            return null;
        }
        first=first.next;
        E value= first.value;
        first.prev.next=null;
        first.prev=null;
        size--;
        return value;
    }
    //获取队头元素,不移除
    public E peek(){
        if(first==null){
            throw new RuntimeException("队列为空,无法获取");
        }
        return first.value;
    }
    public boolean isEmpty(){
        return size==0;
    }
}
class Node{
    E value;
    Node prev;
    Node next;
    public Node(E value){
        this.value=value;
    }
}
6.循环队列 (1)引言

虽然Java中是通过链表来进行实现队列,但是还有另一种方法实现队列,那就是数组,由于直接使用数组会导致在删除后导致空间的浪费,所以就有了循环队列,这种方式实现的队列空间利用率是很好的。

(2)循环队列实现图解

 (3)代码实现

class MyCircularQueue {
        int[] arr;//数组
        int count;//有效元素个数
        int front;
        int rear;
        int size;//数组空间大小
    public MyCircularQueue(int k) {
        arr=new int[k];
        size=arr.length;
    }
    //向队尾添加元素
    public boolean enQueue(int value) {
        if(isFull()){
            return false;
        }
        arr[rear%size]=value;
        rear++;
        count++;
        return true;
    }
    //出队列
    public boolean deQueue() {
        if(isEmpty()){
            return false;
        }
        front++;
        count--;
        return true;

    }

    //获取队头元素
    public int Front() {
        if(isEmpty()){
            return -1;
        }
        return arr[front%size];
    }
    //获取队尾元素
    public int Rear() {
        if(isEmpty()){
            return -1;
        }
        return arr[(rear-1)%size];
    }
    //判空
    public boolean isEmpty() {
        return 0==count;
    }
    //判满
    public boolean isFull() {
        return size==count;
    }
}
三.栈和队列的转换习题 1.用队列实现一个栈

这里使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

 

 代码实现:

class MyStack {
    Queue s1 = new linkedList<>();
    Queue s2 = new linkedList<>();
    
    public MyStack() {

    }
    
    public void push(int x) {
        if(s1.size()!=0){
            s1.offer(x);
        }else if(s2.size()!=0){
            s2.offer(x);
        }else{
            s1.offer(x);
        }
    }
    
    public int pop() {

        int val=0;//保存需要返回的值
        //s1队列为空
        if(!s1.isEmpty()){
            while(s1.size()>1){
                s2.offer(s1.poll());
        }
        val=s1.poll();

        }else {
        //s2队列不为空
            while(s2.size()>1){
                s1.offer(s2.poll());
            }
            val=s2.poll();

        }
            return val;

    }
    
    public int top() {
      int val=0;//保存需要返回的值
        //s2队列为空
        if(!s1.isEmpty()){
            while(s1.size()>1){
                s2.offer(s1.poll());
        }
         val=s1.poll();
        s2.offer(val);

        }else {
        //s2队列不为空
            while(s2.size()>1){
                s1.offer(s2.poll());
            }
            val=s2.poll();
            s1.offer(val);

        }
            return val;
    }
    
    public boolean empty() {
        return s1.size()==0 && s2.size()==0;
    }
}
2.用栈实现一个队列 (1)实现目标

我们使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)

(2)图解

 (3)代码实现
class MyQueue {
    Stack st1;//入队列操作
    Stack st2;//出队列操作
    public MyQueue() {
        st1=new Stack<>();
        st2=new Stack<>();
        
    }
    //入队列
    public void push(int x) {
        st1.push(x);
    }
    //出队列
    public int pop() {
        if(st2.empty()){
            while(!st1.empty())
            st2.push(st1.pop());
        }
        return st2.pop();
    }
    //插卡队头元素
    public int peek() {
        if(st2.empty()){
            while(!st1.empty())
            st2.push(st1.pop());
        }
        return st2.peek();
    }
    //判断队列是否为空
   
    public boolean empty() {
        return st1.empty() && st2.empty();
    }
}
3.实现最小栈 (1)目的

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

(2)图解

(3 代码实现

class MinStack {
    Stack st;
    public MinStack() {
        st = new Stack<>();
    }
    //入栈
    public void push(int val) {
        if(st.empty()){
            st.push(val);
            st.push(val);
        }else{
            int min = getMin();
            if(min>val){
                st.push(val);
                st.push(val);
            }else{
                st.push(min);
                st.push(val);
            }
        }

    }
    //弹出栈顶元素
    public void pop() {
        st.pop();
        st.pop();
    }
    //查看栈顶元素
    public int top() {
        return st.peek();
    }
    //得到最小值
    public int getMin() {
        int t = st.pop();
        int min = st.peek();
        st.push(t);
        return min;
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/356510.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号