双链表

实现双向链表

               一、该链表类的各方法解释(最后在附上完整代码)

                   该链表有一个头指针head指向第一个结点,一个尾指针指向最后一个结点

                  1)结点类

             /**
	      * 结点类
	      */
	    private static class Node<T>{
		  Node<T> next; //保存前继结点
		  Node<T> prev; //保存后继节点
		  T value; //该结点的数据
		
		  /**
		   * @param prev  上一个节点
		   * @param value 结点保存的数据
		   * @param next 下一个结点
		   */
		public Node(Node<T> prev , T value , Node<T> next) {
			this.prev = prev; //前继结点
			this.value = value; //数据
			this.next = next; //后继结点
		 }
		
	      }


                2)插入结点在第一个位置上

/**
	 * 插入结点第一个位置上
	 */
	public void addFirst(T value) {
		linkFirst(value);
	}
	
	/**
	 * 插入结点在第一个位置上
	 */
	private void linkFirst(T value) {
		Node<T> h = head; 	//因为头指针是指向了第一个结点,所以h保存的是第一个结点
		Node<T> newNode = new Node<T>(null , value , h);  //新结点的next指向第一个结点h,第一个结点的前继指针为null
		head = newNode;  //头结点指向新的结点
		//如果头指针为空,说明新的结点即是第一个结点, 也是最后一个结点
		if(h == null) {
			last = newNode;  //让尾指针指向最后一个结点
		}else {
			//如果不为空, 将第h的前继指针pre指向新的结点
			h.prev = newNode;
		}
		size++;  //长度加1
	}
  
              3) 添加结点

/**
	 * 添加结点
	 */
	public void add(T value) {
		linkLast(value);
	}
	
	/**
	 * 添加最后一个结点
	 */
	private void linkLast(T value) {
		Node<T> l = last;   //l保存最后一个结点
		Node<T> newNode = new Node<T>(l , value , null);  //新的结点的前继指针pre指向最后一个结点l
		last = newNode;  //尾指针指向新的结点
		if(l == null) {  //判断如果原来最后的结点是否为空, 如果为空, 则是空链表, 所以新的结点是链表中的第一个结点, 就直接让头指针head指向新的结点
			head = newNode;
		}else {
			l.next = newNode;  //原来的最后结点的next指针指向新的结点
		}
		size++; 	//长度加1
	}
               4)删除第一个结点

/**
	 * 删除第一个结点
	 */
	public T removeFirst() {
		return unLinkFirst();
	}
	
	/**
	 * 删除第一个结点
	 */
	private T unLinkFirst() {
		checkedIsNullException();  //检查是否为空链表,如果是空链表,则抛出异常
		Node<T> h = head;   //保存第一个结点
		head = head.next;   //头指针指向第二个结点,head.next是第二个结点
		if(head == null) {   //如果第二个结点为空,说明链表只有一个结点,删除第一个结点后,链表为空,所以为指针也要改变
			last = null;
		}
		size--;  //长度减1
		
		return h.value;  //返回删除结点的值
	}
              5) 删除最后一个结点

/**
	 * 删除尾结点
	 */
	public T removeLast() {
		return unLinkLast(true);
	}
	
	/**
	 * 删除最后一个元素
	 */
	private T unLinkLast(boolean isRemove) {
		checkedIsNullException();  //检查是否为空链表,如果是空链表,则抛出异常
		Node<T> l = last;   //l保存最后一个结点
		T val = l.value;    //获取最后一个结点的数据
		if(isRemove) {
			last = l.prev;     //把尾指针指向倒数第二个结点
			l = null;         //因为l保存的是最后一个结点,所以把l设置为null
			if(last == null)   //如果last等于空,说明删除之前链表中只有一个结点(也是第一个结点,第一个结点的前继指针是为null的),所以删除后链表没有结点了,把头指针指向null
				head = null;   
		}
		size--;  //长度减1
		return val;  //返回删除的结点的数据
	}
               6)查找结点

/**
	 * 获取第i个结点的元素
	 */
	public T get(int i) {
		return node(i).value;
	}

/**
     * 设置向前查找和向查找,是为了增加效率,如果链表有100个结点,如果我要查第99个结点,如果从第一个结点开始找,
     *     那样效率会很慢.如果要不出现这种情况呢,那么就要从最后一个结点找起
     * 100/2 = 50
     * 如果查找的元素的大于50的,那么就从后往前找,如果小于50的,就从第一个结点开始找
     * 
     */
private Node<T> node(int index){
        checkedPosition(index);  //检查index时候超出链表的范围,如果是, 则抛出异常
        if(index < (size/2)) {   //如果index小于链表的(长度/2),从第一个结点向前查找
            Node<T> thead = head;  //thead保存第一个结点
            /**
             * 遍历链表查找结点
             */
            for(int i = 0; i < index; i++) 
                thead = thead.next;  //继续遍历下一个结点
            return thead;  //返回找到的结点
        }else {
                      Node<T> thead = last;  //thead保存最后一个结点
            /**
             * 遍历链表查找结点
             */
            for(int i = size-1; i > index; i--) 
                thead = thead.prev; //继续遍历上一个结点
            return thead;  //返回找到的结点
        }
        
    }


                7)链表是否为空 

/**
	 * 判断链表是否为空
	 */
	public boolean isEmpty() {
		return head == null;   //如果头指针是指向空
	}
               8)链表的长度

/**
	 * 返回链表的长度
	 */
	public int size() {
		return size;
	}
              9)找指定值出现的第一次的位置

/**
	 * 返回value所出现的第一个位置
	 */
	public int indexOf(Object value) {
		return getIndexOfPosition(value);
	}
	
	/**
	 * 返回value所出现的第一个位置
	 */
	private int getIndexOfPosition(Object value) {
		int index = 0;  //结点所在的位置
		for(Node<T> x = head; x != null; x = x.next) {  //首先从第一个结点开始找,条件是x不等于0,如果等于0,说明遍历完了
			if(x.value.equals(value)) {  //如果遍历到的结点的数据等于value,说明找到了,返回index
				return index;
			}
			index++;  
		}
		return -1;  //找不到,返回-1
	}
               10)返回指定值出现的最后一次的位置

/**
	 * 返回value所最后出现的位置
	 */
	public int lastIndexOf(Object value) {
		return getIndexLastPosition(value);
	}
	
	/**
	 * 返回value出现的最后一个位置
	 */
	private int getIndexLastPosition(Object value) {
		int index = size;    //链表的长度
		for(Node<T> x = last; x != null; x = x.prev) {
			index--;   
			if(x.value.equals(value)) {
				return index;
			}
		}
		return -1;
	}
                  11)是否存在该数据

/**
	 * 判断链表中是否包含value元素
	 */
	public boolean contain(Object value) {
		return indexOf(value) > -1;  //如果找到的位置大于-1,说明链表有该数据的结点
	}
               12)打印链表

public String toString() {
		String str = "";
		for(int i = 0; i < size(); i++) {
			str = str + this.get(i)+" ";
		}
		return str;
	}
               13)检查是否为空链表

private void checkedIsNullException() {
		if(isEmpty())
			throw new NullPointerException("空链表......");
	}
              14)检查是否超出链表的范围

private void checkedPosition(int index) {
		if(index < 0 || index >= size)
			throw new ArrayIndexOutOfBoundsException("index="+index+", size="+size);
	}

完整代码

package cn.zyz.b_zy;

/** 
 * 双向链表 
 */  
public class AA<T> {  
  
    private Node<T> head , last;  //head为头指针, 指向第一个结点; last指向最后一个结点  
    private int size = 0;  //链表的长度  
      
    /** 
     *  结点类 
     */  
    private static class Node<T>{  
        Node<T> next; //保存下一个结点  
        Node<T> prev; //保存上一个节点  
        T value; //该结点的数据  
          
        /** 
         * @param prev  上一个节点 
         * @param value 结点保存的值 
         * @param next 下一个结点 
         */  
        public Node(Node<T> prev , T value , Node<T> next) {  
            this.prev = prev; //前继结点  
            this.value = value; //数据  
            this.next = next; //后继结点  
        }  
          
    }  

    /** 
     * 添加结点 
     */  
    public void add(T value) {  
        linkLast(value);  
    }  
      
    /** 
     * 添加最后一个结点 
     */  
    private void linkLast(T value) {  
        Node<T> l = last;   //l保存最后一个结点  
        Node<T> newNode = new Node<T>(l , value , null);  //新的结点的前继指针pre指向最后一个结点l  
        last = newNode;  //尾指针指向新的结点  
        if(l == null) {  //判断如果原来最后的结点是否为空, 如果为空, 则是空链表, 所以新的结点是链表中的第一个结点, 就直接让头指针head指向新的结点  
            head = newNode;  
        }else {  
            l.next = newNode;  //原来的最后结点的next指针指向新的结点  
        }  
        size++;     //长度加1  
    }  
      
      
    /** 
     * 插入结点第一个位置上 
     */  
    public void addFirst(T value) {  
        linkFirst(value);  
    }  
      
    /** 
     * 插入结点在第一个位置上 
     */  
    private void linkFirst(T value) {  
        Node<T> h = head;     //因为头指针是指向了第一个结点,所以h保存的是第一个结点  
        Node<T> newNode = new Node<T>(null , value , h);  //新结点的next指向第一个结点h,第一个结点的前继指针为null  
        head = newNode;  //头结点指向新的结点  
        //如果头指针为空,说明新的结点即是第一个结点, 也是最后一个结点  
        if(h == null) {  
            last = newNode;  //让尾指针指向最后一个结点  
        }else {  
            //如果不为空, 将第h的前继指针pre指向新的结点  
            h.prev = newNode;  
        }  
        size++;  //长度加1  
    }  
      
    /** 
     * 删除第一个结点 
     */  
    public T removeFirst() {  
        return unLinkFirst();  
    }  
      
    /** 
     * 删除第一个结点 
     */  
    private T unLinkFirst() {  
        checkedIsNullException();  //检查是否为空链表,如果是空链表,则抛出异常  
        Node<T> h = head;   //保存第一个结点  
          
        head = head.next;   //头指针指向第二个结点,head.next是第二个结点  
        if(head == null) {   //如果第二个结点为空,说明链表只有一个结点,删除第一个结点后,链表为空,所以为指针也要改变  
            last = null;  
        }  
        size--;  //长度减1  
          
        return h.value;  //返回删除的结点的数据  
    }  
      
      
    /** 
     * 删除尾结点 
     */  
    public T removeLast() {  
        return unLinkLast();  
    }  
      
    /** 
     * 删除最后一个元素 
     */  
    private T unLinkLast() {  
        checkedIsNullException();  //检查是否为空链表,如果是空链表,则抛出异常  
        Node<T> l = last;   //l保存最后一个结点  
        T val = l.value;    //获取最后一个结点的数据  
        last = l.prev;     //把尾指针指向倒数第二个结点  
        l = null;         //因为l保存的是最后一个结点,所以把l设置为null  
        if(last == null){   //如果last等于空,说明删除之前链表中只有一个结点(也是第一个结点,第一个结点的前继指针是为null的),所以删除后链表没有结点了,把头指针指向null  
            head = null; 
        }
        size--;  //长度减1  
        return val;  //返回删除的结点的数据  
    }  
      
    /** 
     * 获取第i个结点的元素 
     */  
    public T get(int i) {  
        return node(i).value;  
    }  
      
    /** 
     * 设置向前查找和向查找,是为了增加效率,如果链表有100个结点,如果我要查第99个结点,如果从第一个结点开始找, 
     *  那样效率会很慢.如果要不出现这种情况呢,那么就要从最后一个结点找起 
     * 100/2 = 50 
     * 如果查找的元素的大于50的,那么就从后往前找,如果小于50的,就从第一个结点开始找 
     *  
     */  
    private Node<T> node(int index){  
        checkedPosition(index);  //检查index时候超出链表的范围,如果是, 则抛出异常  
        if(index < (size/2)) {   //如果index小于链表的(长度/2),从第一个结点向前查找  
            Node<T> thead = head;  //thead保存第一个结点  
            /** 
             * 遍历链表查找结点 
             */  
            for(int i = 0; i < index; i++)   
                thead = thead.next;  //继续遍历下一个结点  
            return thead;  //返回找到的结点  
        }else {  
            Node<T> thead = last;  //thead保存最后一个结点  
            /** 
             * 遍历链表查找结点 
             */  
            for(int i = size-1; i > index; i--)   
                thead = thead.prev; //继续遍历上一个结点  
            return thead;  //返回找到的结点  
        }  
          
    }  
      
      
    /** 
     * 返回value所最后出现的位置 
     */  
    public int lastIndexOf(Object value) {  
        return getIndexLastPosition(value);  
    }  
      
    /** 
     * 返回value出现的最后一个位置 
     */  
    private int getIndexLastPosition(Object value) {  
        int index = size;  
        for(Node<T> x = last; x != null; x = x.prev) {  
            index--;  
            if(x.value.equals(value)) {  
                return index;  
            }  
        }  
        return -1;  
    }  
      
    /** 
     * 返回value所出现的第一个位置 
     */  
    public int indexOf(Object value) {  
        return getIndexOfPosition(value);  
    }  
      
    /** 
     * 返回value所出现的第一个位置 
     */  
    private int getIndexOfPosition(Object value) {  
        int index = 0;  //结点所在的位置  
        for(Node<T> x = head; x != null; x = x.next) {  //首先从第一个结点开始找,条件是x不等于0,如果等于0,说明遍历完了  
            if(x.value.equals(value)) {  //如果遍历到的结点的数据等于value,说明找到了,返回index  
                return index;  
            }  
            index++;    
        }  
        return -1;  //找不到,返回-1  
    }  
      
    /** 
     * 判断链表中是否包含value元素 
     */  
    public boolean contain(Object value) {  
        return indexOf(value) > -1;  
    }  
      
    /** 
     * 返回链表的长度 
     */  
    public int size() {  
        return size;  
    }  
      
    public String toString() {  
        String str = "";  
        for(int i = 0; i < size(); i++) {  
            str = str + this.get(i)+" ";  
        }  
        return str;  
    }  
  
    private void checkedIsNullException() {  
        if(isEmpty())  
            throw new NullPointerException("空链表......");  
    }  
      
    private void checkedPosition(int index) {  
        if(index < 0 || index >= size)  
            throw new ArrayIndexOutOfBoundsException("index="+index+", size="+size);  
    }  
      
    /** 
     * 判断链表是否为空 
     */  
    public boolean isEmpty() {  
        return head == null;   //如果头指针是指向空  
    }  

}                       





















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值