Java手写LinkedList和拓展

2023-10-27

Java手写LinkedList和拓展

思维导图

LinkedList
Node
add
get
remove
size

实现思路原理

  • 创建一个名为Node的内部类,用于表示链表中的节点。Node类应包含以下属性:

    • data:用于存储节点的数据元素。
    • prev:用于存储指向前一个节点的引用。
    • next:用于存储指向后一个节点的引用。
  • 创建一个名为LinkedList的类,用于表示链表。LinkedList类应包含以下属性:

    • head:用于存储链表的头节点的引用。
    • tail:用于存储链表的尾节点的引用。
    • size:用于存储链表中节点的数量。
  • 实现add方法,用于向链表中添加新的元素。该方法的实现步骤如下:

    • 创建一个新的Node对象,将要添加的数据元素作为参数传入。
    • 如果链表为空(即headnull),则将新节点设置为头节点和尾节点。
    • 否则,将新节点的prev引用设置为当前尾节点,将当前尾节点的next引用设置为新节点,并将新节点设置为新的尾节点。
    • 增加链表的大小。
  • 实现get方法,用于获取指定位置的元素。该方法的实现步骤如下:

    • 检查索引是否越界,如果越界则抛出IndexOutOfBoundsException异常。
    • 从头节点开始,遍历链表,直到找到指定位置的节点。
    • 返回该节点的数据元素。
  • 实现remove方法,用于删除指定位置的元素。该方法的实现步骤如下:

    • 检查索引是否越界,如果越界则抛出IndexOutOfBoundsException异常。
    • 从头节点开始,遍历链表,直到找到指定位置的节点。
    • 如果要删除的节点有前一个节点(即当前节点的prev不为null),则将前一个节点的next引用指向当前节点的下一个节点。
    • 否则,将头节点设置为当前节点的下一个节点。
    • 如果要删除的节点有后一个节点(即当前节点的next不为null),则将后一个节点的prev引用指向当前节点的前一个节点。
    • 否则,将尾节点设置为当前节点的前一个节点。
    • 减少链表的大小。
  • 实现size方法,用于获取链表的长度。该方法的实现步骤如下:

    • 直接返回链表的大小属性。

详细介绍和详细步骤

创建Node类

private class Node {
    private T data;
    private Node prev;
    private Node next;
    
    public Node(T data) {
        this.data = data;
        this.prev = null;
        this.next = null;
    }
}

Node类用于表示链表中的节点,包含数据元素data、指向前一个节点的引用prev和指向后一个节点的引用next。构造函数用于初始化节点的数据元素。

创建LinkedList类

public class LinkedList<T> {
    private Node head;
    private Node tail;
    private int size;
    
    // 构造函数
    public LinkedList() {
        this.head = null;
        this.tail = null;
        this.size = 0;
    }
    
    // 添加元素
    public void add(T element) {
        Node newNode = new Node(element);
        
        if (head == null) {
            head = newNode;
            tail = newNode;
        } else {
            newNode.prev = tail;
            tail.next = newNode;
            tail = newNode;
        }
        
        size++;
    }
    
    // 获取元素
    public T get(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index out of range");
        }
        
        Node current = head;
        for (int i = 0; i < index; i++) {
            current = current.next;
        }
        
        return current.data;
    }
    
    // 删除元素
    public void remove(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("Index out of range");
        }
        
        Node current = head;
        for (int i = 0; i < index; i++) {
            current = current.next;
        }
        
        if (current.prev != null) {
            current.prev.next = current.next;
        } else {
            head = current.next;
        }
        
        if (current.next != null) {
            current.next.prev = current.prev;
        } else {
            tail = current.prev;
        }
        
        size--;
    }
    
    // 获取链表长度
    public int size() {
        return size;
    }
}

LinkedList类用于表示链表,包含头节点head、尾节点tail和链表长度size属性。构造函数用于初始化链表。

add方法用于向链表中添加新的元素。首先创建一个新的Node对象,并将要添加的数据元素作为参数传入。然后根据链表是否为空,将新节点设置为头节点和尾节点,或者将新节点添加到尾节点的后面。最后增加链表的大小。

get方法用于获取指定位置的元素。首先检查索引是否越界,如果越界则抛出IndexOutOfBoundsException异常。然后从头节点开始遍历链表,直到找到指定位置的节点。最后返回该节点的数据元素。

remove方法用于删除指定位置的元素。首先检查索引是否越界,如果越界则抛出IndexOutOfBoundsException异常。然后从头节点开始遍历链表,直到找到指定位置的节点。如果要删除的节点有前一个节点,则将前一个节点的next引用指向当前节点的下一个节点;否则,将头节点设置为当前节点的下一个节点。如果要删除的节点有后一个节点,则将后一个节点的prev引用指向当前节点的前一个节点;否则,将尾节点设置为当前节点的前一个节点。最后减少链表的大小。

size方法用于获取链表的长度,直接返回链表的大小属性。

总结

通过手写LinkedList的实现,我们深入理解了链表的数据结构和原理,并且加深了对Java语言的熟悉程度。我们学习了如何创建链表、添加元素、获取元素、删除元素和获取链表长度的基本功能。通过实践,我们对链表的操作和链表节点的关系有了更深入的理解。

拓展

除了基本的添加、获取和删除功能,我们还可以对LinkedList进行一些拓展,例如:

  • 实现反转链表的功能,将链表中的节点顺序颠倒。
  • 实现查找链表中的环,并返回环的起始节点。
  • 实现合并两个有序链表的功能,将两个有序链表合并为一个有序链表。
    具体如下:

反转链表

public void reverse() {
    Node current = head;
    Node prev = null;
    
    while (current != null) {
        Node next = current.next;
        current.next = prev;
        prev = current;
        current = next;
    }
    
    tail = head;
    head = prev;
}

reverse方法用于将链表中的节点顺序颠倒。首先定义一个当前节点current和一个前一个节点prev,并将它们都初始化为null。然后使用一个循环,遍历链表中的每个节点。在循环中,首先将当前节点的下一个节点保存到一个临时变量next中,然后将当前节点的next引用指向前一个节点prev,然后将前一个节点prev更新为当前节点current,最后将当前节点current更新为下一个节点next。循环结束后,将尾节点tail更新为原来的头节点head,将头节点head更新为反转后的链表的头节点prev

查找链表中的环

public Node findCycle() {
    Node slow = head;
    Node fast = head;
    
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        
        if (slow == fast) {
            break;
        }
    }
    
    if (fast == null || fast.next == null) {
        return null;
    }
    
    slow = head;
    while (slow != fast) {
        slow = slow.next;
        fast = fast.next;
    }
    
    return slow;
}

findCycle方法用于查找链表中的环,并返回环的起始节点。首先定义一个慢指针slow和一个快指针fast,并将它们都初始化为头节点head。然后使用一个循环,慢指针每次移动一步,快指针每次移动两步,直到快指针追上慢指针或者快指针到达链表的末尾。如果快指针追上慢指针,则说明链表中存在环。在循环结束后,如果快指针为null或者快指针的下一个节点为null,则说明链表中不存在环,返回null。否则,将慢指针重新设置为头节点head,然后使用两个指针同时移动,每次移动一步,直到两个指针相遇。相遇的节点即为环的起始节点。

合并两个有序链表

public static LinkedList<Integer> merge(LinkedList<Integer> list1, LinkedList<Integer> list2) {
    LinkedList<Integer> mergedList = new LinkedList<>();
    
    Node node1 = list1.head;
    Node node2 = list2.head;
    
    while (node1 != null && node2 != null) {
        if (node1.data <= node2.data) {
            mergedList.add(node1.data);
            node1 = node1.next;
        } else {
            mergedList.add(node2.data);
            node2 = node2.next;
        }
    }
    
    while (node1 != null) {
        mergedList.add(node1.data);
        node1 = node1.next;
    }
    
    while (node2 != null) {
        mergedList.add(node2.data);
        node2 = node2.next;
    }
    
    return mergedList;
}

merge方法用于合并两个有序链表,并返回合并后的有序链表。首先创建一个新的空链表mergedList作为合并后的链表。然后使用两个指针node1node2分别指向两个链表的头节点。使用一个循环,比较node1node2指向的节点的数据元素大小,将较小的数据元素添加到mergedList中,并将对应的指针向后移动一步。循环结束后,如果链表list1还有剩余的节点,则将剩余的节点添加到mergedList中。如果链表list2还有剩余的节点,则将剩余的节点添加到mergedList中。最后返回合并后的链表mergedList

拓展总结

通过拓展部分的代码,我们实现了链表的反转、查找环和合并有序链表等功能。这些功能都是基于链表的基本操作进行实现的,通过实践我们不仅加深了对链表的理解,而且提高了编程能力。链表作为一种常用的数据结构,对于解决一些特定的问题非常有用,因此掌握链表的基本操作和常见的拓展功能对于编程能力的提升是非常有帮助的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java手写LinkedList和拓展 的相关文章

随机推荐

  • 抖音自动生成文字_文字动画怎么制作?这里教你一键制作抖音爆款文字视频

    现在很多人都会在闲暇时间打开抖音刷刷视频 经常会看到很多文字视频特别有趣 配上动感的节奏 文字立刻鲜活起来 如何才能制作出这样的文字视频呢 今天给大家介绍一种全网最简单的抖音文字视频制作方法 不需要会使用AE 甚至也不需要你打字 直接语音识
  • 关于python基础,90%的人不知道这些。但你一定得清楚。

    经过前几次的学习我们已经安装好Python解释器 搭建好顺手的IDE环境 那么接下来 我们就正式的开始一些列Python知识的学习 代码敲起来 一 字面量 字面量是以变量或常量给出的原始数据 在Python中 有多种类型的字面量 如数字字面
  • linux中断实验

    文章目录 一 linux中断简介 1 linux中断API函数 1 中断号 2 request irq函数 3 free irq 4 中断处理函数 5 中断使能与禁止函数 2 上半部与下半部 1 软中断 2 tasklet 3 工作队列 3
  • jboss源码中片段分析

    package com test import java security AccessController import java security PrivilegedAction import java util ArrayList
  • QRegExp

    d 非负整数 正整数 0 0 9 1 9 0 9 正整数 d 0 非正整数 负整数 0 0 9 1 9 0 9 负整数 d 整数 d d 非负浮点数 正浮点数 0 0 9 0 9 1 9 0 9 0 9 1 9 0 9 0 9 0 9 1
  • post使用方法以及有道API

    import requests import json headers User Agent Mozilla 5 0 Windows NT 10 0 Win64 x64 AppleWebKit 537 36 KHTML like Gecko
  • Unity人物前进的方向和相机朝向一致

    鼠标点击滑动移动相机 代码 using UnityEngine using System Collections This is an improved orbit script based on the MouseOrbitImprove
  • 数据结构-图的应用算法

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 一 最小生成树 1 1 Prim算法 1 2 Kruskal算法 二 最短路径 2 1 Dijkstra算法 2 2 Floyd算法 三 有向无环图描述表达式 四
  • Angular 使用MockJs

    今天要做模拟数据 但是发现没有说这个问题的帖子 特此记录分享一下 如果有用Angular的朋友刚好遇到这个问题 希望可以帮你解决 第一步 安装mockjs npm install mockjs save 第二步 引入mockjs 在 ang
  • Python学习笔记(十三)————循环语句相关

    目录 1 while循环 2 for循环 3 range语句 4 while与for区别 5 循环中断 break和continue 1 while循环 1 while的条件需得到布尔类型 True表示继续循环 False表示结束循环 2
  • 「OceanBase 4.1 体验」OceanBase 4.1社区版的部署及使用体验

    OceanBase 4 1 体验 OceanBase 4 1社区版的部署及使用体验 一 前言 1 1 本次实践介绍 1 2 本次实践目的 二 准备环境资源 2 1 部署前需准备工作 2 2 本地环境规划 三 部署Docker环境 3 1 安
  • 栈,堆,堆栈,队列

    堆栈都是一种数据项按序排列的数据结构 只能在一端 称为栈顶 top 对数据项进行插入和删除 要点 堆 顺序随意 栈 后进先出 Last In First Out 堆 什么是堆 又该怎么理解呢 堆通常是一个可以被看做一棵树的数组对象 堆总是满
  • ViewPager2 + SmartRefreshLayout + RecyclerView出现底部自动回弹显示问题,显示不全

    ViewPager2 SmartRefreshLayout RecyclerView出现底部自动回弹显示问题 显示不全 出现这个问题的原因是RecyclerView的高度超过了父控件的高度 我也不知道为啥 只是测试出来的结果 解决办法 pr
  • 【python基础知识】15.编码基础知识

    编码基础知识 前言 编码 二进制 编码表 encode 和decode 前言 在你的网络冲浪生涯里 我想你或多或少有这样的疑问 为什么传说中只能读懂0和1的计算机能显示如此五花八门的内容 为什么明明办的100兆的宽带 撑死就只有10几兆的下
  • ubuntu18.04 android studio无法使用中文输入法

    1 找到电脑安装的输入法框架 打开系统输入法 查看当前选择的输入法框架 这说明当前使用的是ibus 输入法框架 2 设置studio sh 使用输入法框架 在studio sh 的文件注释行下面 该文件的最前明 添加输入法 export X
  • iOS获取App ipa包 2019-02-12

    转自 https www jianshu com p 8eaa1dd20370 首先 去Mac上的App Store下载Apple Configurator 2 然后把iphone连接上Mac 点击Apple Configurator 2
  • 汽配企业WMS系统:提升作业效率与过程管控

    随着汽配企业竞争的加剧和业务模式的复杂化 许多企业意识到提高仓库作业效率和成本控制能力是企业成功的关键 因此 越来越多的企业选择引入WMS仓储管理系统 然而 汽配企业产品复杂 且从业的人员大部分是老一辈人员 内部信息化程度低 因此需要建立更
  • 代码随想录算法训练营第一天

    LeetCode704 力扣 基础二分法 考虑如何不让数据溢出 区间如何切换 LeetCode34 力扣寻找最左区间 和 最右区间 套路和基础二分法类似 就是要在找到target的时候继续向左或者向右移动 package algor tra
  • Matlab绘制折线图及局部放大图

    Matlab可完成折线图绘制及局部放大 需下载 MATLAB 交互式的局部放大图 知乎 代码开源 非常好用 十分感谢 需求 如下图所示 一 仅绘制折线图 代码如下 x 1 10 x轴上的数据 开始 终止值 a 12008 68032 171
  • Java手写LinkedList和拓展

    Java手写LinkedList和拓展 思维导图 mermaid svg K0RTlFFvnikDRvqp font family trebuchet ms verdana arial sans serif font size 16px f