实现一个简单的LinkedList

链表参考文章
代码参考文章
一些基本概念:
(1) 线性表分为两种,一种是顺序存储结构的顺序表,另一种是通过指针来描述其逻辑位置的链表。

(2)**节点(Node)**是由一个需要储存的对象及对下一个节点的引用组成的。也就是说,节点拥有两个成员:储存的对象、对下一个节点的引用.

(3)单向链表是一种线性表,实际上是由节点(Node)组成的,其数据在内存中存储是不连续的,它存储的数据分散在内存中,每个结点只能也只有它能知道下一个结点的存储位置。由N各节点(Node)组成单向链表,每一个Node记录本Node的数据及下一个Node。向外暴露的只有一个头节点(Head),我们对链表的所有操作,都是直接或者间接地通过其头节点来进行的。

(4) 双向链表

(4)每个链表都包括一个LinikedList对象和许多Node对象,LinkedList对象通常包含头和尾节点的引用,分别指向链表的第一个节点和最后一个节点。而每个节点对象通常包含数据部分data,以及对上一个节点的引用prev和下一个节点的引用next,只有下一个节点的引用称为单向链表,两个都有的称为双向链表。next值为null则说明是链表的结尾,如果想找到某个节点,我们必须从第一个节点开始遍历,不断通过next找到下一个节点,直到找到所需要的.

LinkedList底层实现

package testList;
/**
 * 实现双向LinkedList的方法如下: add方法,get方法, indexOf方法, remove方法
 * @author Administrator
 */

public class SimpleLinkedList<E> {

	//构造方法
//	public SimpleLinkedList() {//为什么没有构造方法
//	}
	private int size;
    private Node<E> first;//双向链表中 的头结点尾节点
    private Node<E> last;
    //add
    public boolean add(E e) {//不指定位置添加元素,则默认添加到了链表的最后
    	addAtLast(e);
    	return true;
    }
    //addAtLast
    public void addAtLast(E element) {
    	Node<E> l=last;
    	Node<E> node=new Node<E>(element,l,null);//public Node(E item,Node<E> prev,Node<E> next)
    	last=node;
    	if(l==null) {
    		first=node;
    	}else {
    		l.next=node;
    	}
    	size++;	
    }
    //add(int index ,E e),
    public void add(int index ,E e) {
    	//检查index是否越界
    	checkRange(index);
    	if(index==size) {
    		addAtLast(e);
    	}else {//如果不是,则得到index所对应的Node元素,执行addBeforeNode。
    		Node<E> node=getNode(index);
    		addBeforeNode(e, node);
    	}
    }
    //检查越界
    public void checkRange(int index) {
    	if(index<0||index>size) {
    		throw new IndexOutOfBoundsException("指定的index超过界限");
    	}
    	}
    //得到index所对应的node元素,采用二分查找,节省查找时间
    public Node<E> getNode(int index) {
    	if(index<(size<<1)) {//首先判断index如果是前一半范围,则游标Node初始为first,用游标Node元素的next,不断指向index所在的元素
    		Node<E> cursor=first;
    		for(int i=0;i<index;i++) {
    			cursor=cursor.next;
    		}
    		return cursor;
    	}else{//如果是后一半的范围内,如果是后一半,则游标Node初始为last,用游标Node元素的prev,不断指向index所在的元素。
    		Node<E> cursor=last;
    		for(int i=size-1;i>index;i--) {//链表的头尾节点是暴露在外面的,应用到了双向链表的特点,相当于已知,其他节点未知
    			cursor=cursor.prev;
    		}
    		return cursor;
    	}
    }
    //addBeforeNode,
    public void addBeforeNode(E element, Node<E> specifiedNode) {
    	Node<E> prevNode=specifiedNode.prev;//新节点的prev是原index元素的prev,新节点的next是原index元素。
    	Node<E> newNode=new Node<E>(element,prevNode,specifiedNode);
    	if(prevNode==null) {//要判断preNode是不是空,是的话,表示newNode为第一个元素,就是first
    		first=newNode;
    	}else {
    		prevNode.next=newNode;
    	}
    	specifiedNode.prev=newNode;
    	size++;
    
    }
    //get 得到链表节点元素
    public E getElement(int index) {
    	checkRange(index);
    	Node<E> node=getNode(index);
    	return node.item;
    }
    //indexOf(Object o)用来得到指定元素的下标
    public int indexOf(E o) {//与ArrayList一样,从第一位开始查找,首先先判断element是不是null,分成两种情况。
    	//从第一位开始查找,自己写的不知道ok否
//    	Node<E> cursor=first;
    	if(o!=null) {
    		for(int i=0;i<size;i++) {
    			Node<E> node=getNode(i);
    			if(node.item.equals(o)) {
    				return i;
    			}
    		}
    		}else {
    			for(int i=0;i<size;i++) {
    				Node<E> node=getNode(i);
    				if(node.item==null) {
    					return i;
    				}
    			}
    		}
    		return -1;	
    	}
/**   public int indexOf(Object element) {//参考博文中的indexOf
        Node<E> cursor = first;
        int count = 0;
        while (cursor != null) {
            if (element != null) {
                if (element.equals(cursor.item)) {
                    return count;
                }
            }else{
                if (cursor.item == null) {
                    return count;
                }
            }
            count ++;
            cursor = cursor.next;
        }
        return -1;
    }
*/
    //remove(int index)方法
    public E remove(int index) {//自己写的不知道ok否
    	checkRange(index);
    	if(index==size) {
    		E lelement=last.item;
    		last.prev.next=null;
    		size--;
    		return lelement;	
    	}else if(index==0){
    		E felement=first.item;
    		first.next.prev=null;
    		size--;
    		return felement;	
    	}else {
    		Node<E> nowNode=getNode(index);
    		nowNode.next.prev=nowNode.prev;
    		nowNode.prev.next=nowNode.next;
    		E nelement=nowNode.item;
    		nowNode.next=null;
    		nowNode.prev=null;
    		size--;
    		return nelement;
    	}
    	
    }
/**参考博客的remove(index)
 * 先获得index对应的Node元素,得到该Node元素的前一个元素和后一个元素。
 * 接下来,只需要将前一个元素和后一个元素直接相连即可,
 * 其他只需要额外判断前一个元素和后一个元素是否为null就行。
    public E remove(int index) {
        checkRange(index);
        return deleteLink(index);
    }
    private E deleteLink(int index) {
        Node<E> l = node(index);
        E item = l.item;
        Node<E> prevNode = l.prev;
        Node<E> nextNode = l.next;

        if (prevNode == null) {
            first = nextNode;
        }else{
            prevNode.next = nextNode;
            l.next = null;
        }

        if (nextNode == null) {
            last = prevNode;
        }else{
            nextNode.prev = prevNode;
            l.prev = null;
        }
        size--;
        l.item = null;
        return item;
    }
 */
   //remove(Object o)
    public boolean remove(E o) {
    	int index=indexOf(o);
    	if(index<0) {
    		return false;
    	}
    	remove(index);
    	return true;
    	}
    }

    



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值