arraylist arraylist使用实例 linkedlist linkedlist源码解析 linkedlist和arraylist的区别

Java中ArrayList类的用法(转)

1、什么是ArrayList
ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处:
动态的增加和减少元素
实现了ICollection和IList接口
灵活的设置数组的大小

2、如何使用ArrayList
最简单的例子:
ArrayList List = new ArrayList();
for( int i=0;i <10;i++ ) //给数组增加10个Int元素
List.Add(i);
//..程序做一些处理
List.RemoveAt(5);//将第6个元素移除
for( int i=0;i <3;i++ ) //再增加3个元素
List.Add(i+20);
Int32[] values = (Int32[])List.ToArray(typeof(Int32));//返回ArrayList包含的数组

这是一个简单的例子,虽然没有包含ArrayList所有的方法,但是可以反映出ArrayList最常用的用法

3、ArrayList重要的方法和属性
1)构造器
ArrayList提供了三个构造器:
public ArrayList();
默认的构造器,将会以默认(16)的大小来初始化内部的数组
public ArrayList(ICollection);
用一个ICollection对象来构造,并将该集合的元素添加到ArrayList
public ArrayList(int);
用指定的大小来初始化内部的数组

2)IsSynchronized属性和ArrayList.Synchronized方法
IsSynchronized属性指示当前的ArrayList实例是否支持线程同步,而ArrayList.Synchronized静态方法则会返回一个ArrayList的线程同步的封装。
如果使用非线程同步的实例,那么在多线程访问的时候,需要自己手动调用lock来保持线程同步,例如:
ArrayList list = new ArrayList();
//...
lock( list.SyncRoot ) //当ArrayList为非线程包装的时候,SyncRoot属性其实就是它自己,但是为了满足ICollection的SyncRoot定义,这里还是使用SyncRoot来保持源代码的规范性
{
list.Add( “Add a Item” );
}

如果使用ArrayList.Synchronized方法返回的实例,那么就不用考虑线程同步的问题,这个实例本身就是线程安全的,实际上ArrayList内部实现了一个保证线程同步的内部类,ArrayList.Synchronized返回的就是这个类的实例,它里面的每个属性都是用了lock关键字来保证线程同步。

3)Count属性和Capacity属性
Count属性是目前ArrayList包含的元素的数量,这个属性是只读的。
Capacity属性是目前ArrayList能够包含的最大数量,可以手动的设置这个属性,但是当设置为小于Count值的时候会引发一个异常。

4)Add、AddRange、Remove、RemoveAt、RemoveRange、Insert、InsertRange
这几个方法比较类似
Add方法用于添加一个元素到当前列表的末尾
AddRange方法用于添加一批元素到当前列表的末尾
Remove方法用于删除一个元素,通过元素本身的引用来删除
RemoveAt方法用于删除一个元素,通过索引值来删除
RemoveRange用于删除一批元素,通过指定开始的索引和删除的数量来删除
Insert用于添加一个元素到指定位置,列表后面的元素依次往后移动
InsertRange用于从指定位置开始添加一批元素,列表后面的元素依次往后移动

另外,还有几个类似的方法:
Clear方法用于清除现有所有的元素
Contains方法用来查找某个对象在不在列表之中

其他的我就不一一累赘了,大家可以查看MSDN,上面讲的更仔细
5)TrimSize方法
这个方法用于将ArrayList固定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。
6)ToArray方法
这个方法把ArrayList的元素Copy到一个新的数组中。
4、ArrayList与数组转换
例1:
ArrayList List = new ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);

Int32[] values = (Int32[])List.ToArray(typeof(Int32));

例2:
ArrayList List = new ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);

Int32[] values = new Int32[List.Count];
List.CopyTo(values);

上面介绍了两种从ArrayList转换到数组的方法

例3:
ArrayList List = new ArrayList();
List.Add( “string” );
List.Add( 1 );
//往数组中添加不同类型的元素

object[] values = List.ToArray(typeof(object)); //正确
string[] values = (string[])List.ToArray(typeof(string)); //错误

和数组不一样,因为可以转换为Object数组,所以往ArrayList里面添加不同类型的元素是不会出错的,但是当调用ArrayList方法的时候,要么传递所有元素都可以正确转型的类型或者Object类型,否则将会抛出无法转型的异常。


5、ArrayList最佳使用建议
这一节我们来讨论ArrayList与数组的差别,以及ArrayList的效率问题
1)ArrayList是Array的复杂版本
ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚

定到实际元素的大小,当动态数组元素确定不在添加的时候,可以调用这个方法来释放空余的内存。
6)ToArray方法
这个方法把ArrayList的元素Copy到一个新的数组中。
4、ArrayList与数组转换
例1:
ArrayList List = new ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);

Int32[] values = (Int32[])List.ToArray(typeof(Int32));

例2:
ArrayList List = new ArrayList();
List.Add(1);
List.Add(2);
List.Add(3);

Int32[] values = new Int32[List.Count];
List.CopyTo(values);

上面介绍了两种从ArrayList转换到数组的方法

例3:
ArrayList List = new ArrayList();
List.Add( “string” );
List.Add( 1 );
//往数组中添加不同类型的元素

object[] values = List.ToArray(typeof(object)); //正确
string[] values = (string[])List.ToArray(typeof(string)); //错误

和数组不一样,因为可以转换为Object数组,所以往ArrayList里面添加不同类型的元素是不会出错的,但是当调用ArrayList方法的时候,要么传递所有元素都可以正确转型的类型或者Object类型,否则将会抛出无法转型的异常。


5、ArrayList最佳使用建议
这一节我们来讨论ArrayList与数组的差别,以及ArrayList的效率问题
1)ArrayList是Array的复杂版本
ArrayList内部封装了一个Object类型的数组,从一般的意义来说,它和数组没有本质的差别,甚至于ArrayList的许多方法,如Index、IndexOf、Contains、Sort等都是在内部数组的基础上直接调用Array的对应方法。
2)内部的Object类型的影响
对于一般的引用类型来说,这部分的影响不是很大,但是对于值类型来说,往ArrayList里面添加和修改元素,都会引起装箱和拆箱的操作,频繁的操作可能会影响一部分效率。
但是恰恰对于大多数人,多数的应用都是使用值类型的数组。
消除这个影响是没有办法的,除非你不用它,否则就要承担一部分的效率损失,不过这部分的损失不会很大。
3)数组扩容
这是对ArrayList效率影响比较大的一个因素。
每当执行Add、AddRange、Insert、InsertRange等添加元素的方法,都会检查内部数组的容量是否不够了,如果是,它就会以当前容量的两倍来重新构建一个数组,将旧元素Copy到新数组中,然后丢弃旧数组,在这个临界点的扩容操作,应该来说是比较影响效率的。
例1:比如,一个可能有200个元素的数据动态添加到一个以默认16个元素大小创建的ArrayList中,将会经过:
16*2*2*2*2 = 256
四次的扩容才会满足最终的要求,那么如果一开始就以:
ArrayList List = new ArrayList( 210 );
的方式创建ArrayList,不仅会减少4次数组创建和Copy的操作,还会减少内存使用。

例2:预计有30个元素而创建了一个ArrayList:
ArrayList List = new ArrayList(30);
在执行过程中,加入了31个元素,那么数组会扩充到60个元素的大小,而这时候不会有新的元素再增加进来,而且有没有调用TrimSize方法,那么就有1次扩容的操作,并且浪费了29个元素大小的空间。如果这时候,用:
ArrayList List = new ArrayList(40);
那么一切都解决了。
所以说,正确的预估可能的元素,并且在适当的时候调用TrimSize方法是提高ArrayList使用效率的重要途径。
4)频繁的调用IndexOf、Contains等方法(Sort、BinarySearch等方

法经过优化,不在此列)引起的效率损失
首先,我们要明确一点,ArrayList是动态数组,它不包括通过Key或者Value快速访问的算法,所以实际上调用IndexOf、Contains等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用Hashtable或SortedList等键值对的集合。
ArrayList al=new ArrayList();

al.Add("How");
al.Add("are");
al.Add("you!");

al.Add(100);
al.Add(200);
al.Add(300);

al.Add(1.2);
al.Add(22.8);

 

 

集合之间的关系图:

下面这张图看起来层级结构更清晰些。

 

 

arraylist使用实例

   public class ArrayList<E> extends AbstractList<E>implements List<E>,

   Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, includingnull. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)

 list接口的实现。

Common ArrayList methods and constructors 常见构造函数和方法

Here are some of the most useful ArrayList methods. Assume these declarations. Note that E is the notation for the type of an element in a collection. Sun recommends using single upper case letters for generic types.

   int i;
   ArrayList<E> a;
   E e;
   Iterator<E> iter;
   ListIterator<E> liter;
   E[] earray;
   Object[] oarray;

如果我们定义了

 ArrayList a=new ArrayList() ;那么这个ArrayL可以存放任何类型的数据

一旦我们指定了某一特定的类型,就只能放这种类型,如:

ArrayList<Integer> a=new ArrayList<Integer>();

如果a.add("xyz")就会报错。

 

Adding elements to the end of an ArrayList, getting them by index

ArrayList<E> a = new ArrayList<E>();  // Default size.
E s;          // Declare s to be an object type E.
. . .
a.add(s);     // Adds s to the end of the ArrayList a
. . .
s = a.get(i); // Assigns ith element from a to s.

To get successive elements from an ArrayList - Four ways

  

Use either a for loop with an integer index to get all the elements from an ArrayList, or go over all elements in a ArrayList using an Iterator (forward) or ListIterator (forward / backward).

  1. foreach loop. This is fast and works for all kinds of lists, but is not entirely flexible (only sequential forward with no deletions, additions, or multiple references). This should be your first choice in programming. Works efficiently with both ArrayList and LinkedList.
    ArrayList<String> a = new ArrayList<String>();
    . . .
    for (String s : a) {
        System.out.println(s);
    }
  2. for loop with index. This is fast, but should not be used with a LinkedList. It does allow orders other than sequentially forward by one.
    for (int i = 0; i < a.size(); i++) {
        System.out.println(a.get(i));
    }
  3. Iterator<E> - Allows simple forward traversal. Can be used for the largest number of other kinds of data structures.

    This example uses an Iterator to print all elements (Strings) in an ArrayList. It uses hasNext(), which returns true if there are more elements, and next(), which returns the next element. Works with both ArrayList and LinkedList.

    for (Iterator<String> iter = a.iterator(); iter.hasNext();  ) {
        System.out.println(iter.next());
    }
  4. ListIterator<E> - Allows traversal of the ArrayList, but it is more general than a simple Iterator, allowing inserts and deletes (although both are very slow for an ArrayList). It also allows bidirectional traversal. Works efficiently with both ArrayList and LinkedList.

Sorting

If the data in your ArrayList has a natural sorting order (ie, implements Comparable, as do String, Integer, ...), you can simply call the static Collections.sort() method. This is a stable, guaranteed n log n sort.

Collections.sort(yourArrayList);

If you want to choose a different sort criterion or your data doesn't implement xxxx, you will have to define a Comparator and pass that to the sort() method.

Collections.sort(yourArrayList, yourComparator);

Check out Collections for other useful utility methods.

下面是一个完整的例子:

复制代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
  
/**
* 老紫竹JAVA提高教程(7)-认识List列表之ArrayList<br>
* 
* @author 老紫竹 JAVA世纪网(java2000.net)
* 
*/
public class Lession7 {
  
 public static void main(String[] args) {
  testNormal();
  testSpecial();
  // 一个最常见的错误
  testForProblem();
 }
  
 public static void testNormal() {
  // -------------------------------------------------------
  // 声明一个列表
  // 允许放入任何数据
  // -------------------------------------------------------
  ArrayList list = new ArrayList();
  // 放入整数
  // 当然你用 new Integer(1)也可以
  list.add(1);
  // 放入字符串
  list.add("abc");
  // 放入浮点数
  list.add(new Float(1.11));
  // add会将数据保存到列表的尾部
  showList(list); // 1, abc, 1.11]
  
  // 下面我们在列表的头部增加数据
  list.add(0, 2);
  list.add(0, "bcd");
  list.add(0, new Double(2.34));
  // 列表可以指定插入的位置
  // 0 是头部第一个位置,所以数据都逐个放到最前面了
  showList(list); // [2.34, bcd, 2, 1, abc, 1.11]
  
  // 下面我们插入到我们希望的任何位置
  // 当然不能越界,(0 到 list.size()-1)范围内才可以
  list.add(1, 3);
  list.add(4, "xyz");
  // 数据被放到了正确的位置
  showList(list); // [2.34, 3, bcd, 2, xyz, 1, abc, 1.11]
  
  // -------------------------------------------------------
  // 我们有了数据,我们来测试读取数据
  // -------------------------------------------------------
  // 我们可以通过指定索引的位置,来拿到我们希望的数据
  System.out.println(list.get(0)); // 2.34
  System.out.println(list.get(4)); // xyz
  
  // -------------------------------------------------------
  // 测试是否存在某个数据
  // -------------------------------------------------------
  System.out.println(list.contains("xyz")); // true
  
  // 测试是否包含一组数据
  Collection c = new ArrayList();
  c.add(1);
  c.add(2);
  System.out.println(list.containsAll(c)); // true
  c.add(3);
  c.add(4);
  // containsAll_1234=false
  System.out.println(list.containsAll(c)); // false
  
  // -------------------------------------------------------
  // 查找某个数据所在的索引位置
  // 如果不存在,返回-1
  // -------------------------------------------------------
  System.out.println(list.indexOf(3)); // 1
  System.out.println(list.indexOf("xyz")); // 4
  System.out.println(list.indexOf("abcd")); // -1
  
  // -------------------------------------------------------
  // 测试删除数据
  // 请注意,
  // 如果你使用整数(int)数字,则默认调用的是remove(int index);
  // 如果你用 long,则会调用 remove(Object obj);
  // 所以如果你要删除整数,请使用 remove(new Integer(int));
  // -------------------------------------------------------
  // 删除索引为1的数据
  list.remove(1);
  // 索引为1的数据被干掉了
  showList(list); // [2.34, bcd, 2, xyz, 1, abc, 1.11]
  
  // 删除数字1 和字符串 abc
  list.remove(new Integer(1));
  list.remove("xyz");
  showList(list); // [2.34, bcd, 2, abc, 1.11]
  
  // -------------------------------------------------------
  // 迭代器的使用
  // -------------------------------------------------------
  Iterator it = list.iterator();
  while (it.hasNext()) {
   System.out.print(it.next() + " "); // 2.34 bcd 2 abc 1.11
  }
  System.out.println();
  
  // -------------------------------------------------------
  // 转化为数组
  // -------------------------------------------------------
  Object[] objs = list.toArray();
  for (Object obj : objs) {
   System.out.print(obj + " "); // 2.34 bcd 2 abc 1.11
  }
  System.out.println();
 }
  
 public static void testSpecial() {
  // -------------------------------------------------------
  // 测试重复和null
  // -------------------------------------------------------
  //
  List<Integer> list = new ArrayList<Integer>();
  list.add(123);
  list.add(456);
  list.add(123);
  list.add(456);
  // 数据允许重复
  showList(list); // [123, 456, 123, 456]
  
  list.add(null);
  list.add(789);
  list.add(null);
  list.add(999);
  // 允许放入多个null
  showList(list); // [123, 456, 123, 456, null, 789, null, 999]
  
  // -------------------------------------------------------
  // 测试一下查找最后一次出现的位置
  // -------------------------------------------------------
  System.out.println(list.indexOf(123)); // 0
  System.out.println(list.lastIndexOf(123)); // 2
  
  // -------------------------------------------------------
  // 转化为数组
  // 记得要转化为Inerger.
  // -------------------------------------------------------
  Integer[] nums = (Integer[]) list.toArray(new Integer[0]);
  // 注意数据里面有null,所以循环变量不要用int 要用Integer
  for (Integer num : nums) {
   System.out.print(num + " "); // 123 456 123 456 null 789 null 999
  }
  System.out.println();
  
 }
  
 public static void testForProblem() {
  // 一些朋友在向循环里向列表增加对象的时候
  // 经常忘记初始化,造成最终加入的都是同一个对象
  List<MyObject> list = new ArrayList<MyObject>();
  MyObject obj = new MyObject();
  for (int i = 1; i <= 5; i++) {
   obj.setName("Name" + i);
   list.add(obj);
  }
  // 里面的数据都是最后一个
  showList(list); // [Name5, Name5, Name5, Name5, Name5]
  
  // 正确的做法
  List<MyObject> list2 = new ArrayList<MyObject>();
  MyObject obj2 = null;
  for (int i = 1; i <= 5; i++) {
   obj2 = new MyObject();
   obj2.setName("Name" + i);
   list2.add(obj2);
  }
  // 里面的数据都是最后一个
  showList(list2); // [Name1, Name2, Name3, Name4, Name5]
 }
  
 /**
  * 显示List里面的数据。
  * 
  * @param list
  */
 private static void showList(List list) {
  System.out.println(Arrays.toString(list.toArray()));
 }
}
  
class MyObject {
 private String name;
  
 public String getName() {
  return name;
 }
  
 public void setName(String name) {
  this.name = name;
 }
  
 /**
  * 重写toString方法,输出name
  */
 public String toString() {
  return name;
 }
}
复制代码

输出:

复制代码
[1, abc, 1.11]
[2.34, bcd, 2, 1, abc, 1.11]
[2.34, 3, bcd, 2, xyz, 1, abc, 1.11]
2.34
xyz
true
true
false
1
4
-1
[2.34, bcd, 2, xyz, 1, abc, 1.11]
[2.34, bcd, 2, abc, 1.11]
2.34 bcd 2 abc 1.11
2.34 bcd 2 abc 1.11
[123, 456, 123, 456]
[123, 456, 123, 456, null, 789, null, 999]
0
2
123 456 123 456 null 789 null 999
[Name5, Name5, Name5, Name5, Name5]
[Name1, Name2, Name3, Name4, Name5]
复制代码

 

 

 

 


先从上图了解一下什么是双循环链表,什么是源码中的header。
LinkedList就是一个实现了双循环链表的类。

Java代码 复制代码  收藏代码
  1. // 其构造函数,已完成了前驱结点和后继结点的指向工作   
  2.     private static class Entry<E> {   
  3.     E element;   
  4.     Entry<E> next;   
  5.     Entry<E> previous;   
  6.   
  7.     Entry(E element, Entry<E> next, Entry<E> previous) {   
  8.         this.element = element;   
  9.         this.next = next;   
  10.         this.previous = previous;   
  11.     }   
  12.     }   
  13.   
  14.   
  15.     private Entry<E> addBefore(E o, Entry<E> e) {   
  16. // newEntry的后继节点指向e,前驱结点指向节点e的前一个节点   
  17. // 换句话说,newEntry完成了自身的节点初始化工作   
  18. // 将节点newEntry插入到节点e和节点e的前一个节点之间   
  19.     Entry<E> newEntry = new Entry<E>(o, e, e.previous);   
  20. // 双向链表由前区节点和后继节点共同完成   
  21. // 改变newEntry前后节点的指针指向,使其指向newEntry   
  22.     newEntry.previous.next = newEntry;   
  23.     newEntry.next.previous = newEntry;   
  24.     size++;   
  25.     modCount++;   
  26.     return newEntry;   
  27.     }  
// 其构造函数,已完成了前驱结点和后继结点的指向工作
    private static class Entry<E> {
	E element;
	Entry<E> next;
	Entry<E> previous;

	Entry(E element, Entry<E> next, Entry<E> previous) {
	    this.element = element;
	    this.next = next;
	    this.previous = previous;
	}
    }


    private Entry<E> addBefore(E o, Entry<E> e) {
// newEntry的后继节点指向e,前驱结点指向节点e的前一个节点
// 换句话说,newEntry完成了自身的节点初始化工作
// 将节点newEntry插入到节点e和节点e的前一个节点之间
	Entry<E> newEntry = new Entry<E>(o, e, e.previous);
// 双向链表由前区节点和后继节点共同完成
// 改变newEntry前后节点的指针指向,使其指向newEntry
	newEntry.previous.next = newEntry;
	newEntry.next.previous = newEntry;
	size++;
	modCount++;
	return newEntry;
    }


关于随机访问:
Java代码 复制代码  收藏代码
  1.        
  2. //LinkedList中获取元素方法   
  3. private Entry<E> entry(int index) {   
  4.         if (index < 0 || index >= size)   
  5.             throw new IndexOutOfBoundsException("Index: "+index+   
  6.                                                 ", Size: "+size);   
  7.         Entry<E> e = header;   
  8.         if (index < (size >> 1)) {   
  9.             for (int i = 0; i <= index; i++)   
  10.                 e = e.next;   
  11.         } else {   
  12.             for (int i = size; i > index; i--)   
  13.                 e = e.previous;   
  14.         }   
  15.         return e;   
  16.     }  
    
//LinkedList中获取元素方法
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;
    }

随机访问是指访问某个元素时,可直接找到其相应位置,如通过下标直接访问数组中元素。
与随机访问相对的是顺序访问,必须通过挨个访问相邻元素,才能获取到所需元素,如上述linkedlist类。
现实生活中,磁带就是顺序访问,磁盘就是随机访问。

 

 

Java中LinkedList类详解

分类: Java 5430人阅读 评论(0) 收藏 举报

LinkedList的使用例子:

  1. import java.util.*;  
  2.   
  3. public class LinkedListDemo {  
  4.       
  5.     public static void main(String []args){  
  6.           
  7.         LinkedList  list = new LinkedList();  
  8.           
  9.         list.add("one");  
  10.         list.add("two");  
  11.         list.add("three");        
  12.         System.out.println("<--list中共有 :" + list.size() + "个元素-->");  
  13.         System.out.println("<--list中的内容 :" + list + "-->");  
  14.           
  15.         String first = (String) list.getFirst();  
  16.         String last = (String) list.getLast();  
  17.         System.out.println("<--list中第一个元素为 :" + first + "-->");  
  18.         System.out.println("<--list中最后一个元素为 :" + last + "-->");  
  19.           
  20.         list.addFirst("Begin");  
  21.         list.addLast("End");  
  22.         System.out.println("<--list中共有 :" + list.size() + "个元素-->");  
  23.         System.out.println("<--list中的内容 :" + list + "-->");  
  24.           
  25.         System.out.println("<--使用ListIterator接口操作list-->");  
  26.         ListIterator lit = list.listIterator();  
  27.         System.out.println("<--下一个索引是"+ lit.nextIndex()+ "-->");  
  28.         lit.next();  
  29.         lit.add("zero");  
  30.         lit.previous();  
  31.         System.out.println("<--上一个索引是"+ lit.previousIndex()+ "-->");        
  32.         lit.previous();  
  33.         System.out.println("<--上一个索引是"+ lit.previousIndex()+ "-->");  
  34.         lit.set("Start");  
  35.         System.out.println("<--list中的内容 :" + list + "-->");  
  36.           
  37.         System.out.println("<--删除list中的zero-->");  
  38.         lit.next();  
  39.         lit.next();  
  40.         lit.remove();  
  41.         System.out.println("<--list中的内容 :" + list + "-->");  
  42.           
  43.           
  44.         System.out.println("<--删除list中的第一个和最后一个元素-->");  
  45.         list.removeFirst();  
  46.         list.removeLast();  
  47.           
  48.         System.out.println("<--list中共有 :" + list.size() + "个元素-->");  
  49.         System.out.println("<--list中的内容 :" + list + "-->");         
  50.     }  
  51.   
  52. }  
import java.util.*;

public class LinkedListDemo {
	
	public static void main(String []args){
		
		LinkedList  list = new LinkedList();
		
		list.add("one");
		list.add("two");
		list.add("three");		
		System.out.println("<--list中共有 :" + list.size() + "个元素-->");
		System.out.println("<--list中的内容 :" + list + "-->");
		
		String first = (String) list.getFirst();
		String last = (String) list.getLast();
		System.out.println("<--list中第一个元素为 :" + first + "-->");
		System.out.println("<--list中最后一个元素为 :" + last + "-->");
		
		list.addFirst("Begin");
		list.addLast("End");
		System.out.println("<--list中共有 :" + list.size() + "个元素-->");
		System.out.println("<--list中的内容 :" + list + "-->");
		
		System.out.println("<--使用ListIterator接口操作list-->");
		ListIterator lit = list.listIterator();
		System.out.println("<--下一个索引是"+ lit.nextIndex()+ "-->");
		lit.next();
		lit.add("zero");
		lit.previous();
		System.out.println("<--上一个索引是"+ lit.previousIndex()+ "-->");		
		lit.previous();
		System.out.println("<--上一个索引是"+ lit.previousIndex()+ "-->");
		lit.set("Start");
		System.out.println("<--list中的内容 :" + list + "-->");
		
		System.out.println("<--删除list中的zero-->");
		lit.next();
		lit.next();
		lit.remove();
		System.out.println("<--list中的内容 :" + list + "-->");
		
		
		System.out.println("<--删除list中的第一个和最后一个元素-->");
		list.removeFirst();
		list.removeLast();
		
		System.out.println("<--list中共有 :" + list.size() + "个元素-->");
		System.out.println("<--list中的内容 :" + list + "-->");		
	}

}

打印结果:

  1. <--list中共有 :3个元素-->  
  2. <--list中的内容 :[one, two, three]-->  
  3. <--list中第一个元素为 :one-->  
  4. <--list中最后一个元素为 :three-->  
  5. <--list中共有 :5个元素-->  
  6. <--list中的内容 :[Begin, one, two, three, End]-->  
  7. <--使用ListIterator接口操作list-->  
  8. <--下一个索引是0-->  
  9. <--上一个索引是0-->  
  10. <--上一个索引是-1-->  
  11. <--list中的内容 :[Start, zero, one, two, three, End]-->  
  12. <--删除list中的zero-->  
  13. <--list中的内容 :[Start, one, two, three, End]-->  
  14. <--删除list中的第一个和最后一个元素-->  
  15. <--list中共有 :3个元素-->  
  16. <--list中的内容 :[one, two, three]-->  

 

 

 

一般大家都知道ArrayList和LinkedList的大致区别:
     1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
     2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
     3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

ArrayList和LinkedList是两个集合类,用于存储一系列的对象引用(references)。例如我们可以用ArrayList来存储一系列的String或者Integer。那么ArrayList和LinkedList在性能上有什么差别呢?什么时候应该用ArrayList什么时候又该用LinkedList呢?


一.时间复杂度
首先一点关键的是,ArrayList的内部实现是基于基础的对象数组的,因此,它使用get方法访问列表中的任意一个元素时(random access),它的速度要比LinkedList快。LinkedList中的get方法是按照顺序从列表的一端开始检查,直到另外一端。对LinkedList而言,访问列表中的某个指定元素没有更快的方法了。
假设我们有一个很大的列表,它里面的元素已经排好序了,这个列表可能是ArrayList类型的也可能是LinkedList类型的,现在我们对这个列表来进行二分查找(binary search),比较列表是ArrayList和LinkedList时的查询速度,看下面的程序:

Java代码 复制代码   收藏代码
  1. package com.mangocity.test;    
  2. import java.util.LinkedList;    
  3. import java.util.List;    
  4. import java.util.Random;    
  5. import java.util.ArrayList;    
  6. import java.util.Arrays;    
  7. import java.util.Collections;    
  8. public class TestList ...{    
  9.      public static final int N=50000;    
  10.   
  11.      public static List values;    
  12.   
  13.      static...{    
  14.          Integer vals[]=new Integer[N];    
  15.   
  16.          Random r=new Random();    
  17.   
  18.          for(int i=0,currval=0;i<N;i++)...{    
  19.              vals=new Integer(currval);    
  20.              currval+=r.nextInt(100)+1;    
  21.          }    
  22.   
  23.          values=Arrays.asList(vals);    
  24.      }    
  25.   
  26.      static long timeList(List lst)...{    
  27.          long start=System.currentTimeMillis();    
  28.          for(int i=0;i<N;i++)...{    
  29.              int index=Collections.binarySearch(lst, values.get(i));    
  30.              if(index!=i)    
  31.                  System.out.println("***错误***");    
  32.          }    
  33.          return System.currentTimeMillis()-start;    
  34.      }    
  35.      public static void main(String args[])...{    
  36.          System.out.println("ArrayList消耗时间:"+timeList(new ArrayList(values)));    
  37.          System.out.println("LinkedList消耗时间:"+timeList(new LinkedList(values)));    
  38.      }    
  39. }   
package com.mangocity.test; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Random; 
import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Collections; 
public class TestList ...{ 
     public static final int N=50000; 

     public static List values; 

     static...{ 
         Integer vals[]=new Integer[N]; 

         Random r=new Random(); 

         for(int i=0,currval=0;i<N;i++)...{ 
             vals=new Integer(currval); 
             currval+=r.nextInt(100)+1; 
         } 

         values=Arrays.asList(vals); 
     } 

     static long timeList(List lst)...{ 
         long start=System.currentTimeMillis(); 
         for(int i=0;i<N;i++)...{ 
             int index=Collections.binarySearch(lst, values.get(i)); 
             if(index!=i) 
                 System.out.println("***错误***"); 
         } 
         return System.currentTimeMillis()-start; 
     } 
     public static void main(String args[])...{ 
         System.out.println("ArrayList消耗时间:"+timeList(new ArrayList(values))); 
         System.out.println("LinkedList消耗时间:"+timeList(new LinkedList(values))); 
     } 
} 

 
我得到的输出是:ArrayList消耗时间:15
                 LinkedList消耗时间:2596
这个结果不是固定的,但是基本上ArrayList的时间要明显小于LinkedList的时间。因此在这种情况下不宜用LinkedList。二分查找法使用的随机访问(random access)策略,而LinkedList是不支持快速的随机访问的。对一个LinkedList做随机访问所消耗的时间与这个list的大小是成比例的。而相应的,在ArrayList中进行随机访问所消耗的时间是固定的。
这是否表明ArrayList总是比LinkedList性能要好呢?这并不一定,在某些情况下LinkedList的表现要优于ArrayList,有些算法在LinkedList中实现时效率更高。比方说,利用Collections.reverse方法对列表进行反转时,其性能就要好些。
看这样一个例子,加入我们有一个列表,要对其进行大量的插入和删除操作,在这种情况下LinkedList就是一个较好的选择。请看如下一个极端的例子,我们重复的在一个列表的开端插入一个元素:

Java代码 复制代码   收藏代码
  1. package com.mangocity.test;    
  2.   
  3. import java.util.*;    
  4. public class ListDemo {    
  5.      static final int N=50000;    
  6.      static long timeList(List list){    
  7.      long start=System.currentTimeMillis();    
  8.      Object o = new Object();    
  9.      for(int i=0;i<N;i++)    
  10.          list.add(0, o);    
  11.      return System.currentTimeMillis()-start;    
  12.      }    
  13.      public static void main(String[] args) {    
  14.          System.out.println("ArrayList耗时:"+timeList(new ArrayList()));    
  15.          System.out.println("LinkedList耗时:"+timeList(new LinkedList()));    
  16.      }    
  17. }   
package com.mangocity.test; 

import java.util.*; 
public class ListDemo { 
     static final int N=50000; 
     static long timeList(List list){ 
     long start=System.currentTimeMillis(); 
     Object o = new Object(); 
     for(int i=0;i<N;i++) 
         list.add(0, o); 
     return System.currentTimeMillis()-start; 
     } 
     public static void main(String[] args) { 
         System.out.println("ArrayList耗时:"+timeList(new ArrayList())); 
         System.out.println("LinkedList耗时:"+timeList(new LinkedList())); 
     } 
} 

 这时我的输出结果是:ArrayList耗时:2463


                           LinkedList耗时:15
这和前面一个例子的结果截然相反,当一个元素被加到ArrayList的最开端时,所有已经存在的元素都会后移,这就意味着数据移动和复制上的开销。相反的,将一个元素加到LinkedList的最开端只是简单的未这个元素分配一个记录,然后调整两个连接。在LinkedList的开端增加一个元素的开销是固定的,而在ArrayList的开端增加一个元素的开销是与ArrayList的大小成比例的。


二.空间复杂度
在LinkedList中有一个私有的内部类,定义如下:

Java代码 复制代码   收藏代码
  1. private static class Entry {    
  2.          Object element;    
  3.          Entry next;    
  4.          Entry previous;    
  5.      }   
private static class Entry { 
         Object element; 
         Entry next; 
         Entry previous; 
     } 

 
每个Entry对象reference列表中的一个元素,同时还有在LinkedList中它的上一个元素和下一个元素。一个有1000个元素的LinkedList对象将有1000个链接在一起的Entry对象,每个对象都对应于列表中的一个元素。这样的话,在一个LinkedList结构中将有一个很大的空间开销,因为它要存储这1000个Entity对象的相关信息。
ArrayList使用一个内置的数组来存储元素,这个数组的起始容量是10.当数组需要增长时,新的容量按如下公式获得:新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%。这就意味着,如果你有一个包含大量元素的ArrayList对象,那么最终将有很大的空间会被浪费掉,这个浪费是由ArrayList的工作方式本身造成的。如果没有足够的空间来存放新的元素,数组将不得不被重新进行分配以便能够增加新的元素。对数组进行重新分配,将会导致性能急剧下降。如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间。


三.总结
ArrayList和LinkedList在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:
1.对ArrayList和LinkedList而言,在列表末尾增加一个元素所花的开销都是固定的。对ArrayList而言,主要是在内部数组中增加一项,指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对LinkedList而言,这个开销是统一的,分配一个内部Entry对象。


2.在ArrayList的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在LinkedList的中间插入或删除一个元素的开销是固定的。


3.LinkedList不支持高效的随机元素访问。


4.ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间


可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用ArrayList会提供比较好的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用LinkedList了。

 

 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值