数据结构 Java数据结构 --- 栈和队列_平台将创建用户补全后的mystack类的对象; 调用对象的push(t item)方法,添加数据;(3)

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

    tail = newNode;
}

// 出队列
public Integer poll(){
    // 如果当前队列就是空队列,再去poll显然不科学
    if(head == null){
        // 如果出队列失败,返回一个错误的值
        return null;
    }
    int ret = head.val;
    head = head.next;
    if(head == null){
        //删除当前元素之后,队列变成了空的队列
        tail = null;

    }
    return ret;
}

// 取队首的元素
public Integer peek() {
    if(head == null){
        return null;
    }
    return head.val;
}

}


### 2.3 循环队列


实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。  
 环形队列通常使用数组实现。  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/da0865b0b15349e2b86fe1ec9c226701.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)



public class MyQueueByArray {
private int[] elem = new int[100];
// [head,tail) 有效元素的范围. 注意, tail 可能在 head 之前
private int head = 0; // 表示对首元素下标
private int tail = 0; // 表示对尾下一个元素的下标
private int size = 0; // 元素个数

public void offer(int val){
    if (size == elem.length) {
        //队列满了, 无法继续插入
        return ;
    }
    // 保证这个操作下标不能越界
    elem[tail] = val;
    tail++;
    // tail ++ 之后如果超出数组有效范围,就从头开始
    if (tail >= elem.length){
        tail = 0;
    }
    size++;
}

public Integer poll(){
    if (size == 0){
        return null;
    }
    Integer ret = elem[head];
    head++;
    if(head >= elem.length){
        head = 0;
    }
    size--;
    return ret ;
}

public Integer peek(){
    if(size == 0){
        return null;
    }
    return elem[head];
}

}


## 3. 双端队列 (Deque)


### 3.1 概念


**双端队列(deque)** 是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。  
 那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。


## 4. java 中的栈和队列


**Stack**




| 方法 | 解释 |
| --- | --- |
| E push(E item) | 压栈 |
| E pop() | 出栈 |
| E peek() | 查看栈顶元素 |
| boolean empty() | 判断栈是否为空 |
| **Stack方法的演示:** |  |



public static void main(String[] args) {
    Stack<Integer> stack = new Stack<>();
    //压栈
    stack.push(1);
    stack.push(2);
    stack.push(3);
    stack.push(4);
    //查看栈顶元素
    System.out.println(stack.peek());

    //出栈
    int ret = stack.pop();
    System.out.println(ret);  //4
    ret = stack.pop();
    System.out.println(ret);  //3
    ret = stack.pop();
    System.out.println(ret);  //2
    ret = stack.pop();
    System.out.println(ret);  //1
    //判断栈是否为空
    System.out.println(stack.empty());
    //此时栈为空 如果 查看栈顶元素 或者 出栈 会报异常(EmptyStackException)
    System.out.println(stack.peek());
    System.out.println(stack.pop());
}

运行结果:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/7e126adafedf4887bc2c09efd8e9ef02.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)


**Queue**




| 错误处理 | 抛出异常 | 返回特殊值 |
| --- | --- | --- |
| 入队列 | add(e) | offer(e) |
| 出队列 | remove() | poll() |
| 队首元素 | element() | peek() |


**Deque**




| 头部/尾部 | 头部元素(队首) | 尾部元素(队尾) |
| --- | --- | --- |
| 错误处理 | 抛出异常 | 返回特殊值 | 抛出异常 |  返回特殊值 |
| 入队列 | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
| 出队列 | removeFirst() | pollFirst() | removeLast() | pollLast() |
| 获取元素 | getFirst() | peekFirst() | getLast() | peekLast() |



> 
> **总结:**  
>  **Stack:**  
>  `push` ,`pop`,`peek`.当当前是一个空栈的,再去pop或者peek就会产生异常.  
>  **Queue:**  
>  `add`,`remove`,`element` 如果当前操作失败就会抛出异常;  
>  `offer`,`poll`,`peek` 如果操作失败就会返回一个错误值;
> 
> 
> 


## 5. LeetCode 题目


### 第一题 : 有效的括号


[有效的括号](https://bbs.csdn.net/topics/618668825)  
 LeetCode 20:  
 **描述:**  
 给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。  
 有效字符串需满足:


1. 左括号必须用相同类型的右括号闭合。
2. 左括号必须以正确的顺序闭合。


#### 解题思路:



> 
> **1. 遍历字符串,依次取出字符串中的字符.  
>        1.1 如果取出的字符串为左括号例如’(‘,’[‘,’{‘.就放入栈中  
>        1.2 如果取出的字符串为右括号例如’)‘,’]‘,’}'.就和栈顶元素比较是否匹配.  
>              a) 匹配就出栈,然后继续遍历.  
>              b) 不匹配就直接返回false  
>        1.3 如果栈为空,且取出的字符是右括号,则返回false没有例如字符串`"]()"`  
>  2. 遍历结束后,判断是否栈为空  
>        2.1 如果为空 则满足题意 return true;  
>        2.2 如果不为空 表示没有足够匹配的字符, return false; 如字符串`"["`**
> 
> 
> 


#### 画图解析:


![在这里插入图片描述](https://img-blog.csdnimg.cn/afbc30e054614bd9873c9154e4f2ef96.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/4871f69e61154b7da3492008fac67992.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)


#### 代码实现:



public boolean isValid(String str) {
    Map<Character,Character> map = new HashMap<>();
    map.put('(',')');
    map.put('[',']');
    map.put('{','}');

    //1.先创建一个栈,栈中保存字符类型即可
    Stack<Character> stack = new Stack<>();
    //2.遍历字符串的每个字符
    for (int i = 0; i < str.length(); i++) {
        char ch = str.charAt(i);
        //3.判断字符 ch 是否为左括号,如果是,就入栈
        if (ch == '(' || ch == '[' || ch == '{'){
            stack.push(ch);
            continue;//进入下次循环,取出下一个字符
        }
        if(stack.empty()){
            //如果ch不是左括号,且栈为空,则不是合法括号
            return false;
        }
        //4.判断ch是否是右括号,如果是,就取栈顶元素比较是否相等
        char top = stack.pop();//栈顶元素
        //以下是3种情况合法情况 -- 写法1
        /\*if(top == '(' && ch == ')') {

continue;
}
if(top == ‘[’ && ch == ‘]’) {
continue;
}
if(top == ‘{’ && ch == ‘}’) {
continue;
}*/
// 判断合法情况 – 写法2
if(map.get(top) == ch){
continue;
}
//如果三种情况都不满足,表示不是合法情况
return false;
}
//遍历完成后 如果栈为空 则满足条件
if(stack.empty()) {
return true;
}
//否则就不合法
return false;
}


### 第二题 : 用队列实现栈


[用队列实现栈](https://bbs.csdn.net/topics/618668825)  
 LeetCode 225:  
 **描述:**  
 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。  
 实现 MyStack 类:


* void push(int x) 将元素 x 压入栈顶。
* int pop() 移除并返回栈顶元素。
* int top() 返回栈顶元素。
* boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。


注意:


* 你只能使用队列的基本操作 —— 也就是 push to back、peek/pop from front、size 和 is empty 这些操作。
* 你所使用的语言也许不支持队列。 你可以使用 list (列表)或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。


#### 解题思路:



> 
> **1. 用两个队列来模拟一个栈的效果,引用两个队列 A 和 B .  
>  2. 入栈 : 直接把元素入队到A中即可  
>  3. 出栈 : 因为队列是先进先出的,栈是后进先出的,可以让 A队列 元素出队列然后入队列到 B队列 中,直到A队列中最后一个元素的时候,直接出队列,就实现了后进先出.然后要让A和B交换,始终让入栈到A队列中.  
>  4. 取栈顶元素 : 取栈顶元素就是 出栈 的元素, 不过取栈顶元素要把这个元素返回去  
>  5. 判断是否为空 : A 和 B都为空的时候 就是空栈**
> 
> 
> 


#### 画图解析:


![1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)](https://img-blog.csdnimg.cn/2d12071f0ff4452dbf56aa0bd9dc0844.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)


#### 代码实现:



import java.util.LinkedList;
import java.util.Queue;

public class MyStackByDoubleQueue {
private Queue A = new LinkedList<>();
private Queue B = new LinkedList<>();

public void push(int x) {
    // x往A中入队列即可
    A.offer(x);
}

public Integer pop() {
    if (empty()){
        return null;
    }
    // 把A中的元素往 B 中放
    while(A.size() > 1) {
        Integer font = A.poll();
        B.offer(font);
    }
    //当循环结束后,A 中 应该只剩1个元素
    //这个元素就应该是被出栈的元素
    int ret = A.poll();
    //交换A和B
    swapAB();
    return ret;
}

private void swapAB(){
    Queue<Integer> tmp = A;
    A = B;
    B = tmp;
}

public Integer top() {
    if (empty()){
        return null;
    }
    // 把A中的元素往 B 中放
    while(A.size() > 1) {
        Integer font = A.poll();
        B.offer(font);
    }
    //当循环结束后,A 中 应该只剩1个元素
    //这个元素就应该是被出栈的元素
    int ret = A.poll();
    B.offer(ret); // top 和 pop的区别就是 top要把元素返回去,pop不需要返回去
    //交换A和B
    swapAB();
    return ret;
}

public boolean empty() {
    return A.isEmpty() && B.isEmpty();
}

}


### 第三题 : 用栈实现队列


[用栈实现队列](https://bbs.csdn.net/topics/618668825)  
 LeetCode 232:  
 **描述:**  
 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):  
 实现 MyQueue 类:


* void push(int x) 将元素 x 推到队列的末尾
* int pop() 从队列的开头移除并返回元素
* int peek() 返回队列开头的元素
* boolean empty() 如果队列为空,返回 true ;否则,返回 false


#### 解题思路:



> 
> **1. 引用2个栈A和B,A专门用来入队列;B专门用来出队列  
>  2. 实现入队列: 先把B中的所有元素都放到A中(因为出栈的时候元素会放入B中),然后直接往A里入栈.  
>  3. 实现出队列: 后进先出的栈实现先进先出的队列,要让A中的所有元素移入B中,先出的的元素就是后进的,此时栈顶就是就是最先进入的元素,B中出栈操作即可  
>  4. 实现取队首元素: 同出队列操作,把A所有元素放入B中,然后取B的栈顶元素就是队首元素.  
>  5. 判空: A 和 B 都为空.**
> 
> 
> 


#### 画图解析:


![在这里插入图片描述](https://img-blog.csdnimg.cn/3455386931ed4ccfb1bd573e0d1a2362.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6d98f81106fa4a82a8ea6429fa6dea22.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)


![在这里插入图片描述](https://img-blog.csdnimg.cn/54f148039e364471851517d8d69d1732.png)


#### 代码实现:



import java.util.Stack;

public class MyQueueByDoubleStack {
private Stack A = new Stack<>();
private Stack B = new Stack<>();

public void push(int x) {
    //1.先将B中的元素 放入 A 中
    while (!B.isEmpty()){
        int tmp = B.pop();
        A.push(tmp);
    }
    //2.把新元素放入A中
    A.push(x);
}


public Integer pop() {
    //1.如果为空 直接返回
    if(empty()){
        return null;
    }
    //2.把A中的元素都给B
    while(!A.isEmpty()){
        int tmp = A.pop();
        B.push(tmp);
    }
    //3.针对B进行出栈
    return B.pop();
}

public Integer peek() {
    //1.如果为空 直接返回
    if(empty()){
        return null;
    }
    //2.把A中的元素都给B
    while(!A.isEmpty()){
        int tmp = A.pop();
        B.push(tmp);
    }
    //3.取B的栈顶元素
    return B.peek();
}

public boolean empty() {
    return A.isEmpty() && B.isEmpty();
}

}


### 第四题 : 最小栈


[最小栈](https://bbs.csdn.net/topics/618668825)  
 LeetCode 155:  
 设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。


* push(x) —— 将元素 x 推入栈中。
* pop() —— 删除栈顶的元素。
* top() —— 获取栈顶元素。
* getMin() —— 检索栈中的最小元素。


#### 解题思路:



> 
> **1. 引用2个栈A和B, A按照正常栈的规则入栈出栈,B存放的是A的最小值以及A历史的最小值  
>  2. 实现入栈操作: A中: 直接入栈 . B中: 取要入栈的值 和 B栈顶元素比较,把较小值入栈到B中.  
>  3. 实现出栈操作: A 和 B 一起出栈  
>  4. 实现取栈顶元素操作: 直接取 A 栈顶元素  
>  5. 实现取最小值操作: 直接取 B 栈顶元素**
> 
> 
> 


#### 画图解析:


![在这里插入图片描述](https://img-blog.csdnimg.cn/91f52ca8c52c4919ad9964b5fe4cf953.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/0ef2138dcadc44fe98e5d1c73171259d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/ddd90349ac4845b785afcf057313227f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAd3d6enp6enp6enp6enp6,size_20,color_FFFFFF,t_70,g_se,x_16)


#### 代码实现:



import java.util.Stack;

public class MinStack {
private Stack A = new Stack<>();
private Stack B = new Stack<>();

public void push(int x){
    //A 直接入栈
    A.push(x);
    //如果B为空 直接入栈
    if(B.isEmpty()){
        B.push(x);
        return;
    }
    //如果B不为空,比较x和B栈顶的较小值,将较小值入栈
    int min = B.peek();
    min = min < x ? min : x;
    B.push(min);
}

public Integer pop(){
    //如果A为空 直接返回
    if(A.isEmpty()){
        return null;
    }
    //B和A同时出栈
    B.pop();
    return A.pop();
}

public Integer top(){
    //如果A为空 直接返回
    if(A.isEmpty()){
        return null;
    }
    return A.peek();
}

public Integer getMin(){
    //如果B为空 直接返回
    if(B.isEmpty()){
        return null;
    }
    //B的栈顶即使最小元素
    return B.peek();
}

}


### 第五题 : 设计循环队列



![img](https://img-blog.csdnimg.cn/img_convert/2a882e2d54c53c489564f830f3fca0ee.png)
![img](https://img-blog.csdnimg.cn/img_convert/1d5d2bc2873439e3cd4e5b5a3eddac9b.png)

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**


            return null;
        }
        return A.peek();
    }

    public Integer getMin(){
        //如果B为空 直接返回
        if(B.isEmpty()){
            return null;
        }
        //B的栈顶即使最小元素
        return B.peek();
    }

}


第五题 : 设计循环队列

[外链图片转存中…(img-6Kh9facX-1715809238834)]
[外链图片转存中…(img-qjNJi6NA-1715809238835)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值