【数据结构与算法】2、链表(简单模拟 Java 中的 LinkedList 集合,反转链表面试题)

news2024/10/7 18:28:47

目录

  • 一、链表基本概念和基本代码实现
  • 二、链表、动态数组整合(面向接口编程)
  • 三、clear()
  • 四、add(int index, E element)
    • (1) 找到 index 位置的节点
    • (2) get(int index) 和 set(int index, E element)
    • (3) add(int index, E element)
  • 五、remove(int index)
  • 六、indexOf(E element)
  • 七、三个 Leetcode 的练习题
    • (1) 删除链表中的节点
    • (2) 反转一个链表
      • ① 递归反转一个链表
      • ② 迭代反转一个链表
    • (3) 判断一个链表是否有环(快慢指针)

一、链表基本概念和基本代码实现

🍃 动态数组有个明显的缺点:可能会造成内存空间的大量浪费
🍃 能否用到多少就申请多少内存:链表可以办到

🍃 链表是一种链式存储的线性表,所有元素的内存地址不一定连续

在这里插入图片描述


在这里插入图片描述

🍀 链表(LinkedList)中有 size 属性【记录着链表中元素的个数、节点的个数)
🍀 链表中的 first 被称作头指针【它引用着链表中的第一个节点(头节点)】

🍀 链表中的元素是存储在Node 节点中的,一个Node 节点可被简单看作是一个元素
🍀 Node 也是一个类
🍀 Node 节点中的 element 属性是该 Node 节点 存储的数据
🍀 Node 节点中的 next 属性引用着下一个节点(next 存储着下一个节点的内存地址)
🍀 尾节点的 next 属性不存储任何内容(① 引用着 null;② 指向 null)

public class LinkedList<E> {
    private int size;

    // 头指针
    private Node<E> first;

    /**
     * 每一个节点就是 Node 类的一个实例
     */
    private static class Node<E> {
        E element;
        Node<E> next;

        public Node(E element, Node<E> next) {
            this.element = element;
            this.next = next;
        }
    }
}

二、链表、动态数组整合(面向接口编程)

在这里插入图片描述

🧡 ArrayListLinkedList 继承(extends)抽象类 AbstractList
🧡 抽象类 AbstractList 抽取 ArrayList 和 LinkedList 的公共代码,并实现(implements)了 List 接口
🧡 List 接口定义了 LinkedList 和 ArrayList 要实现的全部代码

三、clear()

在这里插入图片描述

🧡 没有被引用的对象会被 Java 的垃圾回收器自动回收

   public void clear() {
       size = 0;
       first = null;
   }

四、add(int index, E element)

在这里插入图片描述

🌼 要往 index 位置插入元素
🌼 找到 index - 1 位置的节点(记作:prev
🌼 让新节点(记作:newNode)的 next 指向 prev.next(是新节点的下一个节点)
🌼 让 prev 的 next 指针指向新节点(记作:newNode
🌼 size++

在这里插入图片描述

(1) 找到 index 位置的节点

在这里插入图片描述

☃️ 要找 0 号位置的节点【first 头指针指向的就是 0 号位置的节点】
☃️ 要找 1 号位置的节点【first 头指针的 next 指向的就是 1 号位置的节点】
☃️ 要找 2 号位置的节点【first 头指针的 next 的 next 指向的就是 2 号位置的节点】
☃️ 要找0号位置的节点是0次 next,要找1号位置的节点是1次 next,要找2号位置的节点是2次 next,要找 index 位置的节点是 index 次 next

    /**
     * 返回 index 位置的节点
     */
    private Node<E> node(int index) {
        rangeCheck(index);

        // 从头节点开始(默认指向头节点)
        Node<E> moveNode = first;

        for (int i = 0; i < index; i++) {
            moveNode = moveNode.next;
        }

        return moveNode;
    }

(2) get(int index) 和 set(int index, E element)

🌴 因为 node() 方法返回了 index 位置的节点,所以 get(int index) 方法(返回 index 位置的元素 ) 方法也得以实现
🌴 因为 node() 方法返回了 index 位置的节点,所以 set(int index, E element) 方法(设置 index 位置的元素为 element ) 方法也得以实现

    @Override
    public E get(int index) {
        Node<E> node = node(index);
        return node.element;
    }
    @Override
    public E set(int index, E element) {
        Node<E> node = node(index);
        E old = node.element;
        
        node.element = element;
        return old;
    }

(3) add(int index, E element)

🍀 编写链表代码过程中,要注意边界测试
🍀 比如 index 为 0size – 0size

    @Override
    public void add(int index, E element) {
        if (index == 0) { // 把元素插入到头节点的位置
            first = new Node<>(element, first);
        } else {
            // 拿到【index - 1】位置的节点
            Node<E> prev = node(index - 1);

            prev.next = new Node<>(element, prev.next);
        }

        size++;
    }

五、remove(int index)

在这里插入图片描述

    @Override
    public E remove(int index) {
        Node<E> node = first;

        if (index == 0) { // 删除头节点
            first = node.next;
        } else {
            Node<E> prev = node(index - 1);
            node = prev.next;

            prev.next = node.next;
        }

        size--;

        return node.element;
    }

🌴 注意 index 等于 0 的时候

六、indexOf(E element)

🌴 遍历整个链表,取值比较

    @Override
    public int indexOf(E element) {
        Node<E> moveNode = first;

        if (element == null) {
            for (int i = 0; i < size; i++) {
                if (null == moveNode.element) return i;
                moveNode = moveNode.next;
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (element.equals(moveNode.element)) return i;
                moveNode = moveNode.next;
            }
        }

        return ELEMENT_NOT_FOUND;
    }

七、三个 Leetcode 的练习题

(1) 删除链表中的节点

题目地址:https://leetcode.cn/problems/delete-node-in-a-linked-list/

在这里插入图片描述
在这里插入图片描述

🌼有一个单链表的 head,我们想删除它其中的一个节点 node
🌼 给你一个需要删除的节点 node
🌼 你无法访问第一个节点 head

🌼 链表的所有值都是唯一的
🌼 给定的节点 node 不是链表中的最后一个节点

🌼 删除节点并不是指从内存中删除它

而是:
① 给定节点的值不应该存在于链表中
② 链表中的节点数应该减少 1
node 前面的所有值顺序相同
node 后面的所有值顺序相同

在这里插入图片描述


在这里插入图片描述


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

🍃 用要被删除的节点(delNode)的下一个节点的值(delNode.next.val)覆盖 delNode 的值
🍃 delNode 的 next 指向 delNode 的 next 的 next

(2) 反转一个链表

https://leetcode-cn.com/problems/reverse-linked-list/

在这里插入图片描述

在这里插入图片描述

① 递归反转一个链表

在这里插入图片描述

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) return head;

        ListNode newHead = reverseList(head.next);

        head.next.next = head;
        head.next = null;

        return newHead;
    }
}

② 迭代反转一个链表

在这里插入图片描述
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) return head;

        ListNode newHead = null;

        while (head != null) {
            ListNode tmp = head.next;

            head.next = newHead;
            newHead = head;
            head = tmp;
        }

        return newHead;
    }
}

(3) 判断一个链表是否有环(快慢指针)

https://leetcode.cn/problems/linked-list-cycle/

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) return false;

        ListNode slow = head;
        ListNode fast = head.next;

        while (slow != fast) {
            if (fast == null || fast.next == null) return false;

            slow = slow.next;
            fast = fast.next.next;
        }

        return true;
    }
}

完整代码:https://gitee.com/zgq666good/datastructureandalgorithm.git

如有错误请不吝赐教

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

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

相关文章

基于Java+Swing+Socket实现中国象棋-网络版

基于JavaSwingSocket实现中国象棋-网络版 一、系统介绍二、功能展示1.系统登陆2.选择黑色方进行对局3.整体页面4、保存棋谱5、认输 三、其他系统四、获取源码 前言 中国象棋是起源于中国的一种棋&#xff0c;属于二人对抗性游戏的一种&#xff0c;在中国有着悠久的历史。由于用…

员工管理业务开发 -- 手把手教你做ssm+springboot入门后端项目黑马程序员瑞吉外卖(三)

文章目录 前言六、员工管理业务开发1.开发功能预览2.新增员工功能1&#xff09;需求分析2&#xff09;数据模型&#xff08;表&#xff09;3&#xff09;代码开发4&#xff09;功能测试5&#xff09;编写全局异常处理器 3.员工信息分页查询1&#xff09;需求分析2&#xff09;代…

VS Code的下载安装,及其简单使用

目录 前言 一.下载 二.安装 三.VS Code的插件安装 &#x1f496;插件正常安装 &#x1f496;插件安装异常 四.VS Code的配置 五.VS Code的基本使用 总结 &#x1f381;个人主页&#xff1a;tq02的博客_CSDN博客-C语言,Java领域博主 &#x1f3a5; 本文由 tq02 原创&#…

Redis 分布式锁实现

Redis 分布式锁 分布式锁&#xff1a;满足分布式系统或集群模式下多进程可见并且互斥的锁 特点&#xff1a; 多线程可见互斥高可用高性能&#xff08;高并发&#xff09;安全性、可重入性、重试机制、锁超时自动续期等 … 加锁之后&#xff0c;对整个分布式集群都有效 基于…

多线程之常用线程安全类型分析

写在前面 本文一起看下在日常工作中我们经常用到的线程安全的数据类型&#xff0c;以及一些经验总结。 1&#xff1a;常用线程安全数据类型 1.1&#xff1a;jdk集合数据类型 jdk的集合数据类型分为两类&#xff0c;一种是线性数据结构&#xff0c;另外一种是字典结构&#…

【系统架构】第五章-软件工程基础知识(一)

软考-系统架构设计师知识点提炼-系统架构设计师教程&#xff08;第2版&#xff09; 软件工程 一、软件过程模型 1、瀑布模型 特点&#xff1a;前一个阶段工作的输出结果&#xff0c;是后一个阶段工作的输入 缺点&#xff1a; 软件需求的完整性、正确性等很难确定&#xff0c…

人力资源外包系统(社会实践管理系统)需求分析文档

该系统主要针对当前在校大学生、中专院校学生寒、暑假社会实践而设计的管理系统&#xff1b; 主要用户群为人力资源外包公司&#xff0c;也可以是各个学校管理学生使用&#xff1b; 主要功能有维护企业信息&#xff0c;招工信息&#xff0c;企业宣传资料&#xff1b;维护学校…

基于JavaSpringBoot+uniapp制作一个记账小程序

你不理财,财不理你,制作一个记账小程序对自己的收入/支出明细进行管理,守护好自己的钱袋子。 一、小程序1.1 项目创建1.2 首页1.3 收支报表页1.4 记账提交页1.5 记账列表页

NCI Core Framework

3.1 概述 NCI 核心包括以下必需的功能&#xff1a;  通过 NCI 传输命令、响应、通知和数据消息的数据包格式。  用于设备主机和 NFC 控制器之间不同操作&#xff08;第 4 节中指定&#xff09;的命令、响应和通知的定义。 &#xff08;本规范后面的一些部分定义了不属于…

一起学SF框架系列4.7-模块context-MessageResource

Spring通过MessageSource接口提供了国际化&#xff08;“i18n”&#xff09;功能。搞明白MessageResource相关接口和类&#xff0c;基本就掌握了国际化功能。 MessageSource接口 定义了消息访问接口。 String getMessage&#xff08;String code&#xff0c;Object[]args&…

全网唯一!Matlab原神配色包MGenshin

前段时间&#xff0c;在原神官网逛了一圈&#xff0c;发现里面角色的原画配色十分的好看&#xff0c;便突发奇想&#xff1a;要是把原神配色用在SCI论文插图上&#xff0c;emmmmm…… 于是&#xff0c;我默默打开了自己的Matlab&#xff0c;用TheColor工具箱的图片主题色提取功…

数据驱动的商业决策:BI在企业中的重要性

第一章&#xff1a;引言 在当今数字化时代&#xff0c;数据被广泛应用于各个行业和领域。对企业而言&#xff0c;数据是一项宝贵的资源&#xff0c;可以为其带来无限的商机和竞争优势。然而&#xff0c;海量的数据本身并不具备实际意义&#xff0c;只有通过有效的数据分析和洞…

亚马逊云科技中国峰会:Amazon DeepRacer-梦想加速度

零&#xff1a;前言 你是否憧憬在赛车赛道上开车&#xff0c;享受疾驰而过的感觉&#xff0c;感受无与伦比的驾驶乐趣&#xff1f; Amazon DeepRacer可以满足你的梦想&#xff0c;虚竹哥带你了解Amazon DeepRacer。 它为用户提供了一个虚拟仿真环境和一个真实赛车模型&#xf…

【JDK环境配置】| 两种JDK环境能在同一台电脑共存吗?(文末送书)

目录 &#x1f981; 前言&#x1f981; 基础环境&#x1f981; 安装JDK1.8Ⅰ. 下载Ⅱ. 安装 &#x1f981; 在项目里更改JDK版本---------------------------------------------福利在下面--------------------------------------------------&#x1f981; 福利&#xff08;送…

《基于同态加密和秘密分享的纵向联邦LR协议研究》论文阅读

论文地址&#xff1a;https://xueshu.baidu.com/usercenter/paper/show?paperid1b7e04e0r41x0ax0976q0gy0m5242465 摘要 提出了一种新颖的两方纵向联邦逻辑回归协议,并在半诚实安全模型下证明了该协议的安全性, 包括模型训练流程和模型推理流程的安全性,且无需对非线性函数使…

C++四种基本类型转换

C四种基本类型转换 1.static_cast2.const_cast3.reinterpret_cast4 .dynamic_cast 1.static_cast 用法: static_cast<type_name> (expression) 说明:该运算符把expression转换为typen_name类型&#xff0c;static_cast在编译时使用类型信息执行转换,在转换执行必要的检测…

spring事务源码详解-spring原码(一)

前面说过了aop源码&#xff0c;这里再稍微回顾一下 我们会用注解EnableAspectJautoProxy开启aop 当我们用了proxytargetClass会强制cglib动态代理 源码里有Import 里面会注册AnnotionAwareAspectJAutoProxyCreator 后面会在beanDefinationMap获取到所有定义的Objects循环 …

2020新基建决赛-crypto-onepiece

onepiece 一、概要 1、标题&#xff1a;onepiece 2、关键字&#xff1a;e2&#xff0c;rabin&#xff0c;凯撒 3、比赛&#xff1a;2020新基建决赛 4、工具&#xff1a;python&#xff0c;米斯特工具 二、开始 1、题目分析 题目给了一个pubkey.pem和onepiece.enc&#xff…

C++右值引用 移动语义 完美转发 引用叠加

右值引用 MyString浅拷贝与深拷贝浅赋值与深赋值 左值与右值左值概念左值右值与函数的结合移动构造函数移动赋值函数移动构造和移动赋值的应用 移动语义 有点问题完美转发引用叠加 MyString 浅拷贝与深拷贝 s1先在堆区申请了空间&#xff0c;然后将p指针指向的字符串复制到该…

设计模式之责任链模式笔记

设计模式之责任链模式笔记 说明Chain of Responsibility(责任链)目录责任链模式示例类图请假条类抽象处理者类小组长类部门经理类总经理类测试类 说明 记录下学习设计模式-责任链模式的写法。JDK使用版本为1.8版本。 Chain of Responsibility(责任链) 意图:使多个对象都有机…