用链表实现队列/栈

简介: 本文介绍如何用链表实现栈和队列,利用双链表头尾操作均为O(1)的特性,高效实现栈(push/pop)和队列(入队/出队)。代码简洁,逻辑清晰,适用于理解基础数据结构的底层实现。

用链表实现栈
一些读者应该已经知道该怎么用链表作为底层数据结构实现队列和栈了。因为实在是太简单了,直接调用双链表的 API 就可以了。
注意我这里是直接用的 Java 标准库的 LinkedList,如果你用之前我们实现的 MyLinkedList,也是一样的。
import java.util.LinkedList;

// 用链表作为底层数据结构实现栈
public class MyLinkedStack {
private final LinkedList list = new LinkedList<>();

// 向栈顶加入元素,时间复杂度 O(1)
public void push(E e) {
    list.addLast(e);
}

// 从栈顶弹出元素,时间复杂度 O(1)
public E pop() {
    return list.removeLast();
}

// 查看栈顶元素,时间复杂度 O(1)
public E peek() {
    return list.getLast();
}

// 返回栈中的元素个数,时间复杂度 O(1)
public int size() {
    return list.size();
}

public static void main(String[] args) {
    MyLinkedStack<Integer> stack = new MyLinkedStack<>();
    stack.push(1);
    stack.push(2);
    stack.push(3);

    System.out.println(stack.peek()); // 3
    System.out.println(stack.pop()); // 3
    System.out.println(stack.peek()); // 2
}

}
提示
上面这段代码相当于是把双链表的尾部作为栈顶,在双链表尾部增删元素的时间复杂度都是 O(1),符合要求。
当然,你也可以把双链表的头部作为栈顶,因为双链表头部增删元素的时间复杂度也是 O(1),所以这样实现也是一样的。只要做几个修改 addLast -> addFirst,removeLast -> removeFirst,getLast -> getFirst 就行了。
用链表实现队列
同理,用链表实现队列也是一样的,也直接调用双链表的 API 就可以了:
import java.util.LinkedList;

// 用链表作为底层数据结构实现队列
public class MyLinkedQueue {
private final LinkedList list = new LinkedList<>();

// 向队尾插入元素,时间复杂度 O(1)
public void push(E e) {
    list.addLast(e);
}

// 从队头删除元素,时间复杂度 O(1)
public E pop() {
    return list.removeFirst();
}

// 查看队头元素,时间复杂度 O(1)
public E peek() {
    return list.getFirst();
}

// 返回队列中的元素个数,时间复杂度 O(1)
public int size() {
    return list.size();
}

public static void main(String[] args) {
    MyLinkedQueue<Integer> queue = new MyLinkedQueue<>();
    queue.push(1);
    queue.push(2);
    queue.push(3);

    System.out.println(queue.peek()); // 1
    System.out.println(queue.pop()); // 1
    System.out.println(queue.pop()); // 2
    System.out.println(queue.peek()); // 3
}

}
提示
上面这段代码相当于是把双链表的尾部作为队尾,把双链表的头部作为队头,在双链表的头尾增删元素的复杂度都是 O(1),符合队列 API 的要求。
当然,你也可以反过来,把双链表的头部作为队尾,双链表的尾部作为队头。类似栈的实现,只要改一改 list 的调用方法就行了。
文末思考
双链表他比较牛,队列和栈的 API 考不倒它。但是你想一下,数组实现队列的时候,会不会有问题?
队列 API 要求一端增加元素,一端删除元素,而数组的头部无论是增加还是删除元素,时间复杂度都是 O(n)。这种情况下,有没有办法优化呢?
你可以思考一下,下一章我会告诉你答案。

相关文章
|
XML Java Linux
【Linux 第三方库】linux 交叉编译dbus,expat
【Linux 第三方库】linux 交叉编译dbus,expat
1030 0
|
物联网 Java Linux
Linux安装与配置Eclipse Paho库:实现MQTT通信
Eclipse Paho是一个开源的MQTT(Message Queuing Telemetry Transport)实现,提供了多种编程语言的客户端库,包括C、C++、Java、Python等。在Linux系统中,通过安装和配置Eclipse Paho库,我们可以方便地实现MQTT通信功能。本文将详细介绍在Linux系统中安装和配置Eclipse Paho库的步骤,以便于开发者在物联网项目中使用MQTT协议进行通信。
2834 0
|
安全 算法 物联网
MQTT 安全通信 SSL 双向认证 | 学习笔记
快速学习 MQTT 安全通信 SSL 双向认证
MQTT 安全通信 SSL 双向认证 | 学习笔记
|
传感器 网络协议 物联网
Linux MQTT通信:实现轻量级物联网传输协议
MQTT(Message Queuing Telemetry Transport)是一种轻量级的物联网传输协议,专门设计用于低带宽、不稳定网络环境下的传感器和物联网设备通信。本文将深入探讨Linux环境下如何实现MQTT通信,介绍MQTT协议的基本原理、常用MQTT库以及如何在Linux系统中编写MQTT客户端和服务器端程序。
2667 0
|
5月前
|
域名解析 缓存 边缘计算
CDN加速
CDN(内容分发网络)通过在全球部署节点服务器,将源站内容缓存至边缘节点,用户访问时由最近节点提供服务。基于DNS重定向与智能调度,实现就近加速,降低延迟,提升访问速度与网站可用性,有效应对高并发、带宽不足等问题。
|
5月前
|
缓存 监控 JavaScript
前端性能监控指标
前端性能指标包括白屏时间、首屏时间、DOM可操作时间和页面总加载时间。可通过注入代码或`window.performance` API进行量化统计,后者基于浏览器标准接口,提供精确的网络、解析与渲染各阶段耗时数据,助力性能优化。
|
5月前
|
存储 JavaScript 前端开发
XSS攻击
XSS(跨站脚本攻击)是攻击者通过网站漏洞注入恶意脚本,用户访问时执行,窃取数据、Cookie或劫持会话。主要分反射型和存储型,危害大。防御措施包括输入转义、白名单过滤及CSP内容安全策略,有效防止脚本注入。
|
5月前
|
JavaScript 前端开发 测试技术
Angular框架
本文深入解析Angular核心概念,涵盖ng-show与ng-if的性能差异、$rootScope与$scope的关系、表达式机制、Digest周期、定时器与监听器的取消方法。同时探讨Directive的restrict属性、作用域绑定方式及模块间通信策略。此外,介绍性能优化技巧、单元测试实践、Angular 2生命周期钩子、路由机制、事件发射器、AOT编译、安全防护与Shadow DOM等高级主题,全面提升开发技能。
|
消息中间件 Linux
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
1039 20
|
Linux 开发者
深入理解Linux I/O模型:同步、异步、阻塞与非阻塞
【8月更文挑战第1天】在探索操作系统的奥秘中,I/O模型作为影响性能的关键因素之一,常常让开发者们感到困惑。本文将通过浅显易懂的语言和实际代码示例,揭示Linux下同步与异步、阻塞与非阻塞的概念及其区别,并指导如何在实际应用中选择合适的I/O模型以优化程序性能。
640 1