有这样一道算法题, 假设有20个人围成一个圈,现在从第一个人开始报数,数到3的那个人出列,下一个人继续从1开始报数。。。。如此循环,最后剩下的人是谁?
首先我们定义一个单向循环链表
前文(从零开始学算法--自定义单链表 - 倒霉的菜鸟 - 博客园 (cnblogs.com))中已经自定义了单链表, 单向循环链表唯一的区别就是尾节点的next指针指向首节点,
代码实现也和前文类似,不再赘述
1 public class SingleCycleLinkedList<E> { 2 3 //首先定义节点内部类Node 4 class Node<E>{ 5 private E element; 6 private Node<E> nextNode; 7 8 public Node(E element, Node<E> nextNode){ 9 this.element = element; 10 this.nextNode = nextNode; 11 } 12 13 @Override 14 public String toString() { 15 return element.toString(); 16 } 17 } 18 19 private Node<E> firstNode; 20 21 private Node<E> lastNode; 22 23 private int size; 24 25 public void add(E e) { 26 Node<E> node = firstNode; 27 //当前为空链表 28 if (node == null) { 29 Node<E> newNode = new Node(e, lastNode); 30 firstNode = newNode; 31 lastNode = firstNode; 32 }else { 33 //当前不是空链表,则向尾部添加 34 Node<E> newNode = new Node(e, firstNode); 35 lastNode.nextNode = newNode; 36 lastNode = newNode; 37 } 38 size++; 39 } 40 41 /** 42 * 获取指定位置的元素 43 * @param index 44 * @return 45 */ 46 public E get(int index) { 47 return getNode(index).element; 48 } 49 50 private Node<E> getNode(int index){ 51 Node<E> node = firstNode; 52 for (int i = 0; i < index; i++) { 53 node = node.nextNode; 54 } 55 return node; 56 } 57 58 public int size() { 59 return size; 60 } 61 62 /** 63 * 删除指定位置的元素 64 * @param index 65 */ 66 public void remove(int index) { 67 if(index == 0) { 68 Node<E> node = firstNode; 69 firstNode = node.nextNode; 70 lastNode.nextNode = firstNode; 71 } else if(index == size-1){ 72 Node<E> node = lastNode; 73 //找到前一个节点 74 Node<E> preNode = getNode(index-1); 75 preNode.nextNode = firstNode; 76 lastNode = preNode; 77 }else{ 78 //找到前一个节点 79 Node<E> preNode = getNode(index-1); 80 Node<E> nextNode = getNode(index+1); 81 preNode.nextNode = nextNode; 82 } 83 size--; 84 } 85 86 /** 87 * 删除指定节点 88 * @param index 89 */ 90 public void remove(Node<E> targetNode) { 91 if (firstNode == targetNode) { 92 lastNode.nextNode = targetNode.nextNode; 93 firstNode = targetNode.nextNode; 94 } 95 96 Node<E> node = firstNode; 97 for (int i = 0; i < size-1; i++) { 98 Node<E> preNode = node; 99 node = node.nextNode; 100 if(node == targetNode) { 101 preNode.nextNode = node.nextNode; 102 } 103 } 104 size--; 105 } 106 }
再定义一个循环删除的方法
因为链表首位相接,所以我们不能通过Index来判断需要删除哪个元素,只能先定位到起始节点, 然后根据node.nextNode往下个节点移动,每移动3次就执行一次删除动作
给定初始位置Index, 那么起始节点就应该是index-1, 当index为0时, 起始节点为尾节点
1 public void cycleRemove(int beginIndex, int count) { 2 Node<E> targetNode; 3 if (beginIndex == 0) { 4 targetNode = lastNode; 5 }else { 6 targetNode = getNode(beginIndex-1); 7 } 8 while (size >1) { 9 for (int i = 0; i < count; i++) { 10 targetNode = targetNode.nextNode; 11 } 12 remove(targetNode); 13 System.out.println(targetNode.toString()+"出列"); 14 15 } 16 17 }
测试方法如下
public static void main(String[] args) { SingleCycleLinkedList myList = new SingleCycleLinkedList(); for (int i = 1; i < 21; i++) { myList.add(i); } for (int i = 0; i < myList.size(); i++) { System.out.print(myList.get(i).toString()+" "); } System.out.print("\n"); myList.cycleRemove(0, 3); System.out.print("\n after remove:"); for (int i = 0; i < myList.size(); i++) { System.out.print(myList.get(i).toString()+" "); } }
运行结果