对于链表,我们是再熟悉不过了。下面我们来简单实现一下。
链表是由1个或多个节点连接形成的,所以我们从节点出发,定义节点如下
class Lnode<T>{ public T data; public Lnode<T> next; public Lnode(T key){ data = key; next = null; } }
一个泛型表示节点中的值,next指向下一个节点。
接下来定义链表类,链表定义不是很难。
private Lnode<T> first,last; private int length; private Iterator<T> iterator;
表头,表尾和长度以及一个迭代器。
构造方法也很简单,只需让表头表尾置null,length置0,将迭代器初始化
public MyLinked(){ first = last = null; length = 0; iterator = new LinkedIterator(); }
下面就是操作链表的各种方法,首先看最简单的size方法。直接返回成员属性length就行。
//求长度 public int size(){ return length; }
下来是获取节点的值,获取节点可以单独写一个方法,方便在之后的set、remove方法使用
//获取第i个节点 private Lnode<T> getNode(int i){ if (i<0 || i>=length) return null; if (i==0) return first; Lnode<T> p = first; int j=0; while (p!=null && j<i){ p = p.next; j++; } return p; }
获取节点的值方法只需得到节点,对接点进行判空,不为空返回节点值
//获取第i个节点的值 public T get(int i){ Lnode<T> p = getNode(i); if (p==null) return null; else return p.data; }
接下来是修改某个节点的值,过程和获取节点的值类似,不过将返回节点的值改为赋值即可。
//修改i号节点的值 public boolean set(int i,T x){ Lnode<T> p = getNode(i); if (p==null) return false; else { p.data = x; return true; } }
add方法很常用,而且add方法也有好几种,我们可以使用方法重载进行编写,添加节点时,注意添加到表头,表中间和表尾。
//添加节点 public void add(int i,T x){ int j = i-1; Lnode<T> p; Lnode<T> s = new Lnode<>(x); if (first==null || length == 0){ first =s; last = s; }else if(j<0) { s.next = first; first = s; }else if (j>=length-1){ last.next = s; last = s; }else { p = getNode(j); s.next = p.next; p.next = s; } length++; }可以根据上面这个方法对add方法进行各种各样的重载。
//添加至末尾 public void add(T x){ add(length,x); } //添加至表头 public void addFirst(T x){ add(0,x); } //添加至表尾 public void addLast(T x){ add(length,x); }
接下来是节点删除方法,和add方法类似,注意删的是表头还是表中间
public Lnode<T> removeNode(int i){ Lnode<T> p,q; if (first==null) return null; if (i==0){ p = first; first = first.next; length--; return p; } if (i>=1 && i<=length-1){ p = getNode(i-1); q = p.next; p.next = q.next; if (q==last) last = p; length--; return p; } return null; }根据上面这个节点删除方法,可以进行各种各样的重载。
//删除表头 public T removeFirst(){ return removeNode(0).data; } //删除表尾 public T removeLast(){ return removeNode(length-1).data; } //删除节点 public T remove(){ return removeNode(0).data; } //删除特定的值 public T remove(T x){ int i = indexOf(x); if (i<0) return null; else { return removeNode(i).data; } }
//删除i号节点 public T remove(int i){ Lnode<T> p = removeNode(i); if (p==null) return null; else return p.data; }最后是值查找方法,遍历链表,如果找到相应的节点,返回,否则返回null。
//查找算法 public int indexOf(T key){ Lnode<T> p = getNode(0); int j = 0; while (p!=null && j<length){ if (p.data.equals(key)) return j; p = p.next; j++; } return -1; }
实现迭代器也不难,和ArrayList不同,除了需要判断索引是否超过长度,还要判断当前节点是否为空。
private class LinkedIterator implements Iterator<T>{ private int index = 0; private Lnode<T> current = first; @Override public boolean hasNext() { //在调用next后,index自增,确保index不等于链表的长度 return (index!=length && current!=null); } @Override public T next() { T t = current.data; current = current.next; index++; return t; } }
在最后,源代码附上。
import java.util.Iterator; public class MyLinked<T> implements Iterable<T>{ class Lnode<T>{ public T data; public Lnode<T> next; public Lnode(T key){ data = key; next = null; } } private Lnode<T> first,last; private int length; private Iterator<T> iterator; public MyLinked(){ first = last = null; length = 0; iterator = new LinkedIterator(); } //求长度 public int size(){ return length; } //获取第i个节点 private Lnode<T> getNode(int i){ if (i<0 || i>=length) return null; if (i==0) return first; Lnode<T> p = first; int j=0; while (p!=null && j<i){ p = p.next; j++; } return p; } //获取第i个节点的值 public T get(int i){ Lnode<T> p = getNode(i); if (p==null) return null; else return p.data; } //修改i号节点的值 public boolean set(int i,T x){ Lnode<T> p = getNode(i); if (p==null) return false; else { p.data = x; return true; } } //添加节点 public void add(int i,T x){ int j = i-1; Lnode<T> p; Lnode<T> s = new Lnode<>(x); if (first==null || length == 0){ first =s; last = s; }else if(j<0) { s.next = first; first = s; }else if (j>=length-1){ last.next = s; last = s; }else { p = getNode(j); s.next = p.next; p.next = s; } length++; } //添加至末尾 public void add(T x){ add(length,x); } //添加至表头 public void addFirst(T x){ add(0,x); } //添加至表尾 public void addLast(T x){ add(length,x); } //删除i号节点 public T remove(int i){ Lnode<T> p = removeNode(i); if (p==null) return null; else return p.data; } public Lnode<T> removeNode(int i){ Lnode<T> p,q; if (first==null) return null; if (i==0){ p = first; first = first.next; length--; return p; } if (i>=1 && i<=length-1){ p = getNode(i-1); q = p.next; p.next = q.next; if (q==last) last = p; length--; return p; } return null; } //删除表头 public T removeFirst(){ return removeNode(0).data; } //删除表尾 public T removeLast(){ return removeNode(length-1).data; } //删除节点 public T remove(){ return removeNode(0).data; } //删除特定的值 public T remove(T x){ int i = indexOf(x); if (i<0) return null; else { return removeNode(i).data; } } //查找算法 public int indexOf(T key){ Lnode<T> p = getNode(0); int j = 0; while (p!=null && j<length){ if (p.data.equals(key)) return j; p = p.next; j++; } return -1; } private class LinkedIterator implements Iterator<T>{ private int index = 0; private Lnode<T> current = first; @Override public boolean hasNext() { //在调用next后,index自增,确保index不等于链表的长度 return (index!=length && current!=null); } @Override public T next() { T t = current.data; current = current.next; index++; return t; } } @Override public Iterator<T> iterator() { return new LinkedIterator(); } }