// used for Object, null included
 // and here use hashmap rather than hashtable,
 // for any null object can not be used as a key or as a value in hashtable.
 static void doRemove1(SinglyLinkedList<Character> s) {
   HashMap<Character, Boolean> map = new HashMap<Character, Boolean>();
   SinglyLinkedList.Node<Character> pre = null;
   SinglyLinkedList.Node<Character> node = s.getHead();
   while (node != null) {
     if (map.containsKey(node.item)) {
       pre.next = node.next;
       s.decreaseSize();
     } else {
       map.put(node.item, true);
       // 发现新值后再改变pre,不需要把head单独考虑,因为是从后面开始删除
       pre = node;
     }
     // pre = node;
     node = node.next;
   }
 }
  // only for Character, assume all ascii, without null
  static void doRemove(SinglyLinkedList<Character> s) {
    boolean[] check = new boolean[256];

    SinglyLinkedList.Node<Character> pre = null;
    SinglyLinkedList.Node<Character> node = s.getHead();
    while (node != null) {
      if (node.item == null) {
        System.out.println("---- Warning: null included! remove fail, use function doRemove1()");
        return;
      }
      if (check[node.item]) {
        pre.next = node.next;
        s.decreaseSize();
      } else // else 可以节省运算次数
      check[node.item] = true;
      pre = node;
      node = node.next;
    }
  }
 // use three references, pre, current, runner. No space consume
 static void doRemove2(SinglyLinkedList<Character> s) {
   SinglyLinkedList.Node<Character> pre = null;
   SinglyLinkedList.Node<Character> current = null;
   SinglyLinkedList.Node<Character> runner = null;
   pre = s.getHead();
   current = pre.next;
   while (current != null) {
     runner = s.getHead();
     while (runner != current) {
       if (runner.item == current.item) {
         pre.next = current.next;
         current = current.next;
         s.decreaseSize();
         break;
       }
       runner = runner.next;
     }
     if (runner == current) {
       pre = current;
       current = current.next;
     }
   }
 }