最新【数据结构 Java 版】详解栈和队列的实现(1),springboot特点面试题

最后

由于细节内容实在太多了,为了不影响文章的观赏性,只截出了一部分知识点大致的介绍一下,每个小节点里面都有更细化的内容!

小编准备了一份Java进阶学习路线图(Xmind)以及来年金三银四必备的一份《Java面试必备指南》

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

return usedSize==0;

}

}

1.4 问题


我们上述的栈是用数组实现的,入栈和出栈的时间复杂度都为 O(1)

那么栈能否用单链表实现呢?

  • 使用头插法:入栈时间复杂度为 O(1),出栈时间复杂度为 O(1)
  • 使用尾插法:入栈时间复杂度为 O(N),出栈时间复杂度为 O(N)

综上分析,栈可以通过单链表的头插头删法实现

1.5 栈的单链表实现


接下来将使用单链表实现栈,注意要使用头插头删法

class Node{

public int val;

public Node next;

public Node(int val){

this.val=val;

}

}

public class MyStack{

Node head=null;

// 压栈

public int push(int val){

Node node=new Node(val);

node.next = head;

head = node;

return head.val;

}

// 出栈

public int pop(){

if(empty()){

throw new RuntimeException(“栈为空”);

}

int val=head.val;

head=head.next;

return val;

}

// 查看栈顶元素,不删除

public int peek(){

if(empty()){

throw new RuntimeException(“栈为空”);

}

return head.val;

}

// 判断栈是否为空

public boolean empty(){

return head==null;

}

}

2. 队列

=========================================================================

2.1 概念


  • 队列:只允许在一端进行插入数据操作,在另一端进行删除操作的特殊线性表。
  • 特点:队列具有先进先出的特点
  • 对头:进行删除操作的一端
  • 队尾:进行插入操作的一段

在这里插入图片描述

2.2 问题


在我们实现队列前,要思考队列是靠数组实现呢还是拿链表实现呢?

在 Java 当中,队列是由 LinkedList 实现的,它的底层是一个双向链表。

  • 对于双向链表:我们只要在尾节点进行入队操作,在头节点进行出队操作就很容易实现
  • 对于单链表:我们只要增加一个尾巴节点,然后尾巴节点进行入队操作,头节点进行出队操作也能实现

至于数组,我们上述通过它实现了栈,而栈的特点其实是先进后出,与队列的先进先出原则矛盾。使用数组来实现队列会很麻烦。

2.3 队列的单链表实现


根据 Java 中队列的一些方法,接下来我们来实现自己的队列

class Node{

public int val;

public Node next;

public Node(int val){

this.val=val;

}

}

public class MyQueueLinked {

private Node front;

private Node rear;

private int usedSize;

// 入队列

public void offer(int val){

Node node=new Node(val);

if(this.front==null){

this.front=node;

this.rear=node;

}else{

this.rear.next=node;

this.rear=node;

}

this.usedSize++;

}

// 出队列

public int poll(){

if(isEmpty()){

throw new RuntimeException(“队列为空”);

}

int val=this.front.val;

if(this.front.next==null){

this.front=null;

this.rear=null;

}else{

this.front=this.front.next;

}

this.usedSize–;

return val;

}

// 得到队头元素不删除

public int peek(){

if(isEmpty()){

throw new RuntimeException(“队列为空”);

}else{

return this.front.val;

}

}

// 判断队列是否为空

public boolean isEmpty(){

return this.usedSize==0;

}

// 得到队列长度

public int size(){

return this.usedSize;

}

}

上述队列是用单链表实现的,也叫链式队列。大家也可以自行尝试一下双链表实现队列。

2.4 数组实现队列


假设现在我们用数组模拟入队列和出队列的模型在这里插入图片描述

解决方法:

  • 方法一:出队时,移动数组将后面的元素往前覆盖(时间复杂度为 O(N))
  • 方法二:使用循环的方法,实现循环队列(时间复杂度为 O(1))

2.5 循环队列


循环队列即数组使用了循环的方式,让数组方便队列的入队和出队。那么怎么实现呢?模型如下在这里插入图片描述

  • front:指向的位置就是队列的头,既已经存放数据的第一个下标(删除数据一端)
  • rear:指向的位置就是队列的尾巴,即可以存放数据的第一个下标(插入数据一端)

问题1:如何判断 front = rear 时是空还是满?

为了能够区别是空还是满,我们常假定当 front = rear 时为空。而对于满的话,我们则会将这个数组保留一个空的位置,那么当 rear+1 = front 时,则队列满了在这里插入图片描述

问题2:当 front 在数组最后一个位置时,如何再移它到数组的第一个位置呢?

(下标+1)%数组长度

接下来让我们实现循环队列

public class MyCircularQueue {

private int[] elem;

private int front;

private int rear;

public MyCircularQueue(int k){

this.elem=new int[k+1];

}

// 判断队列是否满了

public boolean isFull(){

return (this.rear+1)%this.elem.length==this.front;

}

// 判断队列是否为空

public boolean isEmpty(){

return this.front==this.rear;

}

// 入队

public void enQueue(int val){

if(isFull()){

this.elem= Arrays.copyOf(this.elem,2*this.elem.length);

}

this.elem[this.rear]=val;

this.rear=(this.rear+1)%this.elem.length;

}

// 出队

public int deQueue(){

if(isEmpty()){

throw new RuntimeException(“队列为空”);

}

int val=this.elem[this.front];

this.front=(this.front+1)%this.elem.length;

return val;

}

// 得到队头元素

public int getFront(){

if(isEmpty()){

throw new RuntimeException(“队列为空”);

}

return this.elem[this.front];

}

// 得到队尾元素

public int getRear(){

if(isEmpty()){

throw new RuntimeException(“队列为空”);

}

if(this.rear==0){

return this.elem[this.elem.length-1];

}

return this.elem[this.rear - 1];

}

}

注意:

假设一个数组长度为3,做题时可能人家用例入队了3次,但是按照上述队列为满的方式,我们其实是保留了一个位置是不能存放数据的。因此对于这种题目我们可以将我们的数组开大一位

2.6 双端队列


  • 双端队列:是指允许两端都可以进行入队和出队操作的队列
  • 特点:元素可以从队头出队和入队,也可以从队尾出队和入队

双端队列较简单,可以使用双向链表实现,这里就展示一下双端队列的模型在这里插入图片描述

3. 栈和队列练习题

==============================================================================

3.1 有效的括号


题目(OJ 链接):

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

有效字符串需满足:左括号必须用相同类型的右括号闭合,左括号必须以正确的顺序闭合。

题解:使用栈,遍历字符串,是左括号就进行入栈,是右括号就与栈顶元素比较。

public boolean isValid(String s) {

Stack stack=new Stack<>();

for(int i=0;i<s.length();i++){

char ch=s.charAt(i);

switch(ch){

case ‘)’:

if(stack.empty()||stack.pop()!=‘(’){

return false;

}

break;

case ‘}’:

if(stack.empty()||stack.pop()!=‘{’){

return false;

}

break;

case ‘]’:

if(stack.empty()||stack.pop()!=‘[’){

return false;

}

break;

default:

stack.push(ch);

break;

}

}

if(stack.empty()){

return true;

}

return false;

}

3.2 用队列实现栈


题目(OJ链接):

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppopempty)。

题解:

由于队列是先进先出,栈是先进后出,故一个队列无法满足实现栈的能力。而使用两个队列,对于入栈,我们我只要找到栈不为空的队列进行入队就行;对于出栈,我们只要将不为空的队列的除最后一个入队的元素全部转移到另一个空队列中,再将留下的元素出队

代码:

class MyStack {

private Queue q1;

private Queue q2;

public MyStack() {

q1=new LinkedList<>();

q2=new LinkedList<>();

}

// 入栈

public void push(int x) {

if(!q1.isEmpty()){

q1.offer(x);

}else if(!q2.isEmpty()){

q2.offer(x);

}else{

q1.offer(x);

}

}

// 出栈

public int pop() {

if(empty()){

throw new RuntimeException(“栈为空”);

}

if(!q1.isEmpty()){

int val1=0;

while(!q1.isEmpty()){

val1=q1.poll();

if(!q1.isEmpty()){

q2.offer(val1);

}

}

return val1;

}else{

int val2=0;

while(!q2.isEmpty()){

val2=q2.poll();

if(!q2.isEmpty()){

q1.offer(val2);

}

}

return val2;

}

}

// 得到栈顶元素不删除

public int top() {

if(empty()){

throw new RuntimeException(“栈为空”);

}

if(!q1.isEmpty()){

int val1=0;

while(!q1.isEmpty()){

val1=q1.poll();

q2.offer(val1);

}

return val1;

}else{

int val2=0;

while(!q2.isEmpty()){

val2=q2.poll();

q1.offer(val2);

}

return val2;

}

}

// 判断栈是否为空

public boolean empty() {

return q1.isEmpty()&&q2.isEmpty();

}

}

3.3 用栈实现队列


题目(OJ 链接):

请你仅使用两个栈实现先入先出队列。

题解:

我们可以创建两个栈 s1、s2,s1 用来入队,s2 用来出队

代码:

class MyQueue {

private Stack s1;

private Stack s2;

public MyQueue() {

s1=new Stack<>();

最后

由于篇幅限制,小编在此截出几张知识讲解的图解

P8级大佬整理在Github上45K+star手册,吃透消化,面试跳槽不心慌

P8级大佬整理在Github上45K+star手册,吃透消化,面试跳槽不心慌

P8级大佬整理在Github上45K+star手册,吃透消化,面试跳槽不心慌

P8级大佬整理在Github上45K+star手册,吃透消化,面试跳槽不心慌

P8级大佬整理在Github上45K+star手册,吃透消化,面试跳槽不心慌

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

3.3 用栈实现队列


题目(OJ 链接):

请你仅使用两个栈实现先入先出队列。

题解:

我们可以创建两个栈 s1、s2,s1 用来入队,s2 用来出队

代码:

class MyQueue {

private Stack s1;

private Stack s2;

public MyQueue() {

s1=new Stack<>();

最后

由于篇幅限制,小编在此截出几张知识讲解的图解

[外链图片转存中…(img-m27ncFIF-1715656590947)]

[外链图片转存中…(img-XRbWZMmG-1715656590948)]

[外链图片转存中…(img-rAIY4qAW-1715656590948)]

[外链图片转存中…(img-6kKA9R2l-1715656590949)]

[外链图片转存中…(img-sm19IUbV-1715656590949)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构》(C语言)是一本经典的教材,编写者严蔚敏老师是我国著名计算机科学家之一。该教材囊括了数据结构的基本概念、逻辑结构、存储结构以及常见的算法和高级数据结构。 在书中,严蔚敏老师为了帮助读者更好地理解和掌握数据结构,设计了许多典型习。这些习内容丰富,涵盖了数据结构中的各个知识点和难度级别。通过解答这些习,读者可以巩固基本概念,熟悉常见算法和数据结构实现方式。 同时,书中还包含了一些考研真详解。考研真是指近年来的研究生考试中出现的与数据结构相关的问。通过对这些考研真的详细解析,读者可以了解考试中的出思路和解技巧,为应对考试做好准备。 这本教材中的典型习和考研真详解给读者提供了一个练习和检验自己掌握程度的机会。通过不断解答这些目,读者可以逐渐提高对数据结构的理解和运用能力。同时,通过分析解过程和思路,读者也可以提高自己的解思维和分析问的能力。 《数据结构》(C语言)典型习和考研真详解不仅适用于计算机相关专业的本科生和研究生,还适用于对数据结构感兴趣的其他读者。无论是作为教材的配套资源还是作为自学的参考资料,这本书都能帮助读者深入理解和应用数据结构的知识,提高自己在相关领域的学术研究或职业发展水平。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值