博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ArrayList,LinkedList,Vector,Stack之间的区别
阅读量:7101 次
发布时间:2019-06-28

本文共 4829 字,大约阅读时间需要 16 分钟。

一,线程安全性

Vector、Stack:线程安全

ArrayList、LinkedList:非线程安全

二,实现方式

LinkedList:双向链表

ArrayList,Vector,Stack:数组

三,容量扩展方面

由于ArrayList和Vector(Stack继承自Vector,只在Vector的基础上添加了几个Stack相关的方法,故之后不再对Stack做特别的说明)使用数组实现,当数组长度不够时,其内部会创建一个更大的数组,然后将原数组中的数据拷贝至新数组中

//ArrayList  public boolean add(E e) {      ensureCapacity(size + 1);      elementData[size++] = e;      return true;  }    public void ensureCapacity(int minCapacity) {      modCount++;      int oldCapacity = elementData.length;      if (minCapacity > oldCapacity) {          Object oldData[] = elementData;          int newCapacity = (oldCapacity * 3)/2 + 1;          //如果这次扩展不能满足要求,那就直接用minCapacity          if (newCapacity < minCapacity)              newCapacity = minCapacity;          // minCapacity is usually close to size, so this is a win:          elementData = Arrays.copyOf(elementData, newCapacity);      }  }

如需扩展,则每次至少扩展至(原长度*3)/2 + 1

//Vector  public synchronized void addElement(E obj) {      modCount++;      ensureCapacityHelper(elementCount + 1);      elementData[elementCount++] = obj;  }    private void ensureCapacityHelper(int minCapacity) {      int oldCapacity = elementData.length;      if (minCapacity > oldCapacity) {          Object[] oldData = elementData;          int newCapacity = (capacityIncrement > 0) ?              (oldCapacity + capacityIncrement) : (oldCapacity * 2);          //如果这次扩展不能满足要求,那就直接用minCapacity          if (newCapacity < minCapacity) {              newCapacity = minCapacity;          }          elementData = Arrays.copyOf(elementData, newCapacity);      }  }

如果在创建Vector时不指定capacityIncrement(自动扩展长度)的值,如需扩展,则每次至少扩展至原长度的2倍

四,效率方面

这里仅仅比较ArrayList和LinkedList之间的效率差异

1,查询

ArrayList直接通过下标进行定位

//ArrayList  public E get(int index) {      RangeCheck(index);//检查下标是否超过数组长度      return (E) elementData[index];  }

LinkedList则需要进行遍历,平均遍历次数应为n/4

//LinkedList  public E get(int index) {      return entry(index).element;  }        private Entry
entry(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); Entry
e = header; //size >>1 相当于size/2 //由于LinkedList由双向链表实现,故从离得较近的一端开始遍历更快 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; }

对于指定位置查询,由于可以通过下标直接进行定位,ArrayList的速度远快于LinkedList

但是如果都为首尾位置的查询,情况会大为不同,因为LinkedList也是可以直接定位到首尾位置的

//LinkedList  public E getFirst() {      if (size==0)          throw new NoSuchElementException();      return header.next.element;  }    public E getLast()  {      if (size==0)          throw new NoSuchElementException();      return header.previous.element;  }

此时ArrayList和LinkedList的效率相同

2,插入

对于ArrayList,指定位置插入有可能首先需要对数组容量进行扩展,之后还有可能导致数组中的数据需要顺次移动(代码中通过数组拷贝实现,避免了数据一个一个的移动),极端情况下插入一个数据将进行两次数组拷贝

//ArrayList  public void add(int index, E element) {      if (index > size || index < 0)          throw new IndexOutOfBoundsException(                  "Index: "+index+", Size: "+size);      ensureCapacity(size+1);  //如必要,将对数组容量进行扩展      System.arraycopy(elementData, index, elementData, index + 1,              size - index);      elementData[index] = element;      size++;  }

如果不指定插入位置,则插入至数组末端,此时只需考虑可能的数组容量扩展对性能带来的影响

//ArrayList  public boolean add(E e) {      ensureCapacity(size + 1);       elementData[size++] = e;      return true;  }

由于LinkedList是由链表实现的,并没有指定位置插入的方法,即便如此,一切也显得如此美好

/LinkedList  public boolean add(E e) {      addBefore(e, header);          return true;  }        private Entry
addBefore(E e, Entry
entry) { Entry
newEntry = new Entry
(e, entry, entry.previous); newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; size++; modCount++; return newEntry; }

当然了,LinkedList可以直接将数据插入至首尾

//LinkedList  public void addFirst(E e) {      addBefore(e, header.next);  }    public void addLast(E e) {      addBefore(e, header);  }

总体来说,LinkedList效率高于ArrayList,即使在末尾插入,ArrayList也需要考虑可能的容量扩展对性能带来的影响

3,修改

和查询属于同一种情况

4,删除

指定位置的删除和插入属于同一种情况

除了删除指定位置数据,ArrayList和LinkedList都包含一个clear()方法用来清除所有数据

//ArrayList  public void clear() {      modCount++;        // Let gc do its work      for (int i = 0; i < size; i++)          elementData[i] = null;      size = 0;  }  [java] view plain copy 在CODE上查看代码片派生到我的代码片//LinkedList  public void clear() {      Entry
e = header.next; while (e != header) { Entry
next = e.next; e.next = e.previous = null; e.element = null; e = next; } header.next = header.previous = header; size = 0; modCount++; }

由于都需要进行遍历,故效率相同

转载地址:http://nmkhl.baihongyu.com/

你可能感兴趣的文章
ibatis sqlMap.xml 文件 like 查询的三种方案
查看>>
UIWebView捕捉点击事件
查看>>
关于Java继承问题
查看>>
Yii - 直接执行SQL语句(转)
查看>>
C#事件-事件处理
查看>>
Android——线程通讯类Handler(转)
查看>>
正确使用pthread_create,防止内存泄漏
查看>>
oracle 为 用户 解锁 加锁 (以hr为例)
查看>>
【C++】模板参数推导(template argument deduction)
查看>>
新闻内容翻页
查看>>
VB 读写文件
查看>>
【Linux】time
查看>>
data-compression download
查看>>
多种联结语句
查看>>
ProcesscmdKey KeyDate老是 ProcessKey解决方法
查看>>
git stash和git stash pop
查看>>
[原]Windows批处理命令学习二
查看>>
利用SSLStrip & Ettercap ARP欺骗嗅探密码
查看>>
心血来潮虚拟机安装了centos 6.2,且重新温习了linux下常用命令
查看>>
pku 1611 The Suspects 并查集的应用
查看>>