标签:linked 删除元素 lin ofo amp 控制 str 布尔类型 迭代
LinkedList是一个链表结构类型的列表,底层通过链表结构来存储数据的链式存储,可以无限链接新元素(受限于硬盘存储容量),不存在ArrayList(底层使用数组实现)中的数组扩容问题,具有插入,删除元素快捷、方便的特点,但因为每个节点需要有上一个节点和下一个节点的引用,从而导致了每个结点需要存储空间的增加,而且不能做到像ArrayList那种快速随机访问指定元素(即可以直接根据索引访问元素值),在LinkedList中获取元素都需要从头节点开始逐个访问链表节点,源码中的节点查找方法(node(int index)方法)使用了头节点和尾节点同时往中间节点查找的方式,一定程度上提高了查找效率,以下为对应的源码:
Node<E> node(int index) {
// assert isElementIndex(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的介绍,依旧是从构造方法开始讲起,在LinkedList中为我们提供了两个构造方法,我们来逐个查看:
这是一个无形参的空构造,方法内除了隐藏的super();再没有其他初始化代码,实例对象中的未赋值属性将全部按照成员变量的默认值进行赋值,分别有first和last,还有一个size属性赋值为0
该构造方法传入了一个集合对象c,并在构造方法的首行使用this()调用了空构造方法,并在之后调用addAll(Collection<? extends E> c)方法将传入集合的所有元素添加到列表中
public LinkedList(Collection<? extends E> c) {
//调用空构造
this();
//将集合中的所有元素添加到列表的尾部
addAll(c);
}
到这里构造方法部分也就介绍完了,在介绍LinkedList中提供的公开方法之前,要注意的是LinkedList和ArrayList一样是一个非线程安全的类对象,所以如果涉及并发操作,建议在初始化的时候就调用Collections.synchronizedList(list)来将线程不安全的列表对象转化为线程安全的对象,内部的实现原理:使用代理模式在原来的方法执行之前嵌套了一个同步机制,这里摘取其中的size()方法,源码如下:
public int size() {
synchronized (mutex) { //同步代码块
return c.size(); //c为被代理对象
}
}
因为给所有的方法加上锁会降低代码的执行效率,而且有些方法是不需要加锁的,如果不想对所有的方法都加锁,可以在需要加锁的特定方法调用之前手动的做同步处理
下面进入LinkedList中公开方法的详细解析,对于功能完全一样的方法会做为同类处理,对于索引这个词语的使用,仅表示从首节点开始算起,迭代的个数值减一,非真正的数组索引:
这三个方法功能相同,都是往列表的尾部链接上新元素,并返回一个布尔值,在offer(E element)方法中仅仅只是调用了add(E element)方法,没有做其他任何操作,而offerLast(E element)调用的是addLast(E element)方法,在add(E element)和addLast()方法中调用了内部的linkLast(E element)方法
该方法用于往列表的头部链接上新地元素,并返回一个布尔值,在offerFirst(E element)方法中调用的是addFirst(E element)方法,在addFirst(E element)方法调用内部的linkFirst(E element)方法
该方法用于在指定索引的位置插入指定元素,无返回值
这两个方法功能相同,都是往列表头部链接上新元素,无返回值,在push(E element)方法中仅仅只是调用了addFirst(E element)方法,没有做其他任何操作,在addFirst(E element)中调用了内部的linkFirst(E element)方法
该方法用于在列表尾部链接上新元素,无返回值,方法内调用内部的linkLast(E element)方法
这三个方法功能相同,都是移除列表的首元素,如果首元素不存在会抛出异常,存在则返回首元素的内容值,在pop()方法和remove()方法中仅仅只是调用了removeFirst()方法,没有做其他任何操作,在removeFirst()方法调用了内部的unlinkFirst(first)方法
该方法用于移除列表的尾元素,如果尾元素不存在会抛出异常,存在则返回尾元素的内容值,在removeLast()方法调用了内部的unlinkLast(last)方法
这两个方法功能相同,都是移除列表的首元素并返回该元素,与removeFirst()方法不同的是,如果首元素不存在则返回null,poll()方法和pollFist()方法内都是调用的内部unlinkFirst(first)方法
该方法用于移除列表的尾元素并返回该元素,与removeLast()方法不同的是,如果尾元素不存在则返回null,方法内调用的是内部unlinkLast(last)方法
这两个方法功能相同,都是获取列表的首元素的内容值,而且不从列表中删除该元素,如果首节点不存在则返回null
该方法用于获取列表的尾元素的内容值,而且不从列表中删除该元素,如果尾元素不存在则返回null
这两个方法功能相同,都是检索列表的首元素、返回该元素而且不删除该元素,如果首元素不存在则抛出异常,在element()方法中仅仅只是调用了getFirst()方法,没有做其他任何操作
该方法用于检索列表尾元素、返回该元素而且不删除该元素,如果尾元素不存在,则抛出异常
这两个方法功能相同,都是用于删除列表中出现的第一个指定元素,返回值为布尔值,在removeFirstOccurance(Object o)方法中仅仅只是调用了remove(Object o)方法,没有做其他任何操作,remove(Object o)方法内调用内部方法unlink(x)方法,其中x为迭代查找到的列表元素
该方法用于删除列表中最后一个指定元素,返回值为布尔类型,方法内调用内部方法unlink(x)方法,其中x为迭代查找到的列表元素
该方法用于删除列表中的指定索引位置的元素,并返回被删除的元素内容值,方法内调用内部方法unlink(node(index))方法
该方法用于向列表中添加传入集合的元素值,内部调用addAll(size,c);即从列表尾部链接所有新元素
该方法用于向列表中的指定索引位置链接上所有的新元素
该方法用于获取指定索引位置的列表元素内容值
该方法用于获取指定元素在列表中第一次出现的索引值,未找到则返回-1
该方法用于获取指定元素在列表中最后一次出现的索引值,未找到则返回-1
该方法用于判断列表中是否含有特定的元素值,内部调用indexOf(Object o)方法
该方法用于获取列表中元素的个数值,即列表的长度
该方法用于将指定索引的元素替换为传入值,并返回被替换下元素的内容值
该方法用于清空列表中的所有值,用遍历方式清空所有列表元素,最后把last=first=0,并把size=0
该方法用于将列表转化为数组,可以在形参中指定返回数组的类型,例如:list.toArray(new String[0])即可将列表转化为String[]类型的数组并返回,无参方法相当于传入new Object[0],返回值类型为Object[]
该方法用于返回一个当前列表的浅克隆对象
该方法用于返回一个当前列表的迭代器对象,可以指定迭代起始位置,内部提供了hasNext(),next(),hasPrevious(),previous(),nextIndex(),previousIndex(),remove()-删除当前位置的元素值,set(E element)-替换当前位置的元素值,add(E element)-在当前位置插入新的元素,forEachRemaining(Consumer<? super E> action)-用于对所有未遍历对象执行传入的指定操作逻辑
注意:remove()方法不可连续调用多次,因为在一次调用之后,内部的lastReturned属性将变为null,当下一次调用previous()或next()方法时会重新被赋值,其次,在使用迭代器遍历列表元素时,不可以直接使用外部列表的方法对列表的结构进行修改(新增元素或删除元素),否则会报错,不过可以使用迭代器内部的add和remove方法来实现元素的新增和删除操作
该方法用于返回一个逆序的迭代器对象,实现原理:内部包含一个listIterator对象,并将索引初始化为size,然后每当调用descendingIterator的next方法时,调用内部listIterator的previous方法,previous方法同理
该方法用于返回一个可分割的列表对象(该对象底层为数组结构),可以用于多线程并发操作同一个列表的多个分割对象,调用该方法返回的对象可以调用trySplit()方法进行元素分割(五五分成),不过要注意的是第一次调用的trySplit()方法和后面调用的trySplit()方法不是同一个,具体查看源码:
//首次调用的是列表对象调用spliterator方法生成的LLSpliterator内部类的trySplit方法,返回值为ArraySpliterator实例对象
public Spliterator<E> trySplit() {
Node<E> p;
//获取剩余元素个数
int s = getEst();
//若元素个数大于1,并且首节点存在
if (s > 1 && (p = current) != null) {
//设置单次切割上限值,最大一次切分1024个元素
int n = batch + BATCH_UNIT;
//调整切割上限值
if (n > s)
n = s;
//调整切割上限值,其中MAX_BATCH=2^25=33554432
if (n > MAX_BATCH)
n = MAX_BATCH;
//新建一个对象数组,用于存储分割出的元素,因为ArraySpliterator是不支持链表结构的
Object[] a = new Object[n];
int j = 0;
//其中的j<n用于控制切割数量
do { a[j++] = p.item; } while ((p = p.next) != null && j < n);
//将当前元素置为切割出去元素的后一个元素
current = p;
//将batch值置为切分出去的最后一个元素的索引的下一个索引位置
batch = j;
//当前列表元素个数减取切割出去的个数
est = s - j;
//调用Spliterators.spliterator方法,返回一个ArraySpliterator
//下一个调用的trySplit将不再是这里的trySplit,而是ArraySpliterator中的trySplit方法,对列表元素进行对半切分
return Spliterators.spliterator(a, 0, j, Spliterator.ORDERED);
}
return null;
}
public static <T> Spliterator<T> spliterator(Object[] array, int fromIndex, int toIndex, int additionalCharacteristics) {
checkFromToBounds(Objects.requireNonNull(array).length, fromIndex, toIndex);
return new ArraySpliterator<>(array, fromIndex, toIndex, additionalCharacteristics);
}
//第一次之后调用的trySplit方法,来自ArraySpliterator类中
public Spliterator<T> trySplit() {
int lo = index, mid = (lo + fence) >>> 1;
return (lo >= mid) ? null : new ArraySpliterator<>(array, lo, index = mid, characteristics);
}
使用spliterator的示例代码
LinkedList<Object> list = new LinkedList<>();
list.add("1");list.add("2");list.add("3");list.add("4");list.add("5");
list.add("6");list.add("7");list.add("8");list.add("9");
Spliterator<Object> spliterator = list.spliterator();
Spliterator<Object> a = spliterator.trySplit();
Spliterator<Object> b = a.trySplit();
Spliterator<Object> c = a.trySplit();
Spliterator<Object> d = b.trySplit();
a.forEachRemaining(System.out::println);
System.out.println();
b.forEachRemaining(System.out::println);
System.out.println();
c.forEachRemaining(System.out::println);
System.out.println();
d.forEachRemaini
对应的处理结果为:
7
8
9
3
4
5
6
1
2
如果对你有帮助,点个赞,或者打个赏吧,嘿嘿
整理不易,请尊重博主的劳动成果
标签:linked 删除元素 lin ofo amp 控制 str 布尔类型 迭代
原文地址:https://www.cnblogs.com/Mango-Tree/p/LinkedList.html