详解Java LinkedList

这篇具有很好参考价值的文章主要介绍了详解Java LinkedList。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

LinkedList简介

LinkedList是List接口的实现类,基于双向链表实现,继承自AbstractSequentialList类,同时也实现了Cloneable、Serializable接口。此外还实现了Queue和Deque接口,可以作为队列或双端队列使用。

详解Java LinkedList

LinkedList的插入删除时间复杂度:

  • 在头部或尾部插入删除元素,只需要修改头节点或尾节点的指针即可完成,时间复杂度为O(1);
  • 在其他位置插入删除元素,需要遍历到指定位置,再修改指定节点的指针,平均要移动n/2个位置,时间复杂度为O(n)。

LinkedList没有像ArrayList有RandomAccess接口的标记,因为LinkedList基于链表实现,链表节点之间的内存地址不连续,只能通过指针来定位,因此无法实现快速随机访问。

常用方法

public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
		//添加元素
        linkedList.add(2);
        linkedList.addFirst(1);
        linkedList.add(3);
        linkedList.add(4);
        linkedList.addLast(5);
		//获取元素
        System.out.println(linkedList.get(1));
        System.out.println(linkedList.getFirst());
        System.out.println(linkedList.getLast());
		//创建双端队列
        Deque<String> deque = new LinkedList<>();
		//元素入队
        deque.offer("a");
        deque.offer("b");
        deque.offer("c");
		//获取队头元素,但不删除队头元素
        System.out.println(deque.peek());
		//元素出队
        String a = deque.poll();
        System.out.println(a);
    }
}

LinkedList核心源码分析

下面以JDK17的LinkedList代码进行分析。

类属性

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
	//LinkedList大小
    transient int size = 0;

    //首节点
    transient Node<E> first;

    //尾节点
    transient Node<E> last;
}

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;
	}
}

构造方法

//创建一个空链表对象
public LinkedList() {
}

//传入一个集合,将集合中的元素存入链表
public LinkedList(Collection<? extends E> c) {
	this();
	addAll(c);
}

添加元素

因为LinkedList基于双向链表实现,并且实现了List和Queue接口,所有有多种添加元素的方法。
add方法

//在链表尾部添加元素
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++;
	modCount++;
}
//在指定下标出添加元素
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) {
	// assert succ != null;
	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++;
	modCount++;
}
//插入链表头部
public void addFirst(E e) {
	linkFirst(e);
}
//头插法
private void linkFirst(E e) {
	final Node<E> f = first;
	final Node<E> newNode = new Node<>(null, e, f);
	first = newNode;
	if (f == null)
		last = newNode;
	else
		f.prev = newNode;
	size++;
	modCount++;
}

//插入链表尾部
public void addLast(E e) {
	linkLast(e);
}

获取元素

LinkedList提供了三个get方法获取元素。

//获取链表第一个元素
public E getFirst() {
	final Node<E> f = first;
	if (f == null)
		throw new NoSuchElementException();
	return f.item;
}

//获取链表最后一个元素
public E getLast() {
	final Node<E> l = last;
	if (l == null)
		throw new NoSuchElementException();
	return l.item;
}

//根据下标获取链表中的元素
public E get(int index) {
	//检查下标是否越界
	checkElementIndex(index);
	//遍历链表,返回查找到的节点值
	return node(index).item;
}

node方法就是用来遍历链表的:

Node<E> node(int index) {
	// assert isElementIndex(index);
	//如果下标小于LinkedList的一半则从头节点开始遍历,否则从尾节点开始
	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;
	}
}

删除元素

removeFirst方法,删除链表头节点

public E removeFirst() {
	final Node<E> f = first;
	if (f == null)
		throw new NoSuchElementException();
	return unlinkFirst(f);
}

private E unlinkFirst(Node<E> f) {
	// assert f == first && f != null;
	//保留待删除节点的信息
	final E element = f.item;
	//记录待删除节点的后继
	final Node<E> next = f.next;
	f.item = null;
	f.next = null; // help GC
	first = next;
	if (next == null)
		last = null;
	else
		next.prev = null;
	size--;
	modCount++;
	return element;
}

removeLast方法,删除链表尾节点

public E removeLast() {
	final Node<E> l = last;
	if (l == null)
		throw new NoSuchElementException();
	return unlinkLast(l);
}

private E unlinkLast(Node<E> l) {
	// assert l == last && l != null;
	final E element = l.item;
	//记录待删除节点的前驱
	final Node<E> prev = l.prev;
	l.item = null;
	l.prev = null; // help GC
	last = prev;
	if (prev == null)
		first = null;
	else
		prev.next = null;
	size--;
	modCount++;
	return element;
}
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;
}
public E remove(int index) {
	checkElementIndex(index);
	return unlink(node(index));
}

//实际执行删除节点的方法
E unlink(Node<E> x) {
	// assert x != null;
	//保留待删除节点的信息,记录前驱和后继
	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--;
	modCount++;
	return element;
}

队列操作

返回队头元素:

public E peek() {
	final Node<E> f = first;
	return (f == null) ? null : f.item;
}

队头元素出队,调用了删除链表头节点的方法:

public E poll() {
	final Node<E> f = first;
	return (f == null) ? null : unlinkFirst(f);
}

入队,调用了add方法:

public boolean offer(E e) {
	return add(e);
}

此外还有一些双端队列的方法,如offerFirstofferLastpeekFirstpeekLastpollFirstpollLast等。文章来源地址https://www.toymoban.com/news/detail-739369.html

到了这里,关于详解Java LinkedList的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中创建List接口、ArrayList类和LinkedList类的常用方法(一)

    要了解List接口,就不得不说起Java的集合框架。 (该图来自菜鸟教程) Java 集合框架主要包括两种类型的容器,集合Collection和图Map。 Collection接口代表了 单列集合 ,它包含了一组Object元素,每个元素都有一个值。 (这里有个“泛型擦除”的概念,在此不提及有兴趣可自行了

    2024年01月19日
    浏览(50)
  • 【数据结构】_4.List接口实现类LinkedList与链表

    目录 1.链表的结构与特点 1.1 链表的结构: 1.2 链表的特点: 2. 不带头单链表的模拟实现 3. 单链表OJ 3.1 题目1:移除链表元素:  3.2 题目2:反转一个单链表 3.3 题目3:返回链表的中间结点 3.4 题目4:链表的倒数第k个结点 3.5 题目5:合并两个有序链表 3.6 题目6:链表的回文结构

    2024年02月15日
    浏览(45)
  • Java语言----LinkedList 和 链表的实现

    目录 一.链表概念 二.链表的分类  三.无头单向非循环链表的实现 3.1创建简单链表 3.2 链表基本方法实现 3.3四大基本功能              3.3.1.增加元素结点              3.3.2.查找元素结点              3.3.3.删除元素结点              3.3.4.结点信息修改   四.LinkedList是什

    2024年02月02日
    浏览(61)
  • 基于Python简单实现接口自动化测试(详解)

    本文从一个简单的登录接口测试入手,一步步调整优化接口调用姿势,然后简单讨论了一下接口测试框架的要点,最后介绍了一下我们目前正在使用的接口测试框架pithy。期望读者可以通过本文对接口自动化测试有一个大致的了解。 为什么要做接口自动化测试? 在当前互联网

    2024年01月20日
    浏览(51)
  • 数据结构(Java实现)LinkedList与链表(上)

    链表 逻辑结构 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。 无头双向链表:在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。 链表的实现 创建一个链表 遍历单链表 、 得到

    2024年02月11日
    浏览(53)
  • 数据结构(Java实现)LinkedList与链表(下)

    ** ** 结论 让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。 LinkedList的模拟实现 单个节点的实现 尾插 运行结果如下: 也可以暴力使用 全部代码 MyLinkedList IndexOut

    2024年02月11日
    浏览(46)
  • Java基础——LinkedList集合实现栈和队列

    (1)LinkedList的特点: 底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首位操作的特有API。 (2)LinkedList集合的特有功能: 方法名称 说明 public void addFirst(E e) 在该列表开头插入指定的元素 public void addLast(E e) 将指定的元素追加到此列表的末尾 publ

    2023年04月12日
    浏览(46)
  • java集合之List接口实现类常用方法详解

    目录 一、List集合概述 二、ArrayList类 三、ArrayList常用方法实例 四、LinkedList类 五、Linkedist常用方法实例         java.util.List接口继承自Collection接口,是单列集合的一个分支,通常将实现了List接口的对象称为List集合,在List集合中允许出现重复的元素,所有的元素是以一种线

    2024年02月08日
    浏览(51)
  • Java中栈实现怎么选?Stack、Deque、ArrayDeque、LinkedList(含常用Api积累)

    目录 Java中的Stack类 不用Stack有以下两点原因 1、从性能上来说应该使用Deque代替Stack。 2、Stack从Vector继承是个历史遗留问题,JDK官方已建议优先使用Deque的实现类来代替Stack。 该用ArrayDeque还是LinkedList? ArrayDeque与LinkList区别: ArrayDeque: LinkList: 结论 API积累 Deque中常用方法:

    2024年02月07日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包