您的位置:首页 > 编程语言 > Java开发

自己写一个简单的LinkedList

2017-09-29 11:08 197 查看
之前写了一遍关于ArrayList的简略版,现在来一遍关于LinkedList的简略版(ps 通过查看源码个人认为jdk源码中的LinkedList有很多啰嗦重复的方法)。

首先LinkedList实现一个链表。由这个类定义的链表也可以像栈或队列一样被使用。这是百度百科的说法。所以我们首先需要新建一个链表类。由于这个链表类只是在LinkedList里面使用,故采取静态内部类的方式

/**
* 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
* 链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
*
* @param <E>
*/
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;
}
}


为了和JDK源码的LinkedList区分,我的类名叫SimpleLinkedList。

定义一个header作为集合的开始

private Entry<E> header = new Entry<E>(null,null,null);


构造器 初始化集合

public SimpleLinkedList(){
header.next = header;
header.previous = header;
}


在链表尾部添加元素

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


公共方法addBefore(E,Entry)的实现

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++;
return newEntry;
}


在链表头部添加元素

public void addFirst(E e){
addBefore(e, header.next);
}


其实JDK里面还有个方法addLast(E) 和add()方法一样,这里就不列出了

获取元素

获取第一个和最后一个元素,由于链表结构,header作为零界点,下一个指向第一个元素;上一个指向最后一个

public E getFirst(){
return header.next.element;
}

public E getLast(){
return header.previous.element;
}


根据指定的位置获取元素(随机获取元素相对ArrayList来说,这个效率很低)

public E get(int index){
return entry(index).element;
}


公共代码entry(int)

private Entry<E> entry(int index) {
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;
}


如果要获取的index小于链表size的一半(右移一位),则从开头0的位置找到index位置,如果大于size则从结尾找到index

替换指定位置元素set方法

public E set(int index,E e){
Entry<E> entry = entry(index);
E oldE = entry.element;
entry.element = e;
return oldE;
}


移除元素

public E remove(int index){
return remove(entry(index));
}
public E removeFirst(){
return remove(header.next);
}
public E removeLast(){
return remove(header.previous);
}

private E remove(Entry<E> e){
if(e==header){
throw new NoSuchElementException();
}
E result = e.element;
e.next.previous = e.previous;
e.previous.next = e.next;
e.next = e.previous = null;
e.element = null;
size--;
return result;
}


另外JDK1.5后加入了一些和Queue相关的方法如pop,peek,push等。我简单的实现了几个,大致和上面的几个方法差不错。下面是完整的源码


/**
* 模拟LinkedList的实现
*
*
*/
public class SimpleLinkedList<E> {
private int size = 0;
private Entry<E> header = new Entry<E>(null,null,null);

public SimpleLinkedList(){
header.next = header;
header.previous = header;
}
/**
* 在链
4000
表结尾处新增一个元素
* 实现原理,每次都在header前添加一个节点
* @param e
* @return
*/
public boolean add(E e){
addBefore(e, header);
return true;
}
/**
* 在链表开头添加元素
* @param e
*/
public void addFirst(E e){ addBefore(e, header.next); }
/**
* 双链表结构,header的下一个,刚好是链表的第一个
* header的上一个,反而是最后一个元素
* @return
*/
public E getFirst(){
return header.next.element;
}

public E getLast(){
return header.previous.element;
}

public int size(){
return size;
}

/**
* 返回指定坐标的元素
*/
public E get(int index){ return entry(index).element; }

private Entry<E> entry(int index) {
Entry<E> e = header;
/**
* 右移一位相当于除以2
* 如果坐标小于长度的一半,从0开始找,一直找到当前坐标,返回当前e的下一个
* 如果要查找的坐标大于链表长度的一半,从末尾找到该坐标的前一个,返回当前e的上一个
*/
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;
}
/**
* 替换指定坐标的元素
* @param index
* @param e
* @return
*/
public E set(int index,E e){ Entry<E> entry = entry(index); E oldE = entry.element; entry.element = e; return oldE; }

public E remove(int index){ return remove(entry(index)); } public E removeFirst(){ return remove(header.next); } public E removeLast(){ return remove(header.previous); } private E remove(Entry<E> e){ if(e==header){ throw new NoSuchElementException(); } E result = e.element; e.next.previous = e.previous; e.previous.next = e.next; e.next = e.previous = null; e.element = null; size--; return result; }

//----------queue的一些方法
/**
* add 和 offer 的区别在于
* 当队列为空add报错,offer返回false
* LinkedList里面还有区别,add是list方法,offer是Queue方法
* @param e
* @return
*/
public boolean offer(E e){
return add(e);
}

/**
* 将元素推入此列表所表示的堆栈。
* 其实就是在list开头添加元素
* 堆的出入规则,先进后出
* @param e
*/
public void push(E e){
addFirst(e);
}
/**
* 从此列表所表示的堆栈处弹出一个元素。
* 其实是头部弹出一个元素
* @return
*/
public E pop(){
return removeFirst();
}
/**
* 获得第一个元素,与pop相对,它不删除元素
* @return
*/
public E peek(){
if(size ==0){
return null;
}
return getFirst();
}

/**
* 链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
* 链表允许插入和移除表上任意位置上的节点,但是不允许随机存取。
*
* @param <E>
*/
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;
}
}
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++;
return newEntry;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jdk linkedlist 链表