【数据结构】—— Java实现双向链表

news2024/11/27 9:44:51

Java实现双向链表

  • 一、链表的概念及结构
  • 二、头指针与头结点的异同
  • 三、代码实现

一、链表的概念及结构

在这里插入图片描述

我们在单链表中,有了next指针。这就使得我们查找下一个结点的时间复杂度为O(1)。可是我们要查找的是上一个结点的话,那最坏的时间复杂度就是O(n)了,因为我们每次都要从头遍历查找。

为了克服单向性这一缺点,我们就提出了双向链表。双向链表(double linked list)是在单链表的每个结点中,在设置一个指向其前驱结点的指针域。 所以双向链表的结构都有两个指针域,一个指向直接后继,另一个指向直接前驱。

二、头指针与头结点的异同

  • 头指针
    1.头指针是指链表指向第一个结点的指针,若链表有头节点,则是指向头节点的指针。
    2.头指针是具有标识作用,所以常用头指针冠以链表的命名
    3.无论链表是否为空,头指针均不为空。头指针是链表的必要元素
    若头指针为空,则链表不存在。

  • 头结点
    1.头结点是为了操作的统一和方便而设立的,放在第一元素的结点之前,其数据域一般无意义(也可存放链表的长度)
    2.有了头结点,对在第一元素结点前插入结点和删除第一节点,其操作与其他结点的操作就统一了
    3.头节点不一定是链表的必须元素

三、代码实现

public class LinkedList {
    //一般脱离类无实际意义,所以定义为静态类
    static class Node {
        int val;
        Node prev;
        Node next;

        public Node(){
        }

        public Node (int val) {
            this.val = val;
        }
    }
    //定义头结点和尾结点
    Node head;
    Node last;

        //头插法
        public void addFirst(int val){
            Node node = new Node(val);
            if (head == null) {
                head = node;
                last = node;
                return ;
            }
            node.next = head;
            head.prev = node;
            head = node;
        }
        //尾插法
        public void addLast(int val){
            Node node = new Node(val);
            if (head == null) {
                head = node;
                last = node;
                return ;
            }
            last.next = node;
            node.prev = last;
            last = node;
        }
        //任意位置插入,第一个数据节点为0号下标
        public boolean addIndex(int index,int val){
            if (head == null) {
                return false;
            }
            //判断所给的索引合法性
            if (index < 0 || index > size()) {
                throw new RuntimeException("the index is not illegal!");
            }
            //第一个位置插入的时候,此时就是头插法
            if (index == 0) {
                addFirst(val);
                return true;
            }
            //最后一个位置插入则为尾插法
            if (index == size()) {
                addLast(val);
                return true;
            }
            //最后考虑中间位置的插入即可
            //1.定义临时头结点,先走到待插入位置的前一个位置
            Node temp = head;
            while (index > 1) {
                temp = temp.next;
                index--;
            }
            //2.对元素进行插入
            Node node = new Node(val);
            node.next = temp.next;
            node.prev = temp;
            temp.next.prev = node;
            temp.next = node;
            return true;
        }

        //查找是否包含关键字key是否在单链表当中
        public boolean contains(int key){
            if (head == null) {
                return false;
            }
            //只要在链表找到我们就返回false就行
            Node temp = head;
            while (temp != null) {
                if (temp.val == key) {
                    return true;
                }
                temp = temp.next;
            }
            return false;
        }

        //删除第一次出现关键字为key的节点
        public void remove(int key){
            if (head == null) {
                return ;
            }
            //只要存在我们才可以去删除
            if (!contains(key)) {
                throw new RuntimeException("the key is not exist !");
            }
            //如果是头节点的情况就直接删除
            if (head.val == key) {
                head  = head.next;
                head.prev = null;
                return ;
            }

            //1.找到第一次出现的关键字key的前一个位置
            Node temp = head;
            while (temp != null) {
                if (temp.val == key) {
                    temp.prev.next = temp.next;
                    temp.next.prev = temp.prev;
                    return;
                }
                temp = temp.next;
            }
        }

        //删除所有值为key的节点
        public void removeAllKey(int key){
            if (head == null) {
                return ;
            }
            while (contains(key)) {
                remove(key);
            }
        }

        //得到单链表的长度
        public int size(){
            if(head == null) {
                return 0;
            }
            Node temp = head;
            int size = 0;
            while (temp != null) {
                size++;
                temp = temp.next;
            }
            return size;
        }

        //遍历双向链表
        public void display(){
            if (head == null) {
                return ;
            }
            Node temp = head;
            while (temp != null) {
                System.out.print(temp.val + " ");
                temp = temp.next;
            }
        }

        //清空链表
        public void clear(){
            head = null;
            last = null;
        }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用图记忆C语言中的运算符优先级

运算符优先级以及结合方向的统计表&#xff0c;网上到处可见。本文画了一张图&#xff0c;以便记忆&#xff01; 1. 总体来说优先级 初级运算 > 单目运算 > 双目运算 > 三目运算 > 赋值运算 > 逗号运算 2. 双目细分 算术运算 > 位移运算 > 关系运算 &g…

今年十八,基础过关

目录 前言 第一关&#xff1a;KEY在哪里 再加密一次你就得到key啦~ 猜猜这是经过了多少次加密&#xff1f; 据说MD5加密很安全&#xff0c;真的是么&#xff1f; 种族歧视 HAHA浏览器 key究竟在哪里呢&#xff1f; key又找不到了 冒充登陆用户​编辑 比较数字大小 就不让你…

Linux应用编程---14.UDP服务器、客户端编程

Linux应用编程—14.UDP服务器、客户端编程 ​ 之前有介绍过UDP是一种无连接、尽最大努力交付、面向报文的协议。应用层交给UDP多长的报文&#xff0c;UDP就照样发送。Linux下UDP属于数据报socket。数据报socket流程图如图1所示&#xff1a; 图1 数据报socket流程图 ​ 新引入的…

FourIE:一种最新联合事件抽取SOTA论文解读

Cross-Task Instance Representation Interactions and Label Dependencies for Joint Information Extraction with Graph Convolutional Networks 论文&#xff1a;Cross-Task Instance Representation Interactions and Label Dependencies for Joint Information Extractio…

Vue2的前端路由(vue-router)

一、路由 路由 (英文&#xff1a;router)就是页面地址与组件之间的对应关系 二、路由方式 服务器端路由、前端路由 三、前端路由 前端路由&#xff1a;地址和组件之间的对应关系&#xff0c;即由前端来维护一组路由规则&#xff08;地址和组件之间的对应关系&#xff09;&…

xlsx.utils.sheet_to_json的{ header: 1 }起的作用,header属性的研究

XLSX.utils.sheet_to_json 是为了把excel里面的数据解析出来&#xff0c;这是它的定义&#xff1a; 其中&#xff0c;worksheet表示特定表名的工作表&#xff0c;opts属于可要可不要的参数。 opts也有几种类型&#xff1a; export interface Sheet2JSONOpts extends DateNFOp…

selinux 控制

在某些Linux发行版上&#xff0c;默认情况下启用SELinux&#xff0c;如果不了解SELinux的工作原理以及如何配置它的基本详细信息&#xff0c;则可能会导致一些不必要的问题。一般强烈建议了解了SELinux 之后再去实现它。但是&#xff0c;在了解 SELinux 的实现细节之前&#xf…

由浅入深,详解ViewModel的那些事

Hi&#xff0c;你好 &#x1f603; 引言 关于 ViewModel &#xff0c;Android 开发的小伙伴应该都非常熟悉&#xff0c;无论是新项目还是老项目&#xff0c;基本都会使用到。而 ViewModel 作为 JetPack 核心组件&#xff0c;其本身也更是承担着不可或缺的作用。 因此&#x…

STL list 模拟实现

list 概述 相比于 vector 的连续线性空间&#xff0c;list 采用的是零散的空间&#xff0c;它的好处是每次插入或删除一个元素&#xff0c;就配置或释放一个元素空间。 list 是支持常数时间从容器任何位置插入和移除元素容器&#xff0c;但不支持快速随机访问。list 通常实现…

Linux操作系统之进程间通讯—共享内存与消息队列

文章目录一、共享内存1、共享内存的原理2、共享内存的实现三、消息队列1、消息队列原理2、消息队列实现一、共享内存 1、共享内存的原理 共享内存为多个进程之间共享和传递数据提供了一种有效的方式。共享内存是先在物理内存上申请一块空间&#xff0c;多个进程可以将其映射到…

dp (四) 打家劫舍

打家劫舍(一)_牛客题霸_牛客网 描述 你是一个经验丰富的小偷&#xff0c;准备偷沿街的一排房间&#xff0c;每个房间都存有一定的现金&#xff0c;为了防止被发现&#xff0c;你不能偷相邻的两家&#xff0c;即&#xff0c;如果偷了第一家&#xff0c;就不能再偷第二家&#…

离线和实时

离线和实时 一、数仓基本概念 1. 数据仓库架构 我们在谈数仓之前&#xff0c;为了让大家有直观的认识&#xff0c;先来谈数仓架构&#xff0c;“架构”是什么&#xff1f;这个问题从来就没有一个准确的答案。这里我们引用一段话&#xff1a;在软件行业&#xff0c;一种被普遍…

8种将pdf转化成excel的方法,亲测实用又有效!

PDF 到 Excel 的在线或离线转换工具可帮助您将原始或扫描的 PDF 文件转换为 Excel 格式。将 PDF 转换为 Excel 主要是为了获得可编辑的 Excel 文件或满足其他目标&#xff1b; 通过消除容易出错的手动复制粘贴来保持数据准确性。在需要使用 Excel 格式的大量 PDF 数据时节省时…

药物临床试验数据分析(靶点|适应症|企业|登记信息)

临床试验相关工作者在对药物进行系统性研究时都需要对药物做临床试验&#xff0c;且在对药物进行临床试验前和临床试验期间都需要对相关药物临床试验数据信息进行全面的分析及了解&#xff0c;有助于目标药物临床试验的顺利开展。药物临床试验数据覆盖非常宽泛&#xff0c;包含…

【进阶C语言】自定义类型——结构体+枚举+联合体

文章目录一.结构体1.内存对齐存在的原因规则举例2.位段二.枚举定义枚举的优点三.联合体定义特点内存计算一.结构体 1.内存对齐 存在的原因 平台原因(移植原因)&#xff1a; 不是所有的硬件平台都能访问任意地址上的任意数据的&#xff1b;某些硬件平台只能在某些地址处取某些…

【PHPWord】使用PHPWord自动生成TOC根据内容的目录完整示例 | table of contents (TOC)

目录 一、什么是Word中的目录二、目录的生成在Word中是如何操作的三、PHPWord中目录的生成1. 插入目录2.添加页码3.修改目录的字体样式4.修改目录的目录样式5.修改生成目录的标题等级四、完整示例代码和效果图一、什么是Word中的目录 在我们日常使用中,经常需要在文档中插入目…

微信小程序项目实例——心情记事本

微信小程序项目实例——心情记事本 文章目录微信小程序项目实例——心情记事本一、项目展示二、首页三、效果图文末项目代码见文字底部&#xff0c;点赞关注有惊喜 一、项目展示 心情记事本是一款可以记录当前心情和生活的记事本 用户可以选择当前的心情&#xff08;开心、平淡…

自己写一个简单的工作流引擎V1

1.需求 市面上常见的工作流组件一般都是前端通过拖拉拽配置流程图&#xff0c;后端流程引擎解析流程配置&#xff0c;这里我们手写一个简单的流程引擎&#xff0c;先实现串行流程&#xff0c;例如下&#xff1a; 小明提交了一个申请单&#xff0c;然后经过经理审批&#xff0…

【学习】Meta Learning、

文章目录一、Meta Learning什么是元学习&#xff1f;元学习–第1步元学习–第2步元学习–步骤3架构ML和Meta回顾GD学习好的初始化参数学习学习率NAS寻找网络结构data augmentationSample ReweightingFew-shot Image Classification元学习与自我监督学习元学习和知识蒸馏元学习和…

语音识别综述

语音识别的基本单位 Phoneme&#xff1a; 音位&#xff0c;音素 a unit of sound 是声音的最基本单位**&#xff0c;每个词语token的声音由多个 phoneme 组成** Grapheme&#xff08;字位&#xff09; smallest unot of a writing system 每个单词书写最基本的单位&#xff…