数据结构: Java中LinkedList的简单实现
2015-10-06 00:37
656 查看
更新:以下代码是初学链表后的简单实现,时隔一年再看一下代码。觉得有点惨不忍睹,测试了一下,标准库的链表插入1000万个元素用了10秒钟,以下代码花费的时间远超标准库。因为如果要将元素插入到链表末尾,都需要遍历整个链表。是个O(N)的算法。但实际上,大部分插入都是插入到最后(或是最前)。我们其实只需要维护一个tail节点就能解决这个问题。这样时间复杂度就为O(1)了。
下面是LinkedList的简单实现。
LinkedList的优点: 新项的插入和现有项的删除花费常数时间。(前提是已有变动项的位置,不然还是要在索引上花费O(N) )
LinkedList的缺点: 很难索引现有项,对get操作的调用花费很多时间。
MyLinkedList作为双向链表,get()方法可以从头结点或者尾节点开始。所以最坏的情况下需要遍历 【N/2】 个元素。
代码中changedTimes和itChangedTimes的作用: 如果获取了一个迭代器之后修改它所对应的MyLinkedList对象,则让该迭代器失效。
public void add(T val) { if(head==null) { head = new Node(val); tail = head; } else { tail.next = new Node(val); tail = tail.next; } ++size; }
下面是LinkedList的简单实现。
LinkedList的优点: 新项的插入和现有项的删除花费常数时间。(前提是已有变动项的位置,不然还是要在索引上花费O(N) )
LinkedList的缺点: 很难索引现有项,对get操作的调用花费很多时间。
MyLinkedList作为双向链表,get()方法可以从头结点或者尾节点开始。所以最坏的情况下需要遍历 【N/2】 个元素。
代码中changedTimes和itChangedTimes的作用: 如果获取了一个迭代器之后修改它所对应的MyLinkedList对象,则让该迭代器失效。
package list; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; /** * MyLinkedList * @author earayu * @param <T> */ public class MyLinkedList<T> implements Iterable<T> { //双向链表的节点 private static class Node<T>{ public T data; public Node<T> prevNode; public Node<T> nextNode; public Node(T data, Node<T> prevNode, Node<T> nextNode) { this.data = data; this.prevNode = prevNode; this.nextNode = nextNode; } } //定义链表的长度,修改次数,头结点和尾节点。 private int size; private int changedTimes; private Node<T> firstNode; private Node<T> lastNode; /** * 调用init()方法,初始化链表 */ public MyLinkedList(){ init(); } /** * 初始化MyLinkedList,将长度,被改变次数,头结点和尾节点都初始化。以免发生错误。 */ private void init(){ size = 0; changedTimes = 0; firstNode = new Node<T>(null, null, null); lastNode = new Node<T>(null, null, null); firstNode.nextNode = lastNode; lastNode.prevNode = firstNode; } /** * 将链表清空,修改次数+1 */ public void clear(){ size = 0; changedTimes++; firstNode = new Node<T>(null, null, null); lastNode = new Node<T>(null, null, null); firstNode.nextNode = lastNode; lastNode.prevNode = firstNode; } public boolean isEmpty(){ return size() == 0; } /** * 返回当前链表长度(不含头尾节点) * @return */ public int size(){ return size; } /** * 将idx索引出节点的值设置成newData * @param idx * @param newData * @return */ public T set(int idx, T newData){ Node<T> p = getNode(idx); T oldVal = p.data; p.data = newData; return oldVal; } /** * 删除制定索引出的节点,索引从0开始 * @param idx * @return */ public T remove(int idx){ return remove(getNode(idx)); } private T remove(Node<T> p){ p.nextNode.prevNode = p.prevNode; p.prevNode.nextNode = p.nextNode; --size; ++changedTimes; return p.data; } /** * 将data添加到链表尾部。 * @param data * @return */ public boolean add(T data){ add(size, data); return true; } /** * 将链表添加到idx索引出,索引从0开始 * @param idx * @param data * @return */ public boolean add(int idx, T data){ if(idx < 0 || idx > size){ throw new IndexOutOfBoundsException(); } Node<T> beforeNode = firstNode; for(int i=0;i<size;i++){ beforeNode = beforeNode.nextNode; } Node<T> afterNode = beforeNode.nextNode; beforeNode.nextNode = new Node(data, beforeNode, afterNode); afterNode.prevNode = beforeNode.nextNode; ++size; ++changedTimes; return true; } /** * 获取idx索引出的节点的数据,索引从0开始 * @param idx * @return */ public T get(int idx){ return getNode(idx).data; } /** * 获取idx索引出的节点 * @param idx * @return */ private Node<T> getNode(int idx){ if(idx < 0 || idx >= size){ throw new IndexOutOfBoundsException(); } Node<T> p; if(idx < size/2){ p = firstNode.nextNode; for(int i=0; i<idx; i++){ p = p.nextNode; } }else{ p = lastNode; for(int i=size; i>idx; i--){ p = p.prevNode; } } return p; } /** * 返回一个迭代器 */ @Override public Iterator<T> iterator() { return new LinkedListIterator(); } /** * * @author earayu * */ private class LinkedListIterator implements Iterator<T>{ //迭代器的当前指向节点,修改次数,可否移除 private Node<T> currentNode = firstNode.nextNode; private int itChangedTimes = changedTimes; private boolean removable = false; /** * 返回是否有下一个节点(不包含尾节点)。 */ @Override public boolean hasNext() { return currentNode != lastNode; } /** * 返回当前指向节点的下一个节点的值,并将指向的节点后移一位。 */ @Override public T next() { if(changedTimes != itChangedTimes){ throw new ConcurrentModificationException(); } if(!hasNext()){ throw new NoSuchElementException(); } T nextItem = currentNode.data; currentNode = currentNode.nextNode; removable = true; return nextItem; } /** * 调用外部类的remove方法,移除上一个访问过的节点。即,当前指向节点的前一个节点。 */ public void remove(){ if(changedTimes != itChangedTimes){ throw new ConcurrentModificationException(); } if(!removable){ throw new IllegalStateException(); } MyLinkedList.this.remove(currentNode.prevNode); removable = false; ++itChangedTimes; } } }
相关文章推荐
- 数据结构: Java中ArrayList的简单实现
- dlutoj 单调队列
- 数据结构实践——负数把正数赶出队列
- 数据结构实践——停车场模拟(栈和队列综合)
- 大话数据结构(2)--数据-横看成岭侧成峰
- iOS编程------XML、JSON数据结构解析
- [面试时]MySQL索引背后的数据结构及算法原理
- 数据结构实践——排队看病模拟(队列)
- POJ 2823 单调队列
- 【数据结构】线性结构:存储&运算&时间复杂度
- 数据结构之线性表
- Linux的常用数据结构之链表
- 数据结构【线性表(二)链表】项目之猴子选大王
- 第4周SHH数据结构—【项目3-单链表应用(1)】
- 数据结构【线性表(二)链表】项目之循环双链表应用
- 数据结构实践——多项式求和
- 第六周项目2—数据结构之自建算法库—链栈
- 项目2 -- 建立链栈算法库
- 数据结构【线性表(二)链表】项目之多项式求和
- 【栈项目1 - 建立顺序栈算法库 第六周】