Java中LinkedList原理代码解析

Java中LinkedList原理代码解析

介绍

Java中的LinkedList是一种双向链表数据结构,在实际开发中经常被使用。LinkedList实现了List和Deque接口,可以被用作列表或队列。本文将深入探究LinkedList的实现原理和相应的代码解析。

LinkedList实现原理

LinkedList的实现原理主要包括以下几点:

  1. 内部节点类

LinkedList实现了一个节点类Node用来存储元素以及前后指针信息,如下所示:

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
  1. 头节点和尾节点

LinkedList内部通过head存储头节点,通过tail存储尾节点。头节点和尾节点都是特殊的空节点,不存储元素。通过头节点和尾节点可以快速访问元素,如下所示:

    transient Node<E> first;
    transient Node<E> last;
  1. 元素数量

LinkedList内部通过一个整型变量size记录元素的数量,如下所示:

    transient int size = 0;
  1. 双向链表实现

LinkedList实现了List和Deque接口,因此是一种双向链表。双向链表的特点是节点除了存储后继节点的指针外,还存储前驱节点的指针,因此可以双向遍历链表。

LinkedList的主要方法

LinkedList内部实现了很多方法,其中最常用的几个方法包括:add、remove、get、set等。以下是这些方法的详细说明。

add方法

add方法有两个重载方法,可以添加元素到列表中的指定位置或列表尾部。默认添加到列表尾部。add方法的实现主要分为两种情况:

  1. 添加到列表末尾

添加到列表末尾时,会先新建一个节点类,并将新节点的prev指向尾节点last,将尾节点last的next指向新节点,将尾节点指向新节点,最后将元素数量size加1,如下所示:

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
    }
  1. 添加到指定位置

添加到指定位置时,会先判断插入的索引位置是否在列表头或者列表尾,若是,则直接调用linkFirst或linkLast方法,否则获取插入位置对应的节点,将新节点的prev指向插入位置节点的prev,插入位置节点的prev的next指向新节点,新节点的next指向插入位置节点,插入位置节点的prev指向新节点,最后将元素数量size加1,如下所示:

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

    void linkBefore(E e, Node<E> succ) {
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
    }

remove方法

remove方法有两个重载方法,可以删除列表中指定索引位置或指定元素。默认删除列表第一个匹配的元素。remove方法的实现主要分为两种情况:

  1. 删除指定索引位置的元素

删除指定索引位置的元素时,先获取要删除的节点,将要删除节点的前一个节点的next指向要删除的节点的next,将要删除节点的下一个节点的prev指向要删除的节点的prev,最后将要删除节点的prev和next置为null,元素数量size减1,如下所示:

    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }

    E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        return element;
    }
  1. 删除指定元素

删除指定元素时,先遍历列表找到第一个匹配的元素,然后将第一个匹配元素节点的prev的next指向第一个匹配元素节点的next,第一个匹配元素节点的next的prev指向第一个匹配元素节点的prev,最后将第一个匹配元素节点的prev和next置为null,元素数量size减1,如下所示:

    public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }

get方法

get方法有一个重载方法,用于获取列表中指定索引位置的元素。实现逻辑较为简单,先获取指定索引位置的节点信息,然后返回节点中存储的元素,如下所示:

    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

    Node<E> node(int index) {
        // 省略一些越界检查等逻辑
        if (index < (size >> 1)) {
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x;
        } else {
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

set方法

set方法有一个重载方法,用于将列表中指定索引位置的元素替换为指定元素。先获取指定索引位置的节点信息,然后将节点中存储的元素替换为指定元素并返回原来存储的元素,如下所示:

    public E set(int index, E element) {
        checkElementIndex(index);
        Node<E> x = node(index);
        E oldVal = x.item;
        x.item = element;
        return oldVal;
    }

示例说明

以下示例演示了如何使用LinkedList实现队列和栈两种数据结构。

1. 队列

队列是一种先进先出的数据结构,LinkedList可以被用作队列的实现。以下是一个自定义的Queue类的示例代码:

public class Queue<E> {
    private LinkedList<E> list = new LinkedList<>();

    public void enqueue(E e) {
        list.addLast(e);
    }

    public E dequeue() {
        return list.removeFirst();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public int size() {
        return list.size();
    }
}

2. 栈

栈是一种先进后出的数据结构,LinkedList可以被用作栈的实现。以下是一个自定义的Stack类的示例代码:

public class Stack<E> {
    private LinkedList<E> list = new LinkedList<>();

    public void push(E e) {
        list.addFirst(e);
    }

    public E pop() {
        return list.removeFirst();
    }

    public boolean isEmpty() {
        return list.isEmpty();
    }

    public int size() {
        return list.size();
    }
}

总结

本文介绍了Java中LinkedList的实现原理和相应的代码解析。LinkedList是一种双向链表数据结构,通过head存储头节点和tail存储尾节点,以及记录元素数量size来实现列表和队列。LinkedList内部实现了很多常用的方法,如add、remove、get、set等,可以方便地实现自定义的数据结构,如队列和栈等。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中LinkedList原理代码解析 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • qstring替换指定位置的字符

    QString替换指定位置的字符攻略 以下是QString替换指定位置的字符的完整攻略: 什么是QString? QString是Qt框架中的一个字符串类,它提供了一系列的字符串操作方法,例如字符串的拼接、查找、替换等。 步骤1:创建一个QString对象 首先,创建一个QString对象,用于存储替换的字符串。 QString str = "He…

    other 2023年5月6日
    00
  • PHP开发框架laravel代码提示示例解析

    PHP开发框架laravel代码提示示例解析 1. 什么是代码提示 代码提示是一种在编程过程中提供自动补全和建议的功能,用于提高开发效率和减少错误。在使用PHP开发框架laravel时,代码提示可以帮助开发者快速查找和使用框架内置的类、方法和属性,减少手动查阅文档的时间。 2. laravel框架代码提示配置 为了实现laravel框架的代码提示功能,我们需…

    other 2023年6月28日
    00
  • 原生JS实现H5转盘游戏的示例代码

    原生JS实现H5转盘游戏的示例代码攻略 介绍 在这个攻略中,我们将使用原生JavaScript来实现一个H5转盘游戏。转盘游戏是一种常见的抽奖游戏,玩家可以通过点击按钮来旋转转盘,并有机会获得不同的奖品。 步骤 步骤一:HTML结构 首先,我们需要创建一个HTML结构来容纳转盘游戏。以下是一个简单的HTML结构示例: <!DOCTYPE html&gt…

    other 2023年9月6日
    00
  • 手机QQ6.0体验版下载地址 手机QQ6.0苹果安卓用户报名地址

    手机QQ6.0体验版下载地址 手机QQ6.0体验版是一款最新的QQ版本,提供了更多的功能和改进。以下是获取手机QQ6.0体验版的详细攻略。 步骤一:报名参与体验 首先,你需要报名参与手机QQ6.0体验版的测试。请按照以下步骤进行: 打开手机QQ官方网站或者QQ官方应用。 在首页或者菜单中找到“体验版”或者“测试版”选项。 点击进入体验版页面。 在页面中找到“…

    other 2023年8月4日
    00
  • 怎么把保存图片做成qq表情包?收藏图片制作qq表情包详细图文教程

    怎么把保存图片做成qq表情包?收藏图片制作qq表情包详细图文教程 制作QQ表情包是让我们更好地在聊天中表达情感和分享心情,而将保存好的图片做成QQ表情包也是很常见的需求。下面将详细讲解如何将保存好的图片制作成QQ表情包。 步骤一:准备工作 选择并下载一个好用的QQ表情制作工具,例如“内部表情包转换工具”或“表情制作大师”等。 准备好需要制作成QQ表情的图片,…

    other 2023年6月26日
    00
  • Flutter组件生命周期和App生命周期示例解析

    下面是详细讲解“Flutter组件生命周期和App生命周期示例解析”的完整攻略。 Flutter组件生命周期 在Flutter中,每个组件都有其生命周期,即组件创建、销毁和重建时的一系列操作。Flutter的组件生命周期有四个部分,分别为: 创建阶段(Create):在这个阶段中,组件通过调用StatelessWidget或StatefulWidget构造函…

    other 2023年6月27日
    00
  • 红米内存不足怎么办?红米手机内部储存空间不足的解决方法

    红米内存不足怎么办?红米手机内部储存空间不足的解决方法 红米手机在使用过程中可能会遇到内存不足的问题,这会导致手机运行缓慢、应用程序崩溃等不良影响。下面是一些解决红米手机内存不足问题的方法。 1. 清理缓存和临时文件 缓存和临时文件占据了手机内存的一部分空间,清理它们可以释放一些内存空间。你可以按照以下步骤进行操作: 打开手机的设置菜单。 滑动到\”存储\”…

    other 2023年8月1日
    00
  • oppo reno反复自动重启怎么解决?

    Oppo Reno自动重启解决攻略 原因分析 Oppo Reno自动重启的原因可能是系统bug、应用冲突、系统升级问题等,需要对具体原因进行分析。 解决方案 以下是解决该问题的几种方案,可以依次尝试,可根据具体情况选择。 方案一:安全模式 进入安全模式,如果无法在安全模式下看到自动重启,可能是因为第三方应用程序引起的。尝试卸载可能引起该问题的应用程序。以下是…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部