Java-集合框架Collection之List(二)
2016-01-30 21:26
676 查看
List接口的实现类LinkedList
LinkedList类是List接口中另一个常用的类,它的本质是是一个双向链表,也常可以当作堆栈、队列或这双端队列,所以在随机插入、随机删除时比ArrayList类的效率要高。
LinkedList源码分析:
LinkedList属性:transient int size = 0;//初始大小为0 //transient(临时的,短暂的)作用:因为LinkedList类实现了Serializable接口序列化, //这个类的属性和方法都会自动序列化,而有些属性为了安全,不被序列化,需要用transient修饰 /** * Pointer to first node. * Invariant: (first == null && last == null) || * (first.prev == null && first.item != null) */ transient Node<E> first;//定义了一个结点指向LinkedList的第一个结点 /** * Pointer to last node. * Invariant: (first == null && last == null) || * (last.next == null && last.item != null) */ transient Node<E> last;//定义一个结点指向LinkedList的最后一个结点 //Node的数据结构 private static class Node<E> { E item; Node<E> next; Node<E> prev; Node(Node<E> prev, E element, Node<E> next) { this.item = element;//当前结点元素的内容 this.next = next;//相当于指针,指向下一个结点的地址 this.prev = prev;//相当于指针,指向上一个结点的地址 } }
LinkedList构造方法:
/*空的链表*/ public LinkedList() { } public LinkedList(Collection<? extends E> c) { this(); addAll(c); } public boolean addAll(Collection<? extends E> c) { return addAll(size, c); } public boolean addAll(int index, Collection<? extends E> c) { checkPositionIndex(index);//判断插入的元素的位置是否超过链表长度或小于0 Object[] a = c.toArray(); int numNew = a.length;//先获得需要插入的元素的个数 if (numNew == 0) return false;//如果插入的元素个数为0返回false Node<E> pred, succ; if (index == size) {//插入元素的位置在链表的最后 succ = null; pred = last; } else {//记录插入的元素位置 succ = node(index);//这个方法只在这个构造方法里调用了一次, //在其他成员方法里没有调用,即要把多个元素一次性放入LinedList对象时,只能在初始化的时候传入Collection对象 pred = succ.prev; } /*插入元素*/ for (Object o : a) { @SuppressWarnings("unchecked") E e = (E) o; Node<E> newNode = new Node<>(pred, e, null); if (pred == null) first = newNode;//插入的元素是第一个 else pred.next = newNode;//下一个元素指向插入的元素 pred = newNode;//前一个元素也指向插入的元素,这也证明了这是一个双向链表 } /*链表后移,链表长度加上添加元素的个数*/ if (succ == null) { last = pred; } else { pred.next = succ; succ.prev = pred; } size += numNew; modCount++;//记录链表结构变化次数 return true; } private void checkPositionIndex(int index) { if (!isPositionIndex(index)) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } private boolean isPositionIndex(int index) { return index >= 0 && index <= size;//判断是否大于等于0且不大于size } 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; }
添加元素:
/*不指定插入元素的位置*/ public boolean add(E e) { linkLast(e); return true; } void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null);//在链表最后放入要插入的元素 last = newNode;//链表的最后一个元素指向插入元素的新结点 if (l == null) first = newNode;//前一个元素指向自身 else l.next = newNode;//下一个元素指向自身 size++;//链表长度+1 modCount++; } /*在链表指定的位置插入元素*/ public void add(int index, E element) { checkPositionIndex(index);//检测插入元素的位置 if (index == size) linkLast(element);//链表的末尾位置 else linkBefore(element, node(index));//链表中除了末尾的位置 } void linkBefore(E e, Node<E> succ) { //assert succ != null; final Node<E> pred = succ.prev; final Node<E> newNode = new Node<>(pred, e, succ); succ.prev = newNode; if (pred == null) first = newNode; else pred.next = newNode; size++; modCount++; } /*指定位置插入元素*/ public E set(int index, E element) { checkElementIndex(index); Node<E> x = node(index); E oldVal = x.item; x.item = element; return oldVal; } /*在链表的第一个位置插入元素*/ private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
获取元素
LinkedList获取元素只有通过获得位置间接的获取这一种方法,不能通过元素的内容获取
/**获取链表中任意一个位置的元素*/ public E get(int index) { checkElementIndex(index); return node(index).item; } /**获取链表中第一个位置的元素*/ public E getFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return f.item; } /*获取链表中最后一个位置的元素*/ public E getLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return l.item; } /*判断是否包含某个元素*/ public boolean contains(Object o) { return indexOf(o) != -1; }
删除元素
/**根据位置移除链表元素*/ public E remove(int index) { checkElementIndex(index); return unlink(node(index)); } /**根据元素内容移除链表元素*/ public boolean remove(Object o) { if (o == null) { /*移除内容为null的元素*/ for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; } E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; //虽然被称为双向链表,但是也有区分第一个和最后一个。 /*前一个结点是否为空,即要删除的是否为第一个*/ if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } /*后一个结点是否为空,即要删除的结点是否为最后一个*/ if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--;//链表长度减去1 modCount++; return element; } /*移除第一个元素的结点 无返回值*/ public E removeFirst() { final Node<E> f = first; if (f == null) throw new NoSuchElementException(); return unlinkFirst(f); } /*移除链表第一个出现的元素o的结点 有返回值*/ public boolean removeFirstOccurrence(Object o) { return remove(o); } /*移除链表最后一个元素的结点 无返回值*/ public E removeLast() { final Node<E> l = last; if (l == null) throw new NoSuchElementException(); return unlinkLast(l); } /*移除链表最后一个出现的元素o的结点 有返回值*/ public boolean removeLastOccurrence(Object o) { if (o == null) { for (Node<E> x = last; x != null; x = x.prev) { if (x.item == null) { unlink(x); return true; } } } else { for (Node<E> x = last; x != null; x = x.prev) { if (o.equals(x.item)) { unlink(x); return true; } } } return false; } /*移除链表中所有的结点*/ public void clear() { // Clearing all of the links between nodes is "unnecessary", but: // - helps a generational GC if the discarded nodes inhabit // more than one generation // - is sure to free memory even if there is a reachable Iterator for (Node<E> x = first; x != null; ) { Node<E> next = x.next; x.item = null;//元素置为空 x.next = null;//下一个结点置为空 x.prev = null;//前一个结点置为空 x = next; } first = last = null; size = 0;//链表长度置为0 modCount++; }
总结
1、LinkedList基于链表,ArrayList基于数组,对于只是对数据的查询,ArrayList效率更高,如果需要频繁的对List中的数据插入和删除操作,链表的效率更高。2、LinkedList和ArrayList都是非线程同步,所以在多线程操作时候要添加线程锁。
(补充)
在ArrayList出现以前,在List中还有一个比较常用的类Vector,Vector在JDK1.0的时候就存在,到了Java2(JDK1.2)以后逐渐被ArrayList取代,在用法上并没有太大的区别。最大的区别就是Vector类是线程同步,ArrayList不是线程同步,所以Vector在性能上较低。Vector类用法:
Vector<String> vector = new Vector<String>(); vector.add("h"); vector.addElement("e"); vector.addElement("l"); vector.add("l"); vector.add("o"); Iterator<String> iterator = vector.iterator(); while(iterator.hasNext()){ System.out.print(iterator.next()); } System.out.println(); Enumeration<String> elements = vector.elements(); while(elements.hasMoreElements()){ System.out.print(elements.nextElement()); } System.out.println(); for (int i = 0; i < vector.size(); i++) { System.out.print(vector.elementAt(i)); }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 从源码安装Mysql/Percona 5.5
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- [C/C++]反转链表
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序