上篇我对BigInteger 膜拜了一番,以为很复杂呢,结果看jdk带的源码,也就一个3000行java文件而已。因而右必要自己亲自写一些底层的东西。
一来是为了练手,二来是为了体会java的思维方式,三是比较C++的后继者们扬弃了什么。
废话不说,要点都写在注释里面了:
/*LinkedListTest.java --模仿C风格的双链表 1. head->func(head) 通过this变成head.func()。 2. C宏/模板 --> 泛型,在方法头上加 public <T extends Comparable<? super T>> public <T extends Comparable<T>> 虽然可以编译,但是不能调用这个类的其他方法。 通过搜索keywords:"Comparable generic type" 正确的办法是在泛型类定义时 DNode<T> 改成 DNode<T extends Comparable<T>> extends 表示限定。 * author ludi 2014.03*/ class DNode<T extends Comparable<T>> { public T val; public DNode<T> next, prev; /*链表通常是双向的, 并且使得某些操作更简单*/ public DNode(){ /*创建链表头一般val置为空,当然我们也可以拿来当作链表个数*/ val = null; next = prev = this; } public DNode(T item){ val = item; next = prev = this; /*这里为什么不是null? * 目的是形成一个闭环,设链表最后一个节点是tail, * 则head->prev = tail; tail.next = head. * 闭环的优点是使后面的插入删除的操作不必判断指针是否为空*/ } /*因为参数是泛型<T>,只好把链表所有方法都放在DNode<T>里面了*/ public String toString(){ String str = "["; /*遍历模板:计数,查找,...*/ DNode<T> curr = this.next; while(curr != this){ if(curr.val != null)str += curr.val.toString() + ", "; curr = curr.next; } str += "]"; return str; } public DNode<T> indexOf( int idx){ DNode<T> curr = this.next; for(; curr != this; curr = curr.next){ if(0 == idx)break; --idx; } return (0 == idx) ? curr : null; } public void insertAfter(DNode<T> node, DNode<T> x){ x.next = node.next; node.next.prev = x; x.prev = node; node.next = x; } public void insertTail( DNode<T> x){ insertAfter(this.prev, x); } public DNode<T> deleteAfter(DNode<T> node){ DNode<T> x = node.next; x.next.prev = node; node.next = x.next; return x; } /*上面的几个方法是基本操作,对于用作一般链表,链表形式的栈,队列已经足够了。 * 下面的仅仅是练习题目*/ public void reverseList(){ /*链表翻转, 类似于数组翻转。(如果是单链表,如何?)*/ DNode<T> first = this.next, last = this.prev; while(first != last){ T val = first.val; first.val = last.val; last.val = val; first = first.next; last = last.prev; } } public void deleteAll(){ /*清空链表*/ DNode<T> x = null; while(this.next != this){ x = deleteAfter(this); x = null; } } public DNode<T> insertionSort() {/*递增排序*/ DNode<T> list = new DNode<T>(), j = null, x = null; DNode<T> head = this; x = head.deleteAfter(head); for(; x != head; x = head.deleteAfter(head)){ /*<= 导致不稳定排序。查找如果从前往后就不能体现插入排序的优势了*/ j = list.prev; while(j != list && x.val.compareTo(j.val) < 0){ j = j.prev; /*如果是数组,这里边移位arr[j+1] = arr[j]。 * 由此看出,只有sizeof(T)大于计算机字长时,链表形式的才更快*/ } System.out.println(list.toString() + " <-- " + x.val + " at " + j.val); list.insertAfter(j, x); } return list; } public int search( T val){ /*如果没有找到返回-1*/ DNode<T> first = this.next; int idx = 0; for(; first != this; first = first.next){ if(0 == first.val.compareTo(val))return idx; ++idx; } System.out.printf("===xx\n"); /*这个为什么没有打出来?A: 不要这样调println(search(i));*/ return -1; } } public class LinkedListTest{ public static void main(String[] arg){ /*创建链表头,节点引用*/ DNode<Integer> head = new DNode<Integer>(), node = null, curr = null; int i; for(i = 0; i < 5; ++i){ node = new DNode<Integer>(2*i); head.insertTail(node); } System.out.println(head.toString() ); for(i = 0; i < 5; ++i){ node = new DNode<Integer>(2*i+1); head.insertAfter(head, node); } System.out.println(head.toString() ); i = 5; node = head.indexOf(i); head.deleteAfter(node); System.out.printf("delete afert %d-th %d:\n", i, node.val); System.out.println(head.toString() ); head.reverseList(); System.out.println("reversed:\n" + head.toString()); node = head.insertionSort(); head = null; head = node; /*防内存泄露, 编译器会不会自动搞?*/ System.out.println("Sorted:\n" + head.toString()); i = 6; System.out.printf("Search %d at pos %d\n", i, head.search( i)); head.deleteAll(); System.out.println("deleteAll:\n" + head.toString()); head = null; } } /* ludi@ubun:~/java $ javac -encoding UTF-8 LinkedListTest.java && java LinkedListTest [0, 2, 4, 6, 8, ] [9, 7, 5, 3, 1, 0, 2, 4, 6, 8, ] delete afert 5-th 0: [9, 7, 5, 3, 1, 0, 4, 6, 8, ] reversed: [8, 6, 4, 0, 1, 3, 5, 7, 9, ] Sorted: [0, 1, 3, 4, 5, 6, 7, 8, 9, ] Search 6 at pos 5 deleteAll: [] ludi@ubun:~/java $ */