java LinkedList的用法

总结下,LinkedList的两个remove方法,remove(Object)和remove(int)的时间复杂度都是O(n),在链表元素很多 并且没有索引可用的情况下,LinkedList也并不适合做随机增删元素。在对性能特别敏感的场景下,还是需要自己实现专用的双向链表结构,真正实现 O(1)级别的随机增删。更进一步,jdk5引入的ConcurrentLinkedQueue是一个非阻塞的线程安全的双向队列实现,同样有本文提到的 问题,有兴趣可以测试一下在大量元素情况下的并发随机增删,效率跟自己实现的特定类型的线程安全的链表差距是惊人的。 确保PHP安全 不能违反的四条安全规则
  理论上说,双向链表的删除的时间复杂度是O(1),你只需要将要删除的节点的前节点和后节点相连,然后将要删除的节点的前节点和后节点置为null即可,
  //伪代码
  node.prev.next=node.next;
  node.next.prev=node.prev;
  node.prev=node.next=null;
  
  这个操作的时间复杂度可以认为是O(1)级别的。但是LinkedList的实现是一个通用的数据结构,因此没有暴露内部的节点Entry对象,remove(Object)传入的Object其实是节点存储的value,这里还需要一个查找过程:
  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 {
  //查找节点Entry
  for (Entry<E> e = header.next; e != header; e = e.next) {
  if (o.equals(e.element)) {
  //删除节点
  remove(e);
  return true;
  }
  }
  }
  return false;
  }
  
  java.util.LinkedList是双向链表,这个大家都知道,比如Java的基础面试题喜欢问ArrayList和LinkedList的区 别,在什么场景下用。大家都会说LinkedList随机增删多的场景比较合适,而ArrayList的随机访问多的场景比较合适。更进一步,我有时候会 问,LinkedList.remove(Object)方法的时间复杂度是什么?有的人回答对了,有的人回答错了。回答错的应该是没有读过源码。
  删除节点的操作就是刚才伪代码描述的:
  private E remove(Entry<E> e) {
  E result = e.element;
  e.previous.next = e.next;
  e.next.previous = e.previous;
  e.next = e.previous = null;
  e.element = null;
  size--;
  modCount++;
  return result;
  }
  
  因此,显然,LinkedList.remove(Object)方法的时间复杂度是O(n)+O(1),结果仍然是O(n)的时间复杂度,而非推测的O(1)复杂度。最坏情况下要删除的元素是最后一个,你都要比较N-1次才能找到要删除的元素。
  
  既然如此,说LinkedList适合随机删减有个前提,链表的大小不能太大,如果链表元素非常多,调用remove(Object)去删除一个元素的效率肯定有影响,一个简单测试,插入100万数据,随机删除1000个元素:
  final List<Integer> list = new LinkedList<Integer>();
  final int count = 1000000;
  for (int i = 0; i < count; i++) {
  list.add(i);
  }
  final Random rand=new Random();
  long start=System.nanoTime();
  for(int i=0;i<1000;i++){
  //这里要强制转型为Integer,否则调用的是remove(int)
  list.remove((Integer)rand.nextInt(count));
  }
  System.out.println((System.nanoTime()-start)/Math.pow(10, 9));
  
  在我的机器上耗时近9.5秒,删除1000个元素耗时9.5秒,是不是很恐怖?注意到上面的注释,产生的随机数强制转为Integer对象,否则调用的是 remove(int)方法,而非remove(Object)。如果我们调用remove(int)根据索引来删除:
  for(int i=0;i<1000;i++){
  list.remove(rand.nextInt(list.size()-1));
  }
  随机数范围要递减,防止数组越界,换成remove(int)效率提高不少,但是仍然需要2.2秒左右(包括了随机数产生开销)。这是因为 remove(int)的实现很有技巧,它首先判断索引位置在链表的前半部分还是后半部分,如果是前半部分则从head往前查找,如果在后半部分,则从 head往后查找(LinkedList的实现是一个环):
  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;
  }
  
  最坏情况下要删除的节点在中点左右,查找的次数仍然达到n/2次,但是注意到这里没有比较的开销,并且比remove(Object)最坏情况下n次查找还是好很多。
  
  题外,ArrayList比LinkedList更不适合随机增删的原因是多了一个数组移动的动作,假设你删除的元素在m,那么除了要查找m次之外,还需要往前移动n-m-1个元素。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
javaLinkedList是一个双向链表的数据结构,位于java.util包。要使用LinkedList,需要先引入它的类。可以使用以下语法格式创建一个LinkedList实例: ```java import java.util.LinkedList; LinkedList<E> list = new LinkedList<E>(); // 普通创建方法 ``` 也可以使用集合来创建一个LinkedList实例: ```java import java.util.LinkedList; LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表 ``` 以下是一个简单的创建LinkedList实例的示例代码: ```java import java.util.LinkedList; public class Example { public static void main(String[] args) { LinkedList<String> sites = new LinkedList<String>(); sites.add("Google"); sites.add("Runoob"); sites.add("Taobao"); sites.add("Weibo"); System.out.println(sites); } } ``` 需要注意的是,LinkedList类的声明如下: ```java public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable ``` LinkedList类是一种具有双向链接的链表,它实现了List接口、Deque接口和AbstractSequentialList类。通过使用LinkedList,可以方便地对链表进行操作。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java链表(Linked list用法(单链表,双链表)](https://blog.csdn.net/Sueko/article/details/123333777)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *3* [java LinkedList用法解析(全面)](https://blog.csdn.net/linZinan_/article/details/114604893)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值