经常被问到的那些JCF——ArrayList和LinkedList(二)

LinkedList:

继续源码+我个人理解:

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
    private transient Entry<E> header = new Entry<E>(null, null, null);
    private transient int size = 0;

    /**
     * Constructs an empty list.
     */
    public LinkedList() {
        header.next = header.previous = header;
    }

   
    public LinkedList(Collection<? extends E> c) {
	this();
	addAll(c);
    }
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;
	}
    }
LinkedList->链表实现的:内部类Entry,包含element,以及它的前继和后继的指针。还有一个size属性,和arrayList差不多。继承的是AbstractSequenceList。

两个构造函数:一个无参一个有参(collection):无参构造函数,初始化链表的头节点;有参构造函数也是初始化头节点,并将collection中的元素添加到链表中。

public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

public boolean addAll(int index, Collection<? extends E> c) {
		if (index < 0 || index > size)
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: "
					+ size);
		Object[] a = c.toArray();
		int numNew = a.length;
		if (numNew == 0)
			return false;
		modCount++;

		Entry<E> successor = (index == size ? header : entry(index));
		Entry<E> predecessor = successor.previous;
		for (int i = 0; i < numNew; i++) {
			Entry<E> e = new Entry<E>((E) a[i], successor, predecessor);
			predecessor.next = e;
			predecessor = e;
		}
		successor.previous = predecessor;

		size += numNew;
		return true;
	}

这就是将一个数组的元素依序插入到链表中的操作!

下面看一些常用的method:

	public E getFirst() {
		if (size == 0)
			throw new NoSuchElementException();

		return header.next.element;
	}

	/**
	 * Returns the last element in this list.
	 */
	public E getLast() {
		if (size == 0)
			throw new NoSuchElementException();

		return header.previous.element;
	}

	/**
	 * Removes and returns the first element from this list.
	
	 */
	public E removeFirst() {
		return remove(header.next);
	}

	/**
	 * Removes and returns the last element from this list.
	
	 */
	public E removeLast() {
		return remove(header.previous);
	}

	/**
	 * Inserts the specified element at the beginning of this list.
	 */
	public void addFirst(E e) {
		addBefore(e, header.next);
	}

	/**
	 * Appends the specified element to the end of this list.
	 */
	public void addLast(E e) {
		addBefore(e, header);
	}

	
	public boolean contains(Object o) {
		return indexOf(o) != -1;
	}

	/**
	 * Returns the number of elements in this list.
	 * 
	 * @return the number of elements in this list
	 */
	public int size() {
		return size;
	}

	
	public boolean add(E e) {
		addBefore(e, header);
		return true;
	}

	
	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 {
			for (Entry<E> e = header.next; e != header; e = e.next) {
				if (o.equals(e.element)) {
					remove(e);
					return true;
				}
			}
		}
		return false;
	}

	private Entry<E> addBefore(E e, Entry<E> entry) {
		Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
		newEntry.previous.next = newEntry;
		newEntry.next.previous = newEntry;
		size++;
		modCount++;
		return newEntry;
	}

	private E remove(Entry<E> e) {
		if (e == header)
			throw new NoSuchElementException();

		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;
	}
/**
	 * Returns the index of the first occurrence of the specified element in
	 * this list, or -1 if this list does not contain the element
	 */
	public int indexOf(Object o) {
		int index = 0;
		if (o == null) {
			for (Entry e = header.next; e != header; e = e.next) {
				if (e.element == null)
					return index;
				index++;
			}
		} else {
			for (Entry e = header.next; e != header; e = e.next) {
				if (o.equals(e.element))
					return index;
				index++;
			}
		}
		return -1;
	}
这些代码很好理解。不过这里也显示出一个问题:这个链表是个循环链表!

看method  getLast和removeLast:他们把最后一个节点表示为:header.pre,再结合有参构造函数来看,其最终实现的链表就是一个循环链表。

接下来的一些方法都是一些逻辑比较简单的链表操作。就不贴了。

不过它内部还实现了一个自己的迭代器,是通过私有内部类来实现的。有兴趣可以自己去看。


它的get(int index)方法。内部直接调用的时候Entry<E> entry(int index)方法:

	/**
	 * Returns the indexed entry.
	 */
	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;
	}
这里不是采用的从前往后的顺序进行遍历,直接2分,如果index<size的一半就从前开始查找,否则就最后一个往前开始查找。这里的size>>1  == size/2;
public void add(int index, E element) {
		addBefore(element, (index == size ? header : entry(index)));
	}
add方法:这句代码真简洁!



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值