• 【数据结构】栈与队列


      栈与队列本质上都是一种线性表,他们存放与读取数据方式的不同,利用好他们各自的特点,就能够解决许多棘手的问题,他们会是之后我们编程中存放数据的两种重要数据结构。接下来就由我来带大家梳理一下他们各自的特点吧。

    一、栈

    1、概念

    :一种特殊的线性表,其 只允许在固定的一端进行插入和删除元素操作 。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出 的原则。
    简单来说就像存放羽毛球的羽毛球桶,后放入桶中的羽毛球会压住先放入桶中的羽毛球,在取羽毛球时,必须先取出后放入的羽毛球,才能取出下面先放入的羽毛球,也就是所谓的先进后出的原则

    压栈:栈的插入操作叫做进栈 / 压栈 / 入栈, 入数据在栈顶
    出栈:栈的删除操作叫做出栈。 出数据在栈顶
    所谓压栈就相当于是放羽毛球,出栈就是取羽毛球。在数据结构中就对应了存放数据和读取数据。

    2、栈的模拟实现

    栈可以用数组或链表实现,一般会采用数组来进行实现,因为相比于链表,数组在进行尾插的效率更高一些

    这里我们就主要来介绍一下栈的数组实现吧:

    和顺序表一样:一个存储数据的数组,一个变量记录个数,一个变量记录容量

    1. public class MyStack {
    2. public int[] elem;
    3. public int usedSize;
    4. }

    功能实现:

    (1)栈的初始化

    1. public MyStack() {
    2. this.elem = new int[10];
    3. }

    (2)压栈

    在压栈时一定要注意数组是否已经满了,如果满了就需要先进行扩容再完成插入操作,不然是会发生空指针异常的。

    1. public void push(int val) {
    2. if(isFull()) {
    3. //扩容
    4. elem = Arrays.copyOf(elem,2*elem.length);
    5. }
    6. elem[usedSize] = val;
    7. usedSize++;
    8. }
    9. public boolean isFull() {
    10. return usedSize == elem.length;
    11. }

    小tips:我们在学习数据结构时一定要注意好这些小细节,提高代码的严谨性和适用性。培养好这种思想对我们后续编程学习非常重要

    (3)出栈

    在出栈时我们也不能单单只想着实现出栈删除尾部元素就完了,要注意还要考虑空栈的情况,如果空栈的话就没有元素可以取出,直接返回即可

    1. public boolean empty() {
    2. return usedSize == 0;
    3. }
    4. public int pop() {
    5. if(empty()) {
    6. return -1;
    7. }
    8. int oldVal = elem[usedSize-1];
    9. usedSize--;
    10. return oldVal;
    11. }

    同时在实际应用中,我们可能只需要知道栈顶元素的值就可以了,不需要删除元素,这时我们就可以“小瞄一下”,只读取栈顶元素值而不删除了。

    1. public int peek() {
    2. if(empty()) {
    3. return -1;
    4. }
    5. return elem[usedSize-1];
    6. }

    3、Stack

    在java中内置了栈的实现类Stack类,我们只需要会调用即可。自己实现一编栈的功能也是为了加深我们对栈的深层理解。

    在java中, Stack 继承了 Vector Vector ArrayList 类似,都是动态的顺序表,不同的是 Vector 是线程安全的。

    常见方法

    使用示例:

    1. public static void main(String[] args) {
    2. Stack s = new Stack();
    3. s.push(1);
    4. s.push(2);
    5. s.push(3);
    6. s.push(4);
    7. System.out.println(s.size()); // 获取栈中有效元素个数---> 4
    8. System.out.println(s.peek()); // 获取栈顶元素---> 4
    9. s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
    10. System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
    11. if(s.empty()){
    12. System.out.println("栈空");
    13. }else{
    14. System.out.println(s.size());
    15. }
    16. }

    二、队列

    1、概念

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

    相信我们在生活中应该多少都有经历过排队,与栈不同,排队讲究的就是一个先来后到,先来的可以进行操作,后来的就得排在之后了。

    数据结构中的队列与现实中的排队是非常类似的,将插入的数据按先后顺序排列起来,在取用时则先取用“先来的”,再取用“后来的”

    2、队列的模拟实现

    队列可以用数组或链表实现,一般采用链表实现,因为在实现出队操作时相当于进行头删,链表进行头删的操作效率更高一些

    这里我们就主要来介绍一下队列的链表实现吧。

    1. public class MyQueue {
    2. static class ListNode {
    3. public int val;
    4. public ListNode prev ;
    5. public ListNode next;
    6. public ListNode(int val) {
    7. this.val = val;
    8. }
    9. }
    10. public ListNode head;
    11. public ListNode last;
    12. }

    (1)入队

    1. public void offer(int val) {
    2. ListNode node = new ListNode(val);
    3. if(head == null) {
    4. head = last = node;
    5. }else {
    6. last.next = node;
    7. node.prev = last;
    8. last = last.next;
    9. }
    10. }

    (2)出队

    1. public int poll() {
    2. if(head == null) {
    3. return -1;
    4. }
    5. int ret = head.val;
    6. if(head.next == null) {
    7. head = null;
    8. last = null;
    9. }else {
    10. head = head.next;
    11. head.prev = null;
    12. }
    13. return ret;
    14. }
    15. public int peek() {
    16. if(head == null) {
    17. return -1;
    18. }
    19. return head.val;
    20. }
    21. public boolean isEmpty() {
    22. return head == null;
    23. }

    3、Queue

    Java 中, Queue 是个接口,底层是通过链表实现

    常见方法:

    使用示例:

    1. public static void main(String[] args) {
    2. Queue q = new LinkedList<>();
    3. q.offer(1);
    4. q.offer(2);
    5. q.offer(3);
    6. q.offer(4);
    7. q.offer(5); // 从队尾入队列
    8. System.out.println(q.size());
    9. System.out.println(q.peek()); // 获取队头元素
    10. q.poll();
    11. System.out.println(q.poll()); // 从队头出队列,并将删除的元素返回
    12. if(q.isEmpty()){
    13. System.out.println("队列空");
    14. }else{
    15. System.out.println(q.size());
    16. }
    17. }

    三、总结

    栈和队列本质上就是两种存放与读取方式不同的线性表,栈的主要特点是先进后出,队列则是先进先出,我们可以根据实际应用场景来选择适合的结构。还是那句话,没有最好的数据结构,只有最适合的数据结构。

    那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。作者还是一个萌新,如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊

  • 相关阅读:
    在VScode中使用sftp传输本地文件到服务器端
    基于Vertx实现可配置及可扩展的IOT服务
    leetcode做题笔记129. 求根节点到叶节点数字之和
    信息系统项目管理师---第八章 项目质量管理
    uniapp:幸运大转盘demo
    《语音优先》智能语音技术驱动的交互界面设计与语音机器人设计(译者序)...
    面向对象编程
    给你一个大厂面试的机会,你能面试上吗?进来看看!
    数据库实验八 视图
    Java 19新特性:虚拟线程(Virtual Threads )
  • 原文地址:https://blog.csdn.net/acm_pn/article/details/140388711