LinkedList

LinkedList是一个基于双向链表的数据结构,在多线程的环境下是不安全的。
因为它是基于链表实现的,所以对它的一切访问操作都会很慢,比如:
增:
若是在链表头部或尾部进行添加元素操作,只需要在每次添加元素时用head和tail来标记链表的头和尾,这样的话增加操作就会很快了;若是在链表中间插入一个元素,最好的方法也只有二分法,本质也就是for循环来进行查找和定位,链表越长,效率越低
删除:
流程和增加操作一样
改和查:
每次进行这两个操作都需要定位到相应的位置,本质也是for循环,效率低下

因为是双向链表,它的基本操作都比较简单,所以就不在这里贴代码了,相应的
我们来看看重点:
LinkedList里既为我们提供了普通的增删改查操作方法(传参时只需传递一个参数),又给我们提供了根据索引来增删改查操作它的方法。我们来看看根据索引的增删改查操作
增:

public void add(int index, E element) {
    checkPositionIndex(index);
if (index == size)
    linkLast(element);
else
    linkBefore(element, node(index));
}

删:

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

查:

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

改:

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

每个方法里都调用了一个构造方法node(int index),下面是源码:

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

可以看出,这个构造方法首先需要我们给出一个索引index,通过这个索引来进行判断:首先获取链表中点索引i,若此索引index处于链表的左侧index<i/2则从链表的头部开始进行for循环,直到找到这个元素;若此索引index处于链表的右侧index>i/2则从链表的尾部开始进行for循环,直到找到这个元素
即上述增删改方法都需要首先定位到指定元素,然后才能再进行相应的操作。
虽然此方法使用二分法来降低查找的复杂度,但是在链表很长的情况下查找效率还是非常低下的,最好的办法应该是对链表的头尾来操作,但是这种情况实在是太少了。
来做个测试:

import java.util.LinkedList;
import java.util.List;
import org.junit.Test;

public class speed {
    int j = 100;
	@Test
	public void tt() {
		long time = System.currentTimeMillis();
		List linkedList = new LinkedList();
		for (int i = 0; i < j; i++)
			linkedList.add(i);
		for (int i = 0; i < linkedList.size(); i++) {
			linkedList.get(i);
			System.out.println("LinkedList遍历速度:" + (System.currentTimeMillis() - time) + "ms");
		}
	}
}

循环向LinkedList中插入100个元素,然后取出并计时
结果:

...
LinkedList遍历速度:0ms
LinkedList遍历速度:1ms
LinkedList遍历速度:2ms
LinkedList遍历速度:3ms

接下来1000个,试一下,结果:

...
LinkedList遍历速度:59ms
LinkedList遍历速度:60ms

可以发现,插入的元素越多,取出时所耗时越久。所以,遍历它最好不要使用for循环去做。
遍历方法:
1、for循环

LinkedList list =new LinkedList();
		l.add(1);
		l.add(2);
		l.add(3);
		l.add(4);
		for(int i=0;i<l.size();i++)
			System.out.print(l.get(i) + " ");

这种方法并不推荐,因为每次调用get方法去取值都要遍历LinkedList的前半部分或后半部分,效率低

2、使用Iterator

for(Iterator it2 = list.iterator();it2.hasNext();){
             System.out.println(it2.next());
        }

或者

Iterator it1 = list.iterator();
        while(it1.hasNext()){
            System.out.println(it1.next());
        }

推荐使用此方法,耗时较低
3、增强for循环

for(String tmp:list){
            System.out.println(tmp);
        }

推荐使用此方法,耗时较低

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LinkedList是Java中的一个类,它实现了List接口和Deque接口,可以被看作是一个顺序容器、队列和栈。LinkedList的遍历过程和查找过程类似,可以从头节点开始往后遍历。然而,LinkedList不擅长随机位置访问,如果使用随机访问遍历LinkedList,效率会很低。通常情况下,我们会使用foreach循环来遍历LinkedList,因为foreach最终会转换成迭代器形式。LinkedList的遍历核心就是它的迭代器实现。[1] LinkedList的继承体系较为复杂,它继承自AbstractSequentialList类,并实现了List和Deque接口。AbstractSequentialList是一个基于顺序访问的接口,通过继承此类,子类只需实现部分代码即可拥有完整的一套访问某种序列表的接口。LinkedList还实现了Deque接口,Deque又继承自Queue接口,因此LinkedList具备了队列的功能。[2][3] LinkedList的实现方式决定了所有与下标有关的操作都是线性时间复杂度,而在首段或末尾删除元素只需要常数时间复杂度。LinkedList没有实现同步(synchronized),如果需要多个线程并发访问,可以使用Collections.synchronizedList()方法对其进行包装。[2] 总结来说,LinkedList是一个灵活的数据结构,可以用作顺序容器、队列和栈。它的遍历过程需要注意效率问题,不适合随机位置访问。LinkedList的继承体系较为复杂,继承自AbstractSequentialList类,并实现了List和Deque接口。LinkedList的实现方式决定了与下标有关的操作是线性时间复杂度,而在首段或末尾删除元素只需要常数时间复杂度。[1][2][3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值