fork download
  1. import java.util.AbstractList;
  2. import java.util.Iterator;
  3. import java.util.Random;
  4.  
  5. import java.util.NoSuchElementException;
  6.  
  7. /**
  8.   * A singly linked null-terminated list implementation.
  9.   */
  10. class LinkedList<E> extends AbstractList<E> {
  11. private Node<E> head = null;
  12. private Node<E> tail = null;
  13. private int size = 0;
  14.  
  15. /**
  16.   * In-place O(NlgN) shuffle.
  17.   */
  18. public void shuffle(Random random) {
  19. head = shuffle(0, size(), head, random);
  20. tail = head;
  21. while (tail.next != null) {
  22. tail = tail.next;
  23. }
  24. }
  25.  
  26. /**
  27.   * Shuffles the specified sublist starting from the lo's index
  28.   * and ending right before the hi's index. Requires you to
  29.   * pass a reference to the element at the lo index, so that
  30.   * the method wouldn't have to search for that element by itself.
  31.   * @return head element of the shuffled null-terminated sublist.
  32.   */
  33. private Node<E> shuffle(int lo, int hi,
  34. Node<E> loElement, Random random) {
  35. if (hi - lo == 1) {
  36. // null-terminate a single-element list
  37. loElement.next = null;
  38. return loElement;
  39. }
  40. int mid = (lo + hi) >>> 1;
  41. Node<E> midElement = loElement;
  42. for (int i = lo; i < mid; i++) {
  43. midElement = midElement.next;
  44. }
  45.  
  46. loElement = shuffle(lo, mid, loElement, random);
  47. midElement = shuffle(mid, hi, midElement, random);
  48. return mergeShuffledLists(
  49. lo, loElement,
  50. mid, midElement,
  51. hi, random
  52. );
  53. }
  54.  
  55. /**
  56.   * Merges two shuffled halves of the list into a single one
  57.   * in a way that the resulting list is uniformly shuffled
  58.   * (given that the specified sublists are uniformly shuffled).
  59.   * @return head element of the merged null-terminated list.
  60.   */
  61. private Node<E> mergeShuffledLists(
  62. int iLeftSublist, Node<E> leftSublistIter,
  63. int iRightSublist, Node<E> rightSublistIter,
  64. int hi, Random random) {
  65. int mid = iRightSublist;
  66. double sublistSize = hi - iLeftSublist;
  67. // initialize with dummy node to avoid both copy-paste code,
  68. // when initializing newHead with the initial value,
  69. // and excessive not-null checks inside the loop
  70. Node<E> newHead = new Node<>(null, null);
  71. Node<E> newListIter = newHead;
  72.  
  73. while (leftSublistIter != null || rightSublistIter != null) {
  74. double decision = random.nextDouble();
  75. if (rightSublistIter == null
  76. || decision < (mid - iLeftSublist) / sublistSize) {
  77. newListIter.next = leftSublistIter;
  78. leftSublistIter = leftSublistIter.next;
  79. iLeftSublist++;
  80. } else {
  81. newListIter.next = rightSublistIter;
  82. rightSublistIter = rightSublistIter.next;
  83. iRightSublist++;
  84. }
  85. newListIter = newListIter.next;
  86. }
  87. // null-terminate reassembled list
  88. newListIter.next = null;
  89. // skip the dummy node
  90. return newHead.next;
  91. }
  92.  
  93. @SuppressWarnings("unchecked")
  94. /**
  95.   * Linear time shuffle that uses O(N) extra memory
  96.   */
  97. public void linearShuffle(Random random) {
  98. if (size() > 1) {
  99. Object[] nodes = new Object[size()];
  100. shuffle(nodes, random);
  101. head = (Node<E>) nodes[0];
  102. tail = head;
  103. for (int i = 1; i < nodes.length; i++) {
  104. tail.next = (Node<E>) nodes[i];
  105. tail = tail.next;
  106. }
  107. }
  108. }
  109.  
  110. /**
  111.   * Uniformly shuffles the array using the specified {@code random}
  112.   * instance.
  113.   */
  114. private static void shuffle(Object[] array, Random random) {
  115. final int n = array.length;
  116. for (int i = 0; i < n - 1; i++) {
  117. swap(array, i, i + random.nextInt(n - i - 1) + 1);
  118. }
  119. }
  120.  
  121. /**
  122.   * Swaps the elements at the specified indices of the {@code array}.
  123.   * @throws IndexOutOfBoundsException if either of the specified
  124.   * indices is out of range.
  125.   */
  126. public static void swap(Object[] array, int i, int j) {
  127. if (!rangeCheck(array, i) || !rangeCheck(array, j)) {
  128. "Got: i = %d, j = %d meanwhile = len(array) = %d",
  129. i, j, array.length
  130. ));
  131. }
  132. Object swap = array[i];
  133. array[i] = array[j];
  134. array[j] = swap;
  135. }
  136.  
  137. @Override
  138. /**
  139.   * Returns the element at the specified position in the list.
  140.   * This method runs at O(N) time since it has to go from
  141.   * the head of the list to the target element.
  142.   */
  143. public E get(int index) {
  144. if (index < 0 || index >= size()) {
  145. "Got: index = %d, size = %d", index, size()
  146. ));
  147. }
  148. int iCurrent = 0;
  149. Node<E> current = head;
  150. while (iCurrent != index) {
  151. current = current.next;
  152. iCurrent++;
  153. }
  154. return current.value;
  155. }
  156.  
  157. /**
  158.   * Checks, if the specified index belongs to the array.
  159.   * @return {@code false} in case the index is out of range
  160.   * or the {@code array} argument is null.
  161.   */
  162. private static boolean rangeCheck(Object[] array, int index) {
  163. if (array == null) {
  164. return false;
  165. }
  166. if (index < 0 || index >= array.length) {
  167. return false;
  168. }
  169. return true;
  170. }
  171.  
  172. @Override
  173. /**
  174.   * Appends the specified element to the end of the list.
  175.   * @return {@code true} in case the collection changed
  176.   * as a result of the call.
  177.   */
  178. public boolean add(E value) {
  179. assert (head == null) == (tail == null);
  180.  
  181. if (value == null) {
  182. "Null elements are not allowed"
  183. );
  184. }
  185.  
  186. if (head == null) {
  187. head = new Node<>(value, null);
  188. tail = head;
  189. } else {
  190. tail.next = new Node<>(value, null);
  191. tail = tail.next;
  192. }
  193. size++;
  194. return true;
  195. }
  196.  
  197. @Override
  198. /**
  199.   * Inserts a new element at the specified position.
  200.   */
  201. public void add(int index, E value) {
  202. assert (head == null) == (tail == null);
  203.  
  204. if (value == null) {
  205. "Null elements are not allowed"
  206. );
  207. }
  208. if (index < 0 || index > size()) {
  209. "Got: index = %d, size = %d", index, size()
  210. ));
  211. }
  212.  
  213. if (index == 0) {
  214. head = new Node<>(value, head);
  215. if (tail == null) {
  216. tail = head;
  217. }
  218. } else {
  219. int iCurrent = 0;
  220. Node<E> current = head;
  221. while (iCurrent < index - 1) {
  222. current = current.next;
  223. iCurrent++;
  224. }
  225. current.next = new Node<>(value, current.next);
  226. if (index == size()) {
  227. tail = current.next;
  228. }
  229. }
  230. size++;
  231. }
  232.  
  233. @Override
  234. /**
  235.   * Returns the size of the array.
  236.   * The implementation is based on just keeping a {@code size}
  237.   * variable which is being updated after every list mutation.
  238.   * Thus the returned value does not depend on whether the
  239.   * list is null-terminated or not.
  240.   */
  241. public int size() {
  242. return size;
  243. }
  244.  
  245. @Override
  246. /**
  247.   * Clears the list.
  248.   */
  249. public void clear() {
  250. head = null;
  251. tail = null;
  252. size = 0;
  253. }
  254.  
  255. @Override
  256. /**
  257.   * Removes the element with the specified index from the list
  258.   */
  259. public E remove(int index) {
  260. if (index < 0 || index >= size()) {
  261. "Got: index = %d, size = %d", index, size()
  262. ));
  263. }
  264. E value = null;
  265. if (index == 0) {
  266. value = head.value;
  267. head = head.next;
  268. if (head == null) {
  269. tail = null;
  270. }
  271. } else {
  272. int iCurrent = 0;
  273. Node<E> current = head;
  274. while (iCurrent < index - 1) {
  275. current = current.next;
  276. iCurrent++;
  277. }
  278. value = current.next.value;
  279. current.next = current.next.next;
  280. if (index == size() - 1) {
  281. tail = current;
  282. }
  283. }
  284. size--;
  285. return value;
  286. }
  287.  
  288. @Override
  289. public boolean isEmpty() {
  290. return size() == 0;
  291. }
  292.  
  293. @Override
  294. public E set(int index, E value) {
  295. if (value == null) {
  296. "Null elements are not allowed"
  297. );
  298. }
  299. if (index < 0 || index >= size()) {
  300. "Got: index = %d, size = %d", index, size
  301. ));
  302. }
  303.  
  304. int iCurrent = 0;
  305. Node<E> current = head;
  306. while (iCurrent < index) {
  307. current = current.next;
  308. iCurrent++;
  309. }
  310. E previousValue = current.value;
  311. current.value = value;
  312. return previousValue;
  313. }
  314.  
  315. @Override
  316. public Iterator<E> iterator() {
  317. return new LinkedListIterator(head);
  318. }
  319.  
  320. @Override
  321. public String toString() {
  322. StringBuilder sb = new StringBuilder("[ ");
  323. for (E element : this) {
  324. sb.append(String.format("%s ", element));
  325. }
  326. sb.append("]");
  327. return sb.toString();
  328. }
  329.  
  330. private static class Node<T> {
  331. private T value;
  332. private Node<T> next = null;
  333.  
  334. public Node(T value, Node<T> next) {
  335. this.value = value;
  336. this.next = next;
  337. }
  338. }
  339.  
  340. /**
  341.   * An iterator that sequentially returns the elements in order.
  342.   * Works in a null-termination manner, so you must
  343.   * make sure that the list is null-terminated.
  344.   */
  345. private class LinkedListIterator implements Iterator<E> {
  346. private Node<E> current;
  347.  
  348. private Node<E> beforePrevious = null;
  349. private int iBeforePrevious = -2;
  350. private boolean removeCalled = false;
  351.  
  352. public LinkedListIterator(Node<E> head) {
  353. current = head;
  354. }
  355.  
  356. @Override
  357. public boolean hasNext() {
  358. return current != null;
  359. }
  360.  
  361. @Override
  362. public E next() {
  363. if (current == null) {
  364. throw new NoSuchElementException("The list is empty");
  365. }
  366. E value = current.value;
  367. iBeforePrevious++;
  368. if (iBeforePrevious > 0) {
  369. beforePrevious = current;
  370. } else if (iBeforePrevious == 0) {
  371. beforePrevious = head;
  372. }
  373. current = current.next;
  374. return value;
  375. }
  376.  
  377. @Override
  378. public void remove() {
  379. if (!removeCalled) {
  380. if (iBeforePrevious >= 0) {
  381. beforePrevious.next = beforePrevious.next.next;
  382. size--;
  383. } else if (iBeforePrevious == -1) {
  384. head = current;
  385. size--;
  386. } else {
  387. "next() has not yet been called"
  388. );
  389. }
  390. } else {
  391. "remove() has already been called once after"
  392. + "the next() call."
  393. );
  394. }
  395. }
  396. }
  397.  
  398. public static void main(String[] args) {
  399. LinkedList<Integer> list = new LinkedList<>();
  400. for (int i = 0; i < 10; i++) {
  401. list.add(i);
  402. }
  403. System.out.println(list);
  404. list.shuffle(new Random());
  405. System.out.println(list);
  406. }
  407. }
Success #stdin #stdout 0.08s 34420KB
stdin
Standard input is empty
stdout
[ 0 1 2 3 4 5 6 7 8 9 ]
[ 3 6 8 5 9 7 1 2 4 0 ]