【数据结构基础】之栈与队列介绍,生动形象,通俗易懂,算法入门必看
创始人
2024-04-02 23:36:38
0

前言

在这里插入图片描述

本文为 数据结构基础【栈与队列】 相关知识,下边将对栈的概念与实现队列的概念与实现循环队列的概念与实现双端队列的概念与实现Java中栈和队列等进行详尽介绍~

📌博主主页:´Code_Wang的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~


目录

【数据结构基础】栈与队列

  • 前言
  • 目录
  • 一、栈
    • 1.栈的概念
    • 2.栈的实现
  • 二、队列
    • 1.队列的概念
    • 2.队列的实现
    • 3.循环队列的概念
    • 4.循环队列的实现
    • 5.双端队列的概念
    • 6.双端队列的实现
  • 三、java 中的栈和队列
    • 1.Java集合框架
    • 2.Java中的Stack(栈)
    • 3.Java中的Queue(队列)
    • 4.Java中的Deque(双端队列)
  • 后记

在这里插入图片描述

一、栈

1.栈的概念

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

2.栈的实现

  • (1)利用顺序表实现,即使用尾插 + 尾删的方式实现
  • (2)利用链表实现,则头尾皆可

相对来说,顺序表的实现上要更为简单一些,所以我们优先用顺序表实现栈。

// 基于数组实现链表
public class Stack {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();}
}

二、队列

1.队列的概念

  • 队列是一种仅支持在表尾进行插入操作、在表头进行删除操作的线性表,插入端称为队尾,删除端称为队首,因整体类似排队的队伍而得名。
  • 队列满足先进先出的性质(FIFO),元素入队即将新元素加在队列的尾,元素出队即将队首元素取出,它后一个作为新的队首。
    在这里插入图片描述

2.队列的实现

队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。

在这里插入图片描述

/*** 基于链表的队列实现*/
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();}
}

3.循环队列的概念

  • 实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。
  • 在顺序队列中,当下标走到队尾后,不能再往后走插入元素,但其实数组中还有位置,这叫做“假溢出”,为了解决这个问题提高数组利用率,就出现了循环队列。
  • 实现循环对列,最重要的是如何判断队列为空还是为满。
    在这里插入图片描述

4.循环队列的实现

如何区分循环队列的空与满:

  • 通过 size 属性记录当前队列中的元素个数
  • 保留一个位置,这个位置不能存储元素。这样当队满为 front == (rear+ 1)% length,队空为 front ==rear
  • front:指向循环队列的第一个元素下标,rear:指向循环队列的最后一个元素的下一个下标

在这里插入图片描述

/*** 循环队列*/
public class LoopQueue implements IQueue {// 指向循环队列的最后一个元素的下一个位置private int tail;// 队首元素,指向队列中的第一个元素索引private int front;// 有效元素个数private int size;private int[] data;public LoopQueue(int k) {data = new int[k + 1];}// 判断队列是否已满public boolean isFull() {if ((tail + 1) % data.length == front) {return true;}return false;}// 判断队列是否为空public boolean isEmpty() {
//        if (front == tail) {
//            return true;
//        }
//        return false;return tail == front;}// 入队public void offer(int value) {if (isFull()) {System.err.println("队列已满!");return;} else {data[tail] = value;tail = (tail + 1) % data.length;size++;}}// 出队public int poll() {if (isEmpty()) {System.err.println("队列为空!");return -1;} else {int value = data[front];front = (front + 1) % data.length;size--;return value;}}// 查看队首元素public int peek() {if (isEmpty()) {System.err.println("队列为空!");return -1;}return data[front];}// 查看队尾元素public int getTail() {if (isEmpty()) {System.err.println("队列为空!");return -1;}// 最后一个元素的下标int index = tail == 0 ? data.length - 1 : tail - 1;return data[index];}// 判断有效个数public int getSize() {return size;}public String toString() {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("[");// 最后一个元素的位置int lastIndex = tail == 0 ? data.length - 1 : tail - 1;for (int i = front; i != tail; ) {stringBuilder.append(data[i]);if (i != lastIndex) {stringBuilder.append(",");}i = (i + 1) % data.length;}stringBuilder.append("]");return stringBuilder.toString();}
}

5.双端队列的概念

双端队列(Deque:double ended queue)就是一个两端都是结尾的队列。队列的每一端都可以插入数据项和移除数据项。相对于普通队列,双端队列的入队和出队操作在两端都可进行。
在这里插入图片描述

6.双端队列的实现

我们使用最常用的顺序结构来存储双端队列,为了节省空间,把它首尾相连,构成循环队列。并且规定left指向左端的第一个元素,right指向右端的下一个位置。那么队空的判断则是left== right ,队满是(left-1+MAX)%MAX== right或者(right-left+MAX)%MAX==MAX。
在这里插入图片描述

class ListNode {//数据域public int val;//指针public ListNode next;//初始化值public ListNode(int val) {this.val = val;}
}public class Deque {public ListNode head;//头结点public ListNode last;//尾节点//在双端队列头那边添加节点变成新的头结点//在第一个节点处添加一个节点public void addFirst(int val) {//创建对象初始化值建立新节点ListNode node = new ListNode(val);//判断尾节点是否为空if (this.last == null) {//若为空就是头结点尾节点都是这个新创建的节点this.head = node;this.last = node;}//node成为新的头节点node.next = this.head;this.head = node;}//在双端队列尾那边添加节点变成新的尾节点//在节点的最后添加一个节点public void addLast(int val) {//创建对象初始化值建立新节点ListNode node = new ListNode(val);//判断尾节点是否为空if (this.last == null) {//若为空就是头结点尾节点都是这个新创建的节点this.head = node;this.last = node;}//node成为新的尾节点this.last.next = node;this.last = node;}//从头结点那边拿出Deque的一个节点public int offerFirst() {//判断头节点是否为空,如果是就输出!if (this.head == null) {System.out.println("!");return -1;}//如果不为空,把头结点指向的值拿出来int oldValue = this.head.val;//判断头结点尾节点是否重合,如果重合就表明双端队列为空if (this.head == this.last) {this.head = null;this.last = null;} else {//没有重合就接着找下一个节点变成新的头结点this.head = this.head.next;}return oldValue;}//从尾结点那边拿出Deque的一个节点public int offerLast() {//判断尾节点是否为空,如果就输出!if (this.last == null) {System.out.println("!");return -1;}// //如果不为空,把尾结点指向的值拿出来int oldValue = this.last.val;//判断头结点尾节点是否重合,如果重合就表明双端队列为空if (this.head == this.last) {this.last = null;this.head = null;} else {//遍历找到新的尾节点ListNode cur = this.head;while (cur.next != last) {cur = cur.next;}//把找到的最后一个节点做为尾节点this.last = cur;//尾节点.next=nullthis.last.next = null;}return oldValue;}//获取Deque处第一个节点的值public int peekFirst() {//判断头结点是否为空,是就输出!if (this.head == null) {System.out.println("!");return -1;}//返回头结点值return this.head.val;}//获取Deque上最后一个节点的值public int peekLast() {//判断尾结点是否为空,是就输出!if (this.last == null) {System.out.println("!");return -1;}//返回尾结点值return this.last.val;}//Check whether the Deque is emptypublic boolean empty() {return this.head == null;}public void display(){ListNode cur =head;while (cur!=last) {System.out.println(cur.val);cur = cur.next;}System.out.println(cur.val);}
}

三、java 中的栈和队列

1.Java集合框架

Java集合框架图:
在这里插入图片描述

2.Java中的Stack(栈)

Stack的方法及说明(Stack继承了Vecter,自己独有的方法只有以下5个):

方法解释
Object push(Object item)将元素推送到堆栈顶部
Object pop()移除并返回堆栈的顶部元素;如果我们在调用堆栈为空时调用pop(),则抛出’EmptyStackException’异常
Object peek()返回堆栈顶部的元素,但不删除它
boolean empty()如果堆栈为空,即顶部没有任何内容,则返回true;否则,返回false
int search(Object element)确定对象是否存在于堆栈中,如果找到该元素,它将从堆栈顶部返回元素的位置;否则,它返回-1

3.Java中的Queue(队列)

Queue的方法及说明:

方法解释
offer()将指定的元素插入此队列,插入成功返回 true;否则返回 false
add()将指定的元素插入此队列,当使用有容量限制插入失败时抛出一个 IllegalStateException异常
poll()获取并移除此队列的头,如果此队列为空,则返回 null
remove()获取并移除此队列的头,如果此队列为空,则抛出NoSuchElementException异常
peek()返回队列的头元素但不删除,如果此队列为空,则返回 null
element()返回队列的头元素但不删除,如果此队列为空,方法会抛出NoSuchElementException异常

4.Java中的Deque(双端队列)

Deque的方法及说明:

方法解释
addFirst()向队头插入元素,如果元素为空,则发生NPE(空指针异常)
addLast()向队尾插入元素,如果为空,则发生NPE
offerFirst()向队头插入元素,如果插入成功返回true,否则返回false
offerLast()向队尾插入元素,如果插入成功返回true,否则返回false
removeFirst()返回并移除队头元素,如果该元素是null,则发生NoSuchElementException
removeLast()返回并移除队尾元素,如果该元素是null,则发生NoSuchElementException
pollFirst()返回并移除队头元素,如果队列无元素,则返回null
pollLast()返回并移除队尾元素,如果队列无元素,则返回null
getFirst()获取队头元素但不移除,如果队列无元素,则发生NoSuchElementException
getLast()获取队尾元素但不移除,如果队列无元素,则发生NoSuchElementException
peekFirst()获取队头元素但不移除,如果队列无元素,则返回null
peekLast()获取队尾元素但不移除,如果队列无元素,则返回null

后记

在这里插入图片描述
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...