Leetcoder Day9|栈与队列part01

语言:Java/C++ 

目录

理论基础

C++

队列

Java

队列

​编辑

232.用栈实现队列

225. 用队列实现栈

Queue

Deque

今日心得


理论基础

又是考研时数据结构里接触到的老朋友,栈是先进后出,队列是先进先出。

C++

现在刷题除了思路还要重点关注程序语言中的细节,卡哥给了C++中栈需要注意的一些问题:

  1. C++中stack 是容器么?
  2. 我们使用的stack是属于哪个版本的STL?
  3. 我们使用的STL中stack是如何实现的?
  4. stack 提供迭代器来遍历stack空间么?

栈和队列是STL(C++标准库)里面的两个数据结构,目前常用的C++中的STL有以下三种:

  1. HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码。
  2. P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。
  3. SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。

提供push 和 pop 等接口

所有元素必须符合先进后出(FILO)规则

栈不提供走访功能,也不提供迭代器(iterator)

因此C++中的栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说可以控制使用哪种容器来实现栈的功能)
所以 STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。

从上图可见,栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。常用的SGI STL,如果没有指定底层实现,默认是以deque为缺省情况下的底层结构。deque是一个双向队列,实现栈时,只要封住一段,只开通另一端就可以了。

也可以指定vector为栈的底层实现,初始化语句如下:

std::stack<int, std::vector<int> > third;  // 使用vector为底层容器的栈
队列

队列为先进先出(FIFO),同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。也不被归类为容器,而被归类为container adapter( 容器适配器)。

也可以指定 list 为起底层实现,初始化queue的语句如下:
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列

Java

栈的底层实现有两种:

  1. 基于数组的实现:顺序栈(ArrayList)
  2. 基于链表的实现:链式栈(LinkedList)

栈的基本操作包括入栈(push),即将元素添加到栈顶;出栈(pop),即将栈顶元素移除;以及访问栈顶元素(peek)

// 基于数组实现链表
public class Stack<E> {private E[] elementData; // 栈中的元素private int size; // 当前栈中元素个数public Stack() {elementData = (E[]) new Object[10]; // 默认长度为10}public Stack(int initCap) {elementData = (E[]) new Object[initCap]; // 初始长度}// 入栈public void push(E value) {// 扩容if(size == elementData.length) {int oldLength = elementData.length;int newLength = oldLength << 1;elementData = Arrays.copyOf(elementData, newLength);}// 在数组尾部添加元素elementData[size++] = value;}// 出栈,返回原来的栈顶元素public E pop () {if(getSize() == 0) {throw new NoSuchElementException("栈中没有元素!");}// 得到原来的栈顶元素位置E oldVaule = elementData[size - 1];size--;elementData[size] = null;return oldVaule;}// 查看栈顶元素public E peek() {if(getSize() == 0) {throw new NoSuchElementException("栈中没有元素!");}return elementData[size - 1];}// 获取当前栈的长度public int getSize() {return size;}@Overridepublic String toString() {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("[");for (int i = 0; i < size; i++) {stringBuilder.append(elementData[i]);if(i != size - 1) {stringBuilder.append(",");}}stringBuilder.append("]");return stringBuilder.toString();}
}
队列

队列是一种仅支持在表尾进行插入操作、在表头进行删除操作的线性表,插入端称为队尾,删除端称为队首。

队列和栈相同也是可以使用数组和链表实现,但是对于队列来说使用链表的结构效率更高

/*** 基于链表的队列*/
public class LinkedQueue{private Node head;private Node tail;private int size;private class Node {private int data;private Node next;public Node(int data) {this.data = data;}}// 入队public void offer(int value) {Node node = new Node(value);if(head == null) {head = tail = node;} else {tail.next = node;tail = node;}size++;}// 出队(队首元素出队)public int poll() {if(size == 0) {throw new NoSuchElementException("对列为空!");} else {int oldValue = head.data;Node tempHead = head;head = head.next;tempHead.next = null;size--;return oldValue;}}// 查看队首元素public int peek() {if(size == 0) {throw new NoSuchElementException("对列为空!");}return head.data;}public String toString() {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("front[");Node node = head;while (node != null) {stringBuilder.append(node.data);if(node.next != null) {stringBuilder.append(",");}node = node.next;}stringBuilder.append("]tail");return stringBuilder.toString();}
}
这里还要列出一下队列中Queue和Deque的基本操作:
Queue:
Queue的6个方法:

压入元素(添加):add()、offer()
相同:未超出容量,从队尾压入元素,返回压入的那个元素。
区别:在超出容量时,add()方法会对抛出异常,offer()返回false

弹出元素(删除):remove()、poll()
相同:容量大于0的时候,删除并返回队头被删除的那个元素。
区别:在容量为0的时候,remove()会抛出异常,poll()返回false

获取队头元素(不删除):element()、peek()
相同:容量大于0的时候,都返回队头元素。但是不删除。
区别:容量为0的时候,element()会抛出异常,peek()返回null。

普通队列(Queue)是指实现了先进先出的基本队列,例如 ArrayBlockingQueue 和 LinkedBlockingQueue,其中

ArrayBlockingQueue是用数组实现的普通队列,如下图所示

 LinkedBlockingQueue 是使用链表实现的普通队列,如下图所示:

⚠️一般情况下 offer() 和 poll() 方法配合使用,put() 和 take() 阻塞方法配合使用,add() 和 remove() 方法配合使用。程序中常用的是 offer() 和 poll() 方法,这两个方法比较友好,不会报错。

Deque(双端队列):

双端队列(Deque)是指队列的头部和尾部都可以同时入队和出队的数据结构,如下图所示:


​​​​​​​
232.用栈实现队列

使用栈实现队列的下列操作:

push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。

说明:

  • 你只能使用标准的栈操作 -- 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。
这道题首先就是捋清栈和队列的区别,栈的所有操作只能从栈顶进行,如进去的顺序是1、2、3、4,出去的顺序是4、3、2、1,而队列是队尾进,队首出,进和出的顺序是一样的,因此不难看出,我们需要两个栈来实现队列,一个将1、2、3、4压入栈中再逐一弹出,弹出顺序为4、3、2、1再进入另一个栈中,再次弹出,顺序就是1、2、3、4了。这个是整体的一个思路,但是如果涉及到出栈,判空等操作,需要更加注意细节。而peek本质上和pop是一样的。
class MyQueue {Stack<Integer> stackIn;Stack<Integer> stackOut;//initializepublic MyQueue() {stackIn=new Stack<>();  //输入栈stackOut=new Stack<>(); //输出栈}// 如果stackOut为空,那么将stackIn中的元素全部放入stackOut中private void dumpStackIn(){if(!stackOut.isEmpty()) return;while(!stackIn.isEmpty()){stackOut.push(stackIn.pop());}}public void push(int x) {stackIn.push(x);  //将元素放入输入栈}public int pop() {dumpStackIn();return stackOut.pop();}public int peek() {dumpStackIn();return stackOut.peek();}public boolean empty() {return stackIn.isEmpty() && stackOut.isEmpty();}
}/*** Your MyQueue object will be instantiated and called as such:* MyQueue obj = new MyQueue();* obj.push(x);* int param_2 = obj.pop();* int param_3 = obj.peek();* boolean param_4 = obj.empty();*/

225. 用队列实现栈

使用队列实现栈的下列操作:

  • push(x) -- 元素 x 入栈
  • pop() -- 移除栈顶元素
  • top() -- 获取栈顶元素
  • empty() -- 返回栈是否为空

注意:

  • 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
  • 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
  • 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

在理论基础中,有涉及到了Java中队列的两种类型,Queue和Deque。其实队列的形式有很多,常见的有8种,这是其中最常使用的两种。因为知道了双端队列的技巧,所以用队列实现栈很容易就想到了使用双端队列,从一头进和出队列即可。用普通的队列亦可实现:如将1、2、3、4入队,将除了4以外的其他元素弹出并再次入队,弹出4,即可实现pop操作。

Queue

class MyStack {Queue<Integer> queue;public MyStack() {queue=new LinkedList<>();}private void rePush(){int size=queue.size();while(size-->1){queue.offer(queue.poll());//把前size-1个重新入队,同时size--}}public void push(int x) {queue.offer(x);rePush(); //将队列中的前n-1个元素弹出并放回队列}public int pop() {return queue.poll();}public int top() {return queue.peek();}public boolean empty() {return queue.isEmpty();}
}
  • 时间复杂度: pop为O(n),其他为O(1)
  • 空间复杂度: O(n)

我在第一次写的时候,在push中使用了一次rePush操作,又在top中使用了一次,导致进行了两次重入队,输出错误,要记住如果在push里已经放入并重新入队,其他操作里就不需要了。

Deque

class MyStack {Deque<Integer> deque;public MyStack() {deque=new ArrayDeque<>();}public void push(int x) {deque.offerLast(x);}public int pop() {return deque.pollLast();}public int top() {return deque.peekLast();}public boolean empty() {return deque.isEmpty();}
}

今日心得

使用栈和队列时,一定也要关注底层实现,并且要熟悉基本操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/417435.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【记账本实战】07 记账本实战之登录注册页面(2)

记账本实战之登录注册页面(2) 目录 记账本实战之登录注册页面(2)前言登录注册页面表单组件的完善图形验证码组件制作修改之前的错误的代码axios 容错处理总结 前言 在本篇教程中&#xff0c;我们将会来完善登录和注册页面&#xff0c;并通过 canvas 手写一个验证码组件&#x…

推荐几个Github高星GoLang管理系统

在Web开发领域&#xff0c;Go语言&#xff08;Golang&#xff09;以其高效、简洁、高并发等特性逐渐成为许多开发者的首选语言。有许多优秀的Go语言Web后台管理系统&#xff0c;这些项目星星众多&#xff0c;提供了丰富的功能和良好的代码质量。本文将介绍一些GitHub高星的GoLa…

Linux第33步_TF-A移植的第1步_创建新的设备树

TF-A移植第1步就是创建新的设备树&#xff0c;并命名为“stm32mp157d-atk”。 和“TF-A移植”有关的知识点&#xff1a; 1)设备树英文名字叫做Device tree&#xff0c;用来描述板子硬件信息的&#xff0c;比如开发板上的 CPU有几个核 、每个CPU核主频是多少&#xff0c;IIC、…

JVM:垃圾收集器(7种)

垃圾收集器关系图&#xff1a; 如果两个收集器之间存在连线&#xff0c;就说明它们可以搭配使用。它们说在的区域则表示这个收集器属于新生代收集器还是老年代收集器。其中Serial&#xff08;串行&#xff09;、Parallel&#xff08;并行&#xff09; 1、Serial收集器 Serial收…

【力扣·每日一题】2182.构造限制重复的字符串(模拟 贪心 优先队列 C++ Go)

题目链接 题意 给你一个字符串 s 和一个整数 repeatLimit &#xff0c;用 s 中的字符构造一个新字符串 repeatLimitedString &#xff0c;使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。 返回 字典序最大的 repeatLimitedString 。 如果…

AutoDL——终端训练神经网络模型(忽略本地问题)

前言&#xff1a; 本人之前分享过一篇文章&#xff1a;使用pycharm连接远程GPU训练神经网络模型&#xff08;超详细&#xff01;&#xff09;&#xff0c;其中详细介绍了如何利用pycharm连接AutoDL算力云平台租用的GPU服务器训练神经模型。但有些小伙伴可能会因为一些原因而导…

unity-声音与声效OLD

声音与声效 基本概念audio clipaudio listeneraudio source 基本操作如何创建音频源&#xff08;背景音乐&#xff09;如何在测试的时候关闭声音 常用代码一般流程如何在一个物体上播放多个音效如何在代码中延时播放多个声音如何在代码中停止音频的播放如何判断当前是否在播放音…

大模型 RAG 面试篇

1.LLMs 存在模型幻觉问题&#xff0c;请问如何处理&#xff1f; 检索LLM。 先用问题在领域数据库里检索到候选答案&#xff0c;再用LLM对答案进行加工。 2.基于LLM向量库的文档对话 思路是怎么样&#xff1f; 加载文件读取文本文本分割文本向量化问句向量化在文本向量中匹配…

基于深度学习的车牌识别(YOLOv5和CNN)

基于深度学习的车牌识别(YOLOv5和CNN&#xff09; 目录 一、综述 二、车牌检测 一、综述 本篇文章是面向的是小白&#xff0c;想要学习深度学习上的应用&#xff0c;本文中目前应用了YOLO v5和CNN来对车牌进行处理&#xff0c;最终形成一个完整的车牌信息记录&#xff0c;…

路飞项目--02

补充&#xff1a;axios封装 # 普通使用&#xff1a;安装 &#xff0c;导入使用 const filmListreactive({result:[]}) axios.get().then() async function load(){let responseawait axios.get()filmList.resultresponse.data.results } # 封装示例&#xff1a;请求发出去之前…

AP5101C 高压线性 LED恒流驱动器 DFN2*2 LED灯汽车雾灯转向灯

产品描述 AP5101C 是一款高压线性 LED 恒流芯片 &#xff0c; 简单 、 内置功率管 &#xff0c; 适用于6- 100V 输入的高精度降压 LED 恒流驱动芯片。电流2.0A。AP5101C 可实现内置MOS 做 2.0A,外置 MOS 可做 3.0A 的。AP5101C 内置温度保护功能 &#xff0c;温度保护点为 130 …

linux编译源码,安装valgrind

目录 1 下载源码 2 在虚拟机上解压 3 进入解压的目录&#xff0c;执行make 4 安装 5 检查安装是否成功 本文参考了内存检查工具valgrind介绍、安装与使用-CSDN博客 1 下载源码 我到Valgrind: Current Releases 下载了valgrind 3.22.0源码 2 在虚拟机上解压 我使用的虚…