自己写一个简单的LinkedList
2017-09-29 11:08
197 查看
之前写了一遍关于ArrayList的简略版,现在来一遍关于LinkedList的简略版(ps 通过查看源码个人认为jdk源码中的LinkedList有很多啰嗦重复的方法)。
首先LinkedList实现一个链表。由这个类定义的链表也可以像栈或队列一样被使用。这是百度百科的说法。所以我们首先需要新建一个链表类。由于这个链表类只是在LinkedList里面使用,故采取静态内部类的方式
为了和JDK源码的LinkedList区分,我的类名叫SimpleLinkedList。
定义一个header作为集合的开始
构造器 初始化集合
在链表尾部添加元素
公共方法addBefore(E,Entry)的实现
在链表头部添加元素
其实JDK里面还有个方法addLast(E) 和add()方法一样,这里就不列出了
获取元素
获取第一个和最后一个元素,由于链表结构,header作为零界点,下一个指向第一个元素;上一个指向最后一个
根据指定的位置获取元素(随机获取元素相对ArrayList来说,这个效率很低)
公共代码entry(int)
如果要获取的index小于链表size的一半(右移一位),则从开头0的位置找到index位置,如果大于size则从结尾找到index
替换指定位置元素set方法
移除元素
另外JDK1.5后加入了一些和Queue相关的方法如pop,peek,push等。我简单的实现了几个,大致和上面的几个方法差不错。下面是完整的源码
首先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;
}
}
相关文章推荐
- 自己动手实现一个简单的string类(一)
- 自己做的一个超级简单的小游戏
- 一个自己编写的简单AC自动机代码-----AC automata get √
- 也发一个自己实现的android简单文件选择器代码。支持多卡,排序
- 简单的一个画布,可以自己画画玩
- WebView 写一个自己的简单浏览器
- 自己写的一个简单的Java GUI源码
- 咱们在讨论的时候能不能先确定一个明确的范围呢?最好能把自己的经历简单说一下。
- Codewars简单使用和 其中一道题,用JavaScript实现一个函数,求一个正数的次大数字,拿自己的解法和大神相比,简直对不起JavaScript给我提供的 那么多便利
- [置顶] 自己写一个简单通用的Makefile
- 自己用 Netty 实现一个简单的 RPC
- 自己封装的一个简单的倒计时功能实例
- C++算法之 自己写一个简单的栈Stack
- 自己编写一个简单的ActiveX控件——详尽教程
- 自己设计一个简单的的Java连接池(一)
- 在自己的WSASOCKET服务端/客户端中做了一个简单的解包程序处理粘包的问题
- C-自己写的一个最简单的班级信息统计程序
- 自己写了一个简单的仿优酷Android客户端图片左右滑动
- 自己动手实现一个简单的JSON解析器
- 自己私用的一个简单程序