LinkedList源码分析

本文深入探讨了 Java LinkedList 的核心实现原理,包括成员变量、构造方法、常用方法及其内部实现逻辑,帮助读者全面理解 LinkedList 的高效操作机制。

成员变量

private transient Entry<E> header = new Entry<E>(null, null, null);
链表头元素

private transient int size = 0;
链表大小

构造方法

public LinkedList() {
		header.next = header.previous = header;
	}
无参构造。初始化链表头,将其next、previoous都指向其自身。

public LinkedList(Collection<? extends E> c) {
		this();
		addAll(c);
	}
该构造首先调用无参构造,然后将Collection中的元素加入到集合中。

方法

getFirst

public E getFirst() {
		if (size == 0)
			throw new NoSuchElementException();

		return header.next.element;
	}
返回链表中的第一个元素

getLast

public E getLast() {
		if (size == 0)
			throw new NoSuchElementException();

		return header.previous.element;
	}
返回链表中最后一个元素,由于其内部实现是双向链表,故直接调用header.previous.element即可。

removeFirst

public E removeFirst() {
		return remove(header.next);
	}
删除链表中的第一个元素,并返回其值,具体实现参见remove方法

removeLast

public E removeLast() {
		return remove(header.previous);
	}
删除链表中最后一个元素,并返回其值

addFirst

public void addFirst(E e) {
		addBefore(e, header.next);
	}
在链表头部插入一个元素

addLast

public void addLast(E e) {
		addBefore(e, header);
	}
在链表添加尾部插入一个元素

contains

public boolean contains(Object o) {
		return indexOf(o) != -1;
	}
检查是否包含指定元素

size

public int size() {
		return size;
	}
返回链表中元素的个数

add

public boolean add(E e) {
		addBefore(e, header);
		return true;
	}
在链表尾部加入一个元素
public void add(int index, E element) {
		addBefore(element, (index == size ? header : entry(index)));
	}
在某个位置加入元素

remove

public boolean remove(Object o) {
		if (o == null) {
			for (Entry<E> e = header.next; e != header; e = e.next) {
				if (e.element == null) {
					remove(e);
					return true;
				}
			}
		} else {
			for (Entry<E> e = header.next; e != header; e = e.next) {
				if (o.equals(e.element)) {
					remove(e);
					return true;
				}
			}
		}
		return false;
	}
删除某个元素,首先判断元素是否为null,然后进行相关的查找。

public E remove(int index) {
		return remove(entry(index));
	}
删除某一位置的元素

addAll

public boolean addAll(Collection<? extends E> c) {
		return addAll(size, c);
	}
将集合添加到链表的尾部
public boolean addAll(int index, Collection<? extends E> c) {
		if (index < 0 || index > size) //边界范围校验
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		Object[] a = c.toArray(); //将集合转化成数组
		int numNew = a.length; //数组的长度
		if (numNew == 0)
			return false; //空集合则不用添加
		modCount++;  //结构变动变量自增

		Entry<E> successor = (index == size ? header : entry(index)); //确定集合元素添加到哪个元素之前,记为E
		Entry<E> predecessor = successor.previous; //保存E的前一个元素
		for (int i = 0; i < numNew; i++) { //循环要加入到链表的集合,
			Entry<E> e = new Entry<E>((E) a[i], successor, predecessor); //构建元素并将其next和previous分别指向E、E.previous。
			predecessor.next = e; //将E.previous的next指向新节点,这样新节点就会插入到链表中。仔细考虑此处并没有立即将successor的previous指向新节点,而是在整个循环结束之后才处理。
			predecessor = e; //将新构建的元素赋值给predecessor,即E.previous为新插入的节点,如此反复最终将这些集合元素添加到链表中
		}
		successor.previous = predecessor; //修复E的previous指向

		size += numNew; //链表大小调整
		return true;
	}
将集合中的元素添加到链表指定位置,方法具体解释见代码后的注释。

clear

public void clear() {
		Entry<E> e = header.next;
		while (e != header) {
			Entry<E> next = e.next;
			e.next = e.previous = null;
			e.element = null;
			e = next;
		}
		header.next = header.previous = header;
		size = 0;
		modCount++;
	}
清空链表

get

public E get(int index) {
		return entry(index).element;
	}
返回某个位置的值

set

public E set(int index, E element) {
		Entry<E> e = entry(index);
		E oldVal = e.element;
		e.element = element;
		return oldVal;
	}
设置某个位置的值

indexOf

public int indexOf(Object o) {
		int index = 0;
		if (o == null) {
			for (Entry e = header.next; e != header; e = e.next) {
				if (e.element == null)
					return index;
				index++;
			}
		} else {
			for (Entry e = header.next; e != header; e = e.next) {
				if (o.equals(e.element))
					return index;
				index++;
			}
		}
		return -1;
	}
返回某个元素在链表中首次出现的位置,未找到则返回-1

lastIndexOf

public int lastIndexOf(Object o) {
		int index = size;
		if (o == null) {
			for (Entry e = header.previous; e != header; e = e.previous) {
				index--;
				if (e.element == null)
					return index;
			}
		} else {
			for (Entry e = header.previous; e != header; e = e.previous) {
				index--;
				if (o.equals(e.element))
					return index;
			}
		}
		return -1;
	}
返回某个元素在链表中最后出现的位置,未找到则返回-1

peek

public E peek() {
		if (size == 0)
			return null;
		return getFirst();
	}
返回链表中的第一元素

element

public E element() {
		return getFirst();
	}
返回链表中的第一个元素,该方法同上面的peek方法的区别在于当链表为空时,peek返回为null,而element方法抛出NoSuchElementException异常

poll

public E poll() {
		if (size == 0)
			return null;
		return removeFirst();
	}
返回链表中的第一个元素,并将其在链表中移除,当链表为空时返回null

remove

public E remove() {
		return removeFirst();
	}
返回链表中的第一个元素,并将其从链表中移除,当链表为空时抛出NoSuchElementException异常

offer

public boolean offer(E e) {
		return add(e);
	}
在链表的尾部加入元素

offerFirst

public boolean offerFirst(E e) {
		addFirst(e);
		return true;
	}
在链表的头部加入元素

offerLast

public boolean offerLast(E e) {
		addLast(e);
		return true;
	}
在链表的尾部加入元素

peekFirst

public E peekFirst() {
		if (size == 0)
			return null;
		return getFirst();
	}
返回链表第一个元素,当链表为空时返回null

peekLast

public E peekLast() {
		if (size == 0)
			return null;
		return getLast();
	}
返回链表的最后一个元素,当链表为空时返回null

entry

private Entry<E> entry(int index) {
		if (index < 0 || index >= size)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		Entry<E> e = header;
		if (index < (size >> 1)) {
			for (int i = 0; i <= index; i++)
				e = e.next;
		} else {
			for (int i = size; i > index; i--)
				e = e.previous;
		}
		return e;
	}
该方法为私有方法,返回某个位置的元素




基于遗传算法的微电网调度(风、光、蓄电池、微型燃气轮机)(Matlab代码实现)内容概要:本文档介绍了基于遗传算法的微电网调度模型,涵盖风能、太阳能、蓄电池和微型燃气轮机等多种能源形式,并通过Matlab代码实现系统优化调度。该模型旨在解决微电网中多能源协调运行的问题,优化能源分配,降低运行成本,提高可再生能源利用率,同时考虑系统稳定性与经济性。文中详细阐述了遗传算法在求解微电网多目标优化问题中的应用,包括编码方式、适应度函数设计、约束处理及算法流程,并提供了完整的仿真代码供复现与学习。此外,文档还列举了大量相关电力系统优化案例,如负荷预测、储能配置、潮流计算等,展示了广泛的应用背景和技术支撑。; 适合人群:具备一定电力系统基础知识和Matlab编程能力的研究生、科研人员及从事微电网、智能电网优化研究的工程技术人员。; 使用场景及目标:①学习遗传算法在微电网调度中的具体实现方法;②掌握多能源系统建模与优化调度的技术路线;③为科研项目、毕业设计或实际工程提供可复用的代码框架与算法参考; 阅读建议:建议结合Matlab代码逐段理解算法实现细节,重点关注目标函数构建与约束条件处理,同时可参考文档中提供的其他优化案例进行拓展学习,以提升综合应用能力。
此项目旨在实现一个简易而实用的RFID智能门禁控制系统。采用经典的51系列单片机——STC89C52作为核心控制器,集成MFRC522射频识别模块来读取RFID卡片信息。用户界面通过128x64像素的LCD显示屏展示相关信息,同时配备了键盘用于密码的输入、验证及修改。此设计结合了RFID技术的高效率识别与单片机的强大控制能力,适用于学习、教学或小型安防项目。 资源包含 源代码:完整C语言编写的源程序,涵盖了RFID识别、密码验证逻辑、显示控制以及用户交互等功能模块。 原理图:详细展示了整个系统的电路连接,包括单片机、MFRC522模块、LCD12864屏幕、按键等组件的电气连接方式,便于理解和自制。 技术特点 RFID技术应用:通过MFRC522模块实现非接触式身份认证,提升门禁安全性与便捷性。 人机交互界面:利用LCD12864显示屏直观展示状态信息,并通过物理按键进行操作,增加了系统的易用性。 密码安全机制:支持用户密码的设定和更改,增强系统安全性。 51单片机编程:适合初学者和专业人士学习51单片机应用开发,尤其是嵌入式系统与物联网领域的实践。 使用指南 环境搭建:确保你有合适的IDE(如Keil uVision)安装以编译51单片机的C代码。 原理图分析:详细阅读原理图,了解各部件间的连接,这对于正确搭建硬件平台至关重要。 编译与上传:将提供的源代码编译无误后,通过编程器或ISP接口烧录到STC89C52单片机中。 硬件组装:根据原理图搭建电路,确保所有组件正确连接。 测试与调试:完成后进行功能测试,可能需要对代码或硬件做适当调整以达到最佳工作状态。
LinkedList是Java中提供的一个双向链表实现类,其内部维护了一个first和last节点,分别表示链表的头和尾。以下是LinkedList源码分析: 1. 声明LinkedList类 ```java public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { transient int size = 0; transient Node<E> first; transient Node<E> last; } ``` 2. 声明Node类 ```java 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; } } ``` 3. 实现LinkedList的方法 - add(E e)方法:将元素添加到链表末尾 ```java 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++; } ``` - add(int index, E element)方法:将元素插入到指定位置 ```java 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(int index)方法:删除指定位置的元素 ```java 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; } ``` - get(int index)方法:获取指定位置的元素 ```java 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; } } ``` 以上就是LinkedList源码分析,通过对其源码的分析,我们可以更深入地理解链表的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值