LinkedList部分源码分析(双链表)

LinkedList就是双链表的数据结构,所以主要复习下双链表的插入、删除和查找

1、结点类

结点类是LinkedList类的静态内部类,包括指向上一个结点的prev引用、指向下一个结点的next引用和数据域item。构造函数也是初始化这三个参数。

	private static class Node<E>{
		E item;
		Node<E> prev;
		Node<E> next;
		
		Node(Node<E> prev,E element,Node<E> next){
			this.item = element;
			this.prev = prev;
			this.next = next;
		}
	}

2、LinkedList中的某些域

这里只写了表示LinkedList大小的size、指向最后一个结点的last引用和指向第一个结点的first引用

	private int size = 0;	//链表元素个数
	private Node last;	//指向最后一个结点
	private Node first;	//指向首元结点

3、LinkedList的插入结点操作

(1)在链表头插入一个元素,在链表尾插入元素与之相似

注意考虑链表本来就没有元素的情况

	/**
	 *  在链表头插入一个元素e
	 * @param e
	 */
	private void linkFirst(E e) {
		Node<E> f = first;	//初始化f,使其指向首元结点,如果链表为空,则f==first==null
		Node<E> newNode = new Node<>(null,e,f);
	//新建一个newNode结点,newNode结点的next引用指向原来的首元结点,此时该结点成为新的首元结点
		first = newNode;	//first引用指向新的首元结点
		if(f == null)
			last = newNode;//如果f==null则表示newNode是第一个创建的结点,此时最后一个元素也就是 
                           //第一个元素,last指向最后一个元素
		else
			f.prev = newNode;	//如果f!=null则表示链表之前就有元素,并且f指向的是旧的首元结点, 
                                //使旧首元结点的prev引用指向新首元结点
		size++;				//插入了元素,链表长度变化
//		modCount++;
	}

(2)在链表尾插入元素

/**
	 * 在链表尾插入一个元素,操作与linkFirst类似
	 * @param e
	 */
	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++;
//		modCount++;
	}

(3)在某个非空结点前插入一个元素

	/**
	 * 在结点succ(确保非空)前插入元素e
	 * @param e
	 * @param succ
	 */
	void linkBefore(E e,Node<E> succ) {
        //succ为空会抛出空指针异常,使用succ结点的prev引用初始化pred,此时pred指向succ的前一个结点
		final Node<E> pred = succ.prev;	
        //创建一个新节点,并且使其prev指向succ的前一个结点,next指向succ
		final Node<E> newNode = new Node<>(pred,e,succ);
		succ.prev = newNode; //将succ的prev指向新的结点,此时新结点成为succ的前一个结点
		if(pred == null)	//pred为空即succ为首元结点,则first指向新结点
			first = newNode;
		else
			pred.next = newNode;
		size++;
//		modCount++;
	}

4、LinkedList结点删除操作

(1)删除第一个结点(确保非空),并返回它的值

	/**
	 * 删除第一个结点(非空),并返回其数据值,传给该函数的参数一般为first
     * 当链表只有一个结点时,first和last指向的是同一个结点
	 * @param f
	 * @return
	 */
	private E unlinkFirst(Node<E> f) {
		final E element= f.item;  //element为返回值
		final Node<E> next = f.next;  //使next指向f的下一个结点
		first = next;  //第一个元素删除后要使first指向之前的第二个元素
		f.item = null;  //这里相当于将item和next引用设为空,有助垃圾回收机制回收内存
		f.next = null;
		
		if(next == null)  //如果next为空则表示元链表只有一个元素
			last = null;  //last原本指向的是要删除的那一个元素,所删除后要将last指向空
		else
			next.prev = null;
		size--;
//		modCount++;
		return element;
	}

(2)删除最后一个结点(确保非空)并返回其值

    /**
	 * 删除最后一个结点l(确保非空),并返回结点的数据值
	 * @param l
	 * @return
	 */
	private E unlinkLast(Node<E> l) {
		final E element = l.item;	//获取结点l的数据值
		final Node<E> prev = l.prev;//l的前一个结点引用
	    l.item = null;				
		l.prev = null;				//帮助垃圾回收
		last = prev;				//将旧尾结点的引用指向前一个结点
		if(prev == null) 			//如果最后一个结点 l 也是首元结点,即只有一个结点
			first = null;			//则将首元结点引用指向空(此时链表中已经没有结点了)
		else
			prev.next = null;		//如果l不是唯一的结点,则将新尾节的next设为空
		size--;
		return element;
			
	}

(3)删除指定的结点并返回其值

   /**
	 * 删除某一个结点x(确保非空),并返回结点数据值
	 * @param x
	 * @return 
	 */
	E unlink(Node<E> x) {
		final E element = x.item;	//取得结点x的数据值
		final Node<E> prev = x.prev;
		final Node<E> next = x.next;

		//如果x为首元结点,则将first引用指向下一个结点(x删除后x的下一个结点为首元结点)
		if(x.prev == null) {		
			first = next;
		}else {						//否则将x前一个结点的next指向x的下一个结点
			prev.next = next;
			x.prev = null;			//帮助垃圾回收
		}
		
		if(next == null) {			//如果x为尾结点,则将last指向x的前一个结点
			last = prev;
		}else {						//否则将x的下一个结点的prev引用指向x的前一个结点
			next.prev = prev;
			x.next = null;			//设为空,帮助垃圾回收
		}
		x.item = null;				//设为空,帮助垃圾回收
		size--;
//		modCount++;
		return element;
	}

上面的这几个方法并不是完全对外暴露的接口,但是常用的那些方法实际上都是调用的这些方法,如下

/**
	 * 返回链表第一个元素值,链表中无元素则抛出异常
	 * @return
	 */
	public E getFirst() {
		final Node<E> f = first;
		if(f == null){
			throw new NoSuchElementException();
		}
		return f.item;
	}
	
	/**
	 * 返回链表最后一个元素值,链表中无元素则抛出异常
	 * @return
	 */
	public E getLast() {
		final Node<E> l =last;
		if(l == null) {
			throw new NoSuchElementException();
		}
		return l.item;
	}
	
	/**
	 *   删除第一元素并返回数据值 
	 * @return
	 */
	public E removeFirst() {
		final Node<E> f = first;
		if(f == null)
			throw new NoSuchElementException();
		return unlinkFirst(f);
	}
	
	/**
	 * 删除最后一个元素并返回值
	 * @return
	 */
	public E removeLast() {
		final Node<E> l = last;
		if(l == null)
			throw new NoSuchElementException();
		return unlinkLast(l);
	}
	
	/**
	 *  删除指定元素,顺在链表查找,找到了就删除
	 */
	public boolean remove(Object o) {
		if(o == 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;
	}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值