Java 链表与LinkedList

news2025/1/10 20:52:42
  1. 链表的组合形式
    ①有头结点、无头结点
    ②单向链表、双向链表
    ③循环链表、非循环链表
    根据自由组合,可以得到8种不同形式的链表,那么在刷题种常碰到的是不带有头结点的单向非循环链表不带头结点的双向非循环链表

  2. 模拟实现不带头结点的单向非循环链表的操作

public class MySingleLinkedList {
    //无头单向非循环链表的实现
    static class ListNode {
        int val;  //数值域
        ListNode next; //指向下一结点

        public ListNode(int val) {
            this.val = val;
        }
    }


    public ListNode head; //记录链表的头


    public void createNode() {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(3);
        ListNode listNode3 = new ListNode(5);
        ListNode listNode4 = new ListNode(7);
        listNode1.next = listNode2;
        listNode2.next = listNode3;
        listNode3.next = listNode4;

        head = listNode1;
    }
    //头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data); //实例化这个结点
        if (head == null) {
            head = node;
        }
        //链表不为空的时候
        node.next = head;
        head = node;
    }
    //尾插法
    public void addLast(int data){
        ListNode node = new ListNode(data); //实例化这个结点
        if (head == null) {
            head = node;
        }
        //找到尾结点
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }//此时cur指向的就是尾结点
        cur.next = node;

    }
    //任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if (index < 0 || index > size()) {
            //抛异常
            throw new IndexOutException("插入下标不合法");
        }
        if (index == 0) {
            //头插
            addFirst(data);
        }
        if (index == size()) {
            //尾插
            addLast(data);
        }
        //中间插
        ListNode cur = head;
        while (index-1 > 0) {
            cur = cur.next;
            index--;
        }//此时cur是要插入的前一个结点
        ListNode node = new ListNode(data); //实例化这个结点
        node.next = cur.next;
        cur.next = node;
    }
    //查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        if (head == null) {
            return false;
        }
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
    //删除第一次出现关键字为key的节点
    public void remove(int key){
        if (head == null) {
            System.out.println("删除失败");
            return;
        }
        if (head.val == key) {
            head = head.next;
            return;
        }
        ListNode cur = head;
        while (cur.next != null) {
            if (cur.next.val == key) {
                cur.next = cur.next.next;
                return;
            }else {
                cur = cur.next;
            }
        }
    }
    //删除所有值为key的节点
    public void removeAllKey(int key){
        if (head == null) {
            System.out.println("删除失败");
            return;
        }
        while (head.val == key) {
            head = head.next;
        }
        ListNode curPre = head;
        ListNode cur = head.next;
        while (cur != null) {
            if (cur.val == key) {
                curPre.next = cur.next;
                cur = cur.next;
            }else {
                curPre = curPre.next;
                cur = cur.next;
            }
        }
    }
    //得到单链表的长度
    public int size(){
        if (head == null) {
            return -1;
        }
        ListNode cur = head; //为了让头结点不发生改变
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }
    public void clear() {
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = null;
            cur = curNext;
        }
        head = null;
    }
    public void display() {
        ListNode cur = head; //为了让头结点不发生改变
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

}

分析:
在这里插入图片描述

  1. 模拟实现不带头结点的单向非循环链表的操作(LinkedList)
public class MyLinkedList {
    //模拟双向链表
    static class ListNode {
        int val;  //数值域
        ListNode next; //指向下一结点
        ListNode prev; //指向上一结点

        public ListNode(int val) {
            this.val = val;
        }
    }
    public ListNode head; //头结点
    public ListNode last; //尾结点
    //创建结点
    public void createNode() {
        ListNode listNode1 = new ListNode(1);
        ListNode listNode2 = new ListNode(3);
        ListNode listNode3 = new ListNode(5);
        ListNode listNode4 = new ListNode(7);
        listNode1.next = listNode2;
        listNode2.prev = listNode1;
        listNode2.next = listNode3;
        listNode3.prev = listNode2;
        listNode3.next = listNode4;
        listNode4.prev = listNode3;
        head = listNode1;
        last = listNode4;
    }
//头插法
    public void addFirst(int data){
        ListNode node = new ListNode(data);
        if (head == null) {
            head = node;
            last = node;
        }else{
            node.next = head;
            head = node;
        }

    }
//尾插法
    public void addLast(int data){
        ListNode node = new ListNode(data);
        if (last == null ) {
            head = node;
            last = node;
        }else {
            last.next = node;
            last = node;
        }

    }
//任意位置插入,第一个数据节点为0号下标
    public void addIndex(int index,int data){
        if (index < 0 || index > size()) {
            throw new IndexOutException("下标不合法");
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        ListNode cur = head;
        ListNode node = new ListNode(data);
        //找到要插入结点的前一个结点
        while (index-1 > 0) {
            cur = cur.next;
            index--;
        }
        node.next = cur.next;
        cur.next = node;
        node.next.prev = node;
        node.prev = cur;
    }
//查找是否包含关键字key是否在单链表当中
    public boolean contains(int key){
        ListNode cur = head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }
//删除第一次出现关键字为key的节点
    public void remove(int key){
        if (head == null) {
            return;
        }
        if (head.val == key) {
            if (head == last) {
                head = null;
                last = null;
                return;
            }else {
                head = head.next;
                head.prev = null;
                return;
            }
        }
        if (last.val == key) {
            if (head == last) {
                head = null;
                last = null;
                return;
            }else {
                last = last.prev;
                last.next = null;
                return;
            }
        }
        //要删的在中间
        ListNode cur = head;
        ListNode curNext = head.next;
        while (curNext != null) {
            if (curNext.val == key) {
                cur.next = curNext.next;
                curNext.next.prev = cur;
                return;
            }else {
                cur = cur.next;
                curNext = curNext.next;
            }
        }

    }
//删除所有值为key的节点
    public void removeAllKey(int key){
        ListNode cur = head;
        while (cur != null) {
            if(cur.val == key) {
                //判断当前是不是头节点
                if(cur == head) {
                    head = head.next;
                    if(head != null) {
                        head.prev = null;//一个节点
                    }
                }else {
                    //中间和尾巴的情况
                    cur.prev.next = cur.next;
                    if(cur.next != null) {
                        cur.next.prev = cur.prev;
                    }else {
                        last = last.prev;
                    }
                }
                cur = cur.next;
            }else {
                cur = cur.next;
            }
        }
    }
//得到单链表的长度
    public int size(){
        int count = 0;
        ListNode cur = head;
        while (cur != null) {
            cur = cur.next;
            count ++;
        }
        return count;
    }
    public void display(){
        ListNode cur = head;
        while (cur != null) {
            System.out.print(cur.val +" ");
            cur = cur.next;
        }
        System.out.println();
    }
    public void clear(){
        ListNode cur = head;
        while (cur != null) {
            ListNode curNext = cur.next;
            cur.next = null;
            cur.prev = null;
            cur = curNext;
        }
        head = null;
        last = null;
    }
}
  1. 关于LinkedList的使用
    LinkdeList实际上是一个双向的无头结点的非循环链表
    其构造方法有2种
        List<Integer> list = new ArrayList<>();
        list.add(1);
        LinkedList<Integer> list1 = new LinkedList<>();
        list1.add(6);
        LinkedList<Integer> list2 = new LinkedList<>(list);
        System.out.println(list1);
        System.out.println(list2);

①第一种是无参构造
②第二种是带参数构造,传入一个其他集合容器种的元素

  1. LinkedList的遍历
        LinkedList<Integer> list = new LinkedList<>();
        list.add(1);
        list.add(2);
        list.add(3);

①sout直接输出(必然重写例如toString)

        System.out.println(list);

②for-each

        for (int x: list) {
            System.out.println(x);
        }

③迭代器

        ListIterator<Integer> iterator =  list.listIterator();
        while (iterator.hasNext()) {
            System.out.print(iterator.next());
        }
        //逆序
        ListIterator<Integer> iterator1 =  list.listIterator(list.size());
        while (iterator1.hasPrevious()) {
            System.out.print(iterator1.previous());
        }
  1. 关于链表和顺序表的区别
    ①存储空间上:顺序表逻辑上相邻物理位置上也一定相邻;链表逻辑上相邻,但是物理位置上不一定相邻
    ②随机访问:顺序表可以随机访问,而链表需要从头到尾遍历访问
    ③插入删除效率:顺序表插入和删除需要移动大量的元素,但是链表不需要

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

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

相关文章

Notes可以手动签名了

大家好&#xff0c;才是真的好。 Notes/Domino 12.0.2陆续有人下载测试了&#xff0c;关于Notes的新功能中&#xff0c;我们上一篇也介绍到了可以手动签名。 字面上的意思&#xff0c;就是你可以调出手写板&#xff0c;然后使用触屏或鼠标来进行签名&#xff0c;可以在Nomad …

javaEE 初阶 — 定时器

文章目录定时器1 什么是定时器2 标准库中定时器3 实现一个定时器3.1 实现的思路3.2 为什么要使用优先级队列来保存任务3.3 开始实现定时器 1 什么是定时器 定时器 类似于一个 “闹钟”&#xff0c;达到一个设定的时间之后&#xff0c;就执行某个指定好的代码。 定时器是一种实…

印染行业APS智能排程排产的应用意义

不得不说的印染之“痛” 在印染行业&#xff0c;因排产无法自动化、智能化&#xff0c;企业在交期、成本、生产管理方面承受着巨大的压力&#xff0c;尤其当下印染企业生产管理正从传统的粗放式转向精细化&#xff0c;这些痛点愈加凸显。 一方面&#xff0c;客户和企业面临一个…

httpd安装

一、离线安装 1、去 https://pkgs.org/ 下载httpd所依赖的7个rpm包 [基于CentOS 7 x86_64系统&#xff0c;如需其他环境可前往官网直接下载] apr-1.4.8-5.el7.x86_64.rpm apr-util-1.5.2-6.el7.x86_64.rpm apr-util-ldap-1.5.2-6.el7.x86_64.rpm postgresql-libs-9.2.24-1.el…

互联互通-标准化成熟度指标分析(未完成)

整体分析1 医疗机构基本情况2 数据资源标准化建设情况&#xff08;30 分&#xff09;2.1数据集标准化情况&#xff08;15 分&#xff09;2.1.1电子病历基本数据集 第1部分&#xff1a;病历概要&#xff08;1-4数据集&#xff09;2.1.2电子病历基本数据集 第2部分&#xff1a;门…

Jetpack Compose UI创建布局绘制流程+原理 —— 内含概念详解(手撕源码)

本文是我去年首发于稀土掘金平台的文章 全文较长&#xff1a;共1万5千字&#xff0c;适合有耐心❤️的人学习 有些概念不懂的可以去4.部分概念详解这个目录先稍微学习一下 Compose源码基于最新的Compose 版本&#xff1a;1.0.1 系统源码基于最新的Android11 版本 注意&#xff…

【蓝桥杯基础题】2020年省赛填空题—回文日期

&#x1f451;专栏内容&#xff1a;蓝桥杯刷题⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录一、题目背景二、题目描述1.问题描述2.输入格式3.输出格式4.一个例子5. 评测用例规模与约定三、题目分析1.获取位数2.回文…

236页10万字精选数据中台建设方案2022版

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 目录 1. 数据中台平台建设方案 …

数据存储大小端 网络字节序

一、概念 大端模式&#xff1a;数据的低位存放在内存的高地址中 小端模式&#xff1a;数据的低位存放在内存的低地址中 二、数据的高低位 首先需要清楚一段数据存储高低位区分 联想记忆最右边为16^0 下来16^1 比如下图二进制为例&#xff1a; 三、内存的高低位 以vs2019为…

JVM知识体系学习四:排序规范(happens-before原则)、对象创建过程、对象的内存中存储布局、对象的大小、对象头内容、对象如何定位、对象如何分配

文章目录前言一、排序规范1、happens-before原则2、找文档位置二、对象创建的过程&#xff08;后面回答的就是这几个问题&#xff09;1、一线互联网企业面试题&#xff1a; 关于对象2、对象创建过程三、对象在内存中的存储布局1、1.8版本虚拟机配置2、对象的内存布局a、普通对象…

字节三面:如何设计一个高并发系统

前言 大家好&#xff0c;我是田螺。 记得很久之前&#xff0c;去面试过字节跳动。被三面的面试官问了一道场景设计题目&#xff1a;如何设计一个高并发系统。当时我回答得比较粗糙&#xff0c;最近回想起来&#xff0c;所以整理了设计高并发系统的15个锦囊&#xff0c;相信大…

【EHub_tx1_tx2_E100】Ubuntu18.04 + ROS_ Melodic + 万集716 单线激光 测试

简介&#xff1a;介绍 万集716 单线激光 在EHub_tx1_tx2_E100载板&#xff0c;TX1核心模块环境&#xff08;Ubuntu18.04&#xff09;下测试ROS驱动&#xff0c;打开使用RVIZ 查看点云数据&#xff0c;本文的前提条件是你的TX1里已经安装了ROS版本&#xff1a;Melodic。关于测试…

三、k8s资源管理

文章目录1 k8s资源管理介绍2 YAML语言介绍3 资源管理方式3.1 命令式对象管理3.2 命令式对象配置3.3 声明式对象配置3.4 如何编写YAML1 k8s资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 kubernetes的本质…

MySQL字符集和排序规则详解

一. 相关概念1. 字符集MySQL提供了多种字符集和排序规则选择&#xff0c;其中字符集设置和数据存储以及客户端与MySQL实例的交互相关&#xff0c;排序规则和字符串的对比规则相关(1). 字符集的设置可以在MySQL实例、数据库、表、列四个级别(2). MySQL设置字符集支持在InnoDB, M…

Git学习:工作流学习实践

文章目录一、前言二、开发过程一、前言 在实践的项目开发过程中&#xff0c;会使用Git或者类似的版本控制工具来管理代码。下面介绍基于Git工具在实际项目开发过程中的使用流程。 如上图所示显示了项目开发的一个简化流程。在开发一个新需求/版本的时候&#xff0c;一般会从主…

筛法求欧拉函数

欧拉函数的定义 在数论中&#xff0c;对正整数n&#xff0c;欧拉函数是小于n的正整数中与n互质的数的数目. 欧拉函数的重要性质 若(即m与n互质)&#xff0c;则若为质数&#xff0c;则若为质数&#xff0c;则对于性质2&#xff0c;若为质数&#xff0c;则小于的个数都互质&am…

北大陈斌Python算法笔记(二)

前言 &#x1f340;作者简介&#xff1a;被吉师散养、喜欢前端、学过后端、练过CTF、玩过DOS、不喜欢java的不知名学生。 &#x1f341;个人主页&#xff1a;红中 &#x1f342;不就是蓝桥杯嘛&#xff0c;干他&#xff01;&#xff01;我堂堂 栈的应用&#xff1a;简单括号匹…

docker安装nginx与容器之间的互相通信

目录 1. docker网络模式 2. 连接容器的三种方法 3. Docker Networking 3.1 创建网络 3.2 查看宿主机中创建的网络 3.3 删除网络 3.4 如何使用网络 4.搭建Nginx 1.准备工作 1.1 拉取镜像 ​编辑1.2 在宿主机中创建挂载目录 2.准备2个tomcat 容器集群 3.准备 Nginx配…

力扣(LeetCode)1658. 将 x 减到 0 的最小操作数(C++/Python)

题目描述 逆向思维滑动窗口 题目分析 &#xff1a; 从数组左侧和右侧&#xff0c;取出左侧的连续数字&#xff0c;右侧的连续数字&#xff0c;使得这些数字之和等于 x&#xff0c;维护最小取数次数&#xff0c;作为答案 。 设整个数组之和 total &#xff0c;除去左侧和右侧的…

Notes 12.0.2版本新特性

大家好&#xff0c;才是真的好。 随着上周代号多瑙河的Notes/Domino 12.0.2版本正式发布&#xff0c;很多人在周末加班&#xff0c;写新特性和功能测试文档等&#xff0c;恩&#xff0c;我也是这样&#xff0c;所以今天第一时间来介绍下Notes 12.0.2客户机新特性。 从12.0.2版…