数据结构基础java实现—双向链表
来源:互联网 发布:tgp腾讯游戏客户端mac 编辑:程序博客网 时间:2024/05/22 13:37
设计双向链表需要两个类
1. LinkedList类,包含头结点first,尾节点last,节点个数size,记录头结点和尾节点有助于理解和简化编程。提供最基本的方法为:在指定索引位置插入和删除数据。
2. Node类,包含一个泛型对象的引用item,一个前引用prev,一个后引用next,这个可以设置为内部静态类。
在指定索引位置插入和删除数据,需要通过node(int index)方法返回index位置上的Node数据一遍操作。在返回index位置上的node数据时,要考虑index与size的关系,从而判别是从前往后查找还是从后往前查找。
插入和删除数据时需要分三种情况考虑:头结点插入删除,尾节点插入删除,中间节点插入删除。每种情况均写成私有的方法,由public方法根据实际情况调用。
在public的方法中,凡是牵扯的index的操作都要对index做检查,防止下标越界,这个由checkIndex(int index)方法完成。需要注意的是插入数据时的下标检查与其他时候的下标检查不一致,因为插入数据时index是可以等于size的。
以下代码为个人所写代码:
package wenpq.util;/** * @author wenpq * wenpq的linkedList */public class LinkedList<E>{private int size = 0;private Node<E> first; // 头结点与尾节点的使用,排除了特殊情形简化编码private Node<E> last;// ------------------------------------------------构造函数public LinkedList() {}// ------------------------------------------------内部使用函数// 检查下标是否越界 private void checkIndex(int index) { if (!(index >= 0 && index < size)) throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); } // 返回index位置上的node Node<E> node(int index) { // 右移1 和除2取整等价 if(index<(size>>1)){ // 从前向后 连接到指定节点 Node<E> x=first; for(int i=0;i<index;i++) x = x.next; return x; }else{ // 从后向前 连接到指定节点 Node<E> x=last; for(int i=size-1;i>index;i--) x = x.prev; return x; } } // 头节点前插入void linkFirst(E e){Node<E> f = first;Node<E> newNode = new Node<>(null,e,f);if (f==null){last = newNode;}else{f.prev = newNode;}first = newNode;size++;}// 尾节点后插入void linkLast(E e){Node<E> l = last;Node<E> newNode = new Node<>(l,e,null);if(l==null){first = newNode;}else{l.next = newNode;}last = newNode;size++;}// 中间前节点插入 插入后 element位置就是index 故要插入原来位置之前void linkBefore(E e, Node<E> succ){Node<E> newNode = new Node<>(succ.prev,e,succ);succ.prev.next = newNode;succ.prev = newNode;size++;}// 头节点删除 void unlinkFirst(Node<E> f) { final Node<E> next = f.next; f.item = null; f.next = null; // help GC first = next; if (next == null) last = null; else next.prev = null; size--; } // 尾节点删除 void unlinkLast(Node<E> l) { final Node<E> prev = l.prev; l.item = null; l.prev = null; // help GC last = prev; if (prev == null) first = null; else prev.next = null; size--; } // 中间节点删除 void unlink(Node<E> x) { final Node<E> next = x.next; final Node<E> prev = x.prev; prev.next = next; x.prev = null; next.prev = prev; x.next = null; x.item = null; size--; }// ------------------------------------------------可以继承自接口的一些操作(没有写完)public int size() {return size;}public boolean add(E e) {linkLast(e);return true;}public E get(int index) {checkIndex(index); return node(index).item;}public boolean set(int index, E element) {checkIndex(index); Node<E> x = node(index); x.item = element; return true;}public void add(int index, E element) {// 注意在add的时候index是可以等于size的 if (!(index >= 0 && index <= size)) throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); if (index == size){ linkLast(element); }else{ if(index ==0 ){ linkFirst(element); }else linkBefore(element, node(index)); } }public void remove(int index) {checkIndex(index); if (index == size-1){ unlinkLast(node(index)); }else{ if(index ==0 ){ unlinkFirst(node(index)); }else unlink(node(index)); } }/** * 采用静态内部类 减少代码 较少动态创建开销 */private static class Node<E> {// 一个E类型引用// 一个前引用// 一个后引用Node<E> prev;E item;Node<E> next;public Node(Node<E> prev, E item, Node<E> next) {super();this.prev = prev;this.item = item;this.next = next;}}}
以下为测试代码:
public class Test {public static void main(String[] args) { LinkedList<String> list = new LinkedList<String>(); list.add("one"); list.add("two"); list.add("three"); list.add(0,"first"); list.add(list.size(),"end"); list.set(1, "new one"); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); } list.remove(3); list.remove(3); for(int i=0;i<list.size();i++){ System.out.println(list.get(i)); }}}
对比util的LinkedList的代码,标准库则做了更多考虑,在类申明时:
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
之所以继承AbstractSequentialList ,是因为它实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些骨干性函数。降低了List接口的复杂度。这些接口都是随机访问List的,LinkedList是双向链表;既然它继承于AbstractSequentialList,就相当于已经实现了“get(int index)这些接口”。
java.io.Serializable用于声明该类的对象可以序列化,在socket通信和远程方法调用时会用到。实际上在源代码中头结点first,尾节点last,节点个数size这些都被transient关键字修饰,限定了不可能序列化的属性。
而在完成get,set,add方法时也不像上面代码那样分三种情况讨论,因为它调用的内部方法已经做了考虑。
对于remove方法,util源码返回了remove的对象,可能是因为考虑到同时要取数据燃耗删除数据的操作吧,目前还明白为什么要这么做,先留着,以后再来想。
- 数据结构基础java实现—双向链表
- 基础数据结构--双向链表的实现
- 使用java实现双向链表数据结构
- java 实现双向链表(数据结构)
- 数据结构--java实现双向链表
- 数据结构--双向链表实现(java)
- 数据结构——双向链表(Java实现)
- 【数据结构】双向链表实现
- (Java)Java双向链表实现(数据结构七)
- [java数据结构]--java双向链表LinkedList的简单实现
- 【JAVA数据结构】双向链表
- Java数据结构--双向链表
- 数据结构之双向链表的Java实现
- 数据结构之双向链表(JAVA实现)
- 数据结构学习笔记之用Java实现双向链表
- 数据结构之循环双向链表java实现
- Linux基础数据结构——双向链表
- 数据结构基础(1)-->双向链表
- iOS多线程GCD
- 电容的充电速率
- 高级控件:菜单、工具栏多窗口控制
- PHP Console工具使用分享
- MongoDB之整库备份还原单表collection备份还原
- 数据结构基础java实现—双向链表
- poj3009 冰球
- Android:圆形头像
- HDU1162最小生成树
- 网页宽度自动调整响应式网页
- 结合属性文件的工厂模式(java反射的应用)
- mysql 数据库导入导出方法总结(是时候总结)
- 用堆实现优先队列
- nyist5 暴力;kmp