1 import java.util.Iterator; 2 import java.util.NoSuchElementException; 3 4 public class List<Item> implements Iterable<Item> 5 { 6 private int N; 7 private Node first; 8 private Node last; 9 10 private class Node 11 { 12 private Item item; 13 private Node next; 14 } 15 16 public List() 17 { 18 first = null; 19 last = null; 20 } 21 22 public List(Item[] a) 23 { 24 for (Item t : a) 25 append(t); 26 } 27 28 public List(Iterable<Item> coll) 29 { 30 for (Item t : coll) 31 append(t); 32 } 33 34 public boolean isEmpty() 35 { 36 return first == null; 37 } 38 39 public int size() 40 { 41 return N; 42 } 43 44 public Item first() 45 { 46 if (isEmpty()) throw new RuntimeException("List is empty"); 47 return first.item; 48 } 49 50 public Item last() 51 { 52 if (isEmpty()) throw new RuntimeException("List is empty"); 53 return last.item; 54 } 55 56 public Item removeFirst() 57 { 58 if (isEmpty()) throw new RuntimeException("List is empty"); 59 Item item = first.item; 60 first = first.next; 61 N--; 62 if (isEmpty()) last = null; // to avoid loitering 63 return item; 64 } 65 66 public void prepend(Item item) 67 { 68 Node x = new Node(); 69 x.item = item; 70 if (isEmpty()) { first = x; last = x; } 71 else { x.next = first; first = x; } 72 N++; 73 } 74 75 public void append(Item item) 76 { 77 Node x = new Node(); 78 x.item = item; 79 if (isEmpty()) { first = x; last = x; } 80 else { last.next = x; last = x; } 81 N++; 82 } 83 84 public String toString() 85 { 86 StringBuilder s = new StringBuilder(); 87 for (Item item : this) 88 s.append(item + " "); 89 return s.toString(); 90 } 91 92 public Iterator<Item> iterator() 93 { 94 return new ListIterator(); 95 } 96 97 private class ListIterator implements Iterator<Item> 98 { 99 private Node current = first; 100 101 public boolean hasNext() { return current != null; } 102 public void remove() { throw new UnsupportedOperationException(); } 103 104 public Item next() 105 { 106 if (!hasNext()) throw new NoSuchElementException(); 107 Item item = current.item; 108 current = current.next; 109 return item; 110 } 111 } 112 113 /***************** 114 * Exercise 1.3.19 115 *****************/ 116 public Item removeLast() 117 { 118 if (isEmpty()) throw new RuntimeException("List is empty"); 119 if (first == last) return removeFirst(); 120 Item item = last.item; 121 122 Node prev = null, 123 curr = first; 124 while (curr.next != null) 125 { 126 prev = curr; 127 curr = curr.next; 128 } 129 prev.next = null; 130 last = prev; 131 N--; 132 133 return item; 134 } 135 136 /***************** 137 * Exercise 1.3.20 138 *****************/ 139 public Item delete(int k) 140 { 141 if (k < 1) return null; 142 143 int i = 1; 144 Node prev = null, 145 curr = first; 146 147 while (i < k && curr != null) 148 { 149 prev = curr; 150 curr = curr.next; 151 i++; 152 } 153 154 if (curr != null) 155 { 156 if (prev == null) 157 first = curr.next; 158 else 159 prev.next = curr.next; 160 161 if (curr.next == null) 162 last = prev; 163 164 N--; 165 return curr.item; 166 } 167 else 168 return null; 169 } 170 171 /************************************* 172 * Exercise 1.3.21 173 * (Renamed from find() to contains()) 174 *************************************/ 175 public boolean contains(Item item) 176 { 177 Node curr = first; 178 while (curr != null && !curr.item.equals(item)) 179 curr = curr.next; 180 return curr != null; 181 } 182 183 /***************** 184 * Exercise 1.3.26 185 *****************/ 186 public void remove(Item item) 187 { 188 List<Integer> idx = new List<Integer>(); 189 int i = 1; 190 191 for (Item x : this) 192 { 193 if (x.equals(item)) 194 idx.prepend(i); 195 i++; 196 } 197 198 for (int k : idx) 199 delete(k); 200 } 201 202 /*************************************** 203 * Recursive solution to Exercise 1.3.26 204 ***************************************/ 205 public void removeRec(Item item) 206 { 207 first = remove_Node(first, item); 208 setLastAndN(); 209 } 210 211 private Node remove_Node(Node node, Item item) 212 { 213 if (node != null) 214 { 215 Node rest = remove_Node(node.next, item); 216 217 if (node.item.equals(item)) 218 return rest; 219 else 220 { 221 node.next = rest; 222 return node; 223 } 224 } 225 else 226 return null; 227 } 228 229 private void setLastAndN() 230 { 231 last = first; 232 N = 0; 233 if (first != null) 234 { 235 N++; 236 while (last.next != null) 237 { 238 last = last.next; 239 N++; 240 } 241 } 242 } 243 244 245 /********************* 246 * Operations on nodes 247 *********************/ 248 249 public Node node(int k) 250 { 251 if (k < 1) return null; 252 253 int i = 1; 254 Node curr = first; 255 256 while (i < k && curr != null) 257 { 258 curr = curr.next; 259 i++; 260 } 261 262 return curr; 263 } 264 265 public Node createNode(Item item) 266 { 267 Node node = new Node(); 268 node.item = item; 269 return node; 270 } 271 272 /***************** 273 * Exercise 1.3.24 274 *****************/ 275 public void removeAfter(Node node) 276 { 277 if (node != null && node.next != null) 278 { 279 if (node.next.next == null) 280 last = node; 281 node.next = node.next.next; 282 N--; 283 } 284 } 285 286 /***************** 287 * Exercise 1.3.25 288 *****************/ 289 public void insertAfter(Node a, Node b) 290 { 291 if (a != null && b != null) 292 { 293 if (last == a) 294 last = b; 295 b.next = a.next; 296 a.next = b; 297 N++; 298 } 299 } 300 301 /************************************************* 302 * Exercise 1.3.27 303 * Type 'Item' must implement interface Comparable 304 *************************************************/ 305 public Item max(Node node) 306 { 307 if (node == null) throw new RuntimeException("List is empty"); 308 return max(node, null); 309 } 310 311 public Item max(Node node, Item def) 312 { 313 if (node == null) 314 return def; 315 316 Item max = node.item; 317 Node curr = node; 318 319 while (curr.next != null) 320 { 321 curr = curr.next; 322 if (((Comparable)max).compareTo(curr.item) < 0) 323 max = curr.item; 324 } 325 326 return max; 327 } 328 329 /************************************************* 330 * Exercise 1.3.28 331 * (recursive variant of Exercise 1.3.27) 332 * Type 'Item' must implement interface Comparable 333 *************************************************/ 334 public Item maxRec(Node node, Item def) 335 { 336 if (node == null) 337 return def; 338 else 339 return maxRec(node); 340 } 341 342 public Item maxRec(Node node) 343 { 344 if (node == null) throw new RuntimeException("List is empty"); 345 346 if (node.next == null) 347 return node.item; 348 else 349 { 350 Item maxTail = maxRec(node.next); 351 return ((Comparable)node.item).compareTo(maxTail) > 0 ? node.item : maxTail; 352 } 353 } 354 355 /***************** 356 * Exercise 1.3.30 357 *****************/ 358 public void reverse() 359 { 360 first = reverse(first); 361 setLastAndN(); 362 } 363 364 public Node reverse(Node node) 365 { 366 Node srcFirst = node, 367 destFirst = null; 368 while (srcFirst != null) 369 { 370 Node next = srcFirst.next; 371 srcFirst.next = destFirst; 372 destFirst = srcFirst; 373 srcFirst = next; 374 } 375 376 return destFirst; 377 } 378 379 /*************************************** 380 * Recursive solution to Exercise 1.3.30 381 ***************************************/ 382 public void reverseRec() 383 { 384 first = reverseRec(first); 385 setLastAndN(); 386 } 387 388 private Node reverseRec(Node node) 389 { 390 return reverseRec(node, null); 391 } 392 393 private Node reverseRec(Node srcFirst, Node destFirst) 394 { 395 if (srcFirst == null) 396 return destFirst; 397 else 398 { 399 Node next = srcFirst.next; 400 srcFirst.next = destFirst; 401 return reverseRec(next, srcFirst); 402 } 403 } 404 405 406 /************ 407 * Unit tests 408 ************/ 409 410 private static void testBaseMethods() 411 { 412 int[] a = { 2, 4, 6, 8, 10, 12 }; 413 414 List<Integer> lst = new List<Integer>(); 415 for (int i = 0; i < a.length; i++) 416 lst.append(a[i]); 417 showList(lst); 418 419 lst = new List<Integer>(); 420 for (int i = 0; i < a.length; i++) 421 lst.prepend(a[i]); 422 showList(lst); 423 424 StdOut.println("removeFirst: " + lst.removeFirst()); 425 showList(lst); 426 } 427 428 private static void testRemoveLast() 429 { 430 List<Integer> lst = new List<Integer>(new Integer[] { 6, 8, 10, 12 }); 431 showList(lst); 432 433 while (!lst.isEmpty()) 434 { 435 StdOut.println("removeLast: " + lst.removeLast()); 436 showList(lst); 437 } 438 } 439 440 private static void testDelete() 441 { 442 List<Integer> lst = new List<Integer>(new Integer[] { 2, 4, 6, 8, 10, 12 }); 443 showList(lst); 444 445 StdOut.printf("delete(%d): %s ", 5, lst.delete(5)); 446 showList(lst); 447 448 StdOut.printf("delete(%d): %s ", 1, lst.delete(1)); 449 showList(lst); 450 451 StdOut.printf("delete(%d): %s ", 4, lst.delete(4)); 452 showList(lst); 453 454 StdOut.printf("delete(%d): %s ", 8, lst.delete(8)); 455 showList(lst); 456 457 StdOut.printf("delete(%d): %s ", 0, lst.delete(0)); 458 showList(lst); 459 460 while (!lst.isEmpty()) 461 { 462 StdOut.printf("delete(%d): %s ", 1, lst.delete(1)); 463 showList(lst); 464 } 465 } 466 467 private static void testContains() 468 { 469 Integer[] a = { 4, 6, 10, 12 }; 470 List<Integer> lst = new List<Integer>(a); 471 showList(lst); 472 473 StdOut.printf("contains(%d): %s ", 0, lst.contains(0)); 474 475 for (int i = 0; i < a.length; i++) 476 StdOut.printf("contains(%d): %s ", a[i], lst.contains(a[i])); 477 } 478 479 private static void testRemove() 480 { 481 for (int k = 0; k < 8; k++) 482 { 483 List<Integer> lst1 = randomList(20, 0, 5); 484 List<Integer> lst2 = new List<Integer>(lst1); 485 StdOut.println(lst1); 486 StdOut.println(); 487 488 int n = StdRandom.uniform(0, 5); 489 490 StdOut.printf("remove(%d): ", n); 491 lst1.remove(n); 492 showList(lst1); 493 494 StdOut.printf("removeRec(%d): ", n); 495 lst2.removeRec(n); 496 showList(lst2); 497 StdOut.println(); 498 } 499 } 500 501 private static void testReverse() 502 { 503 int n = 10; 504 Integer[] a = new Integer[n]; 505 for (int i = 0; i < n; i++) 506 a[i] = 2 * (i + 1); 507 508 testReverse(new List<Integer>(a)); 509 StdOut.println(); 510 511 testReverse(randomList(20, 0, 10)); 512 StdOut.println(); 513 514 testReverse(new List<Integer>(new Integer[] { 37 })); 515 StdOut.println(); 516 517 testReverse(new List<Integer>(new Integer[] { })); 518 StdOut.println(); 519 } 520 521 private static void testReverse(List<Integer> lst) 522 { 523 List<Integer> lst1 = lst; 524 List<Integer> lst2 = new List<Integer>(lst1); 525 StdOut.println(lst1); 526 527 StdOut.println("reverse():"); 528 lst1.reverse(); 529 StdOut.println(lst1); 530 531 StdOut.println("reverseRec():"); 532 lst2.reverseRec(); 533 StdOut.println(lst2); 534 } 535 536 private static void testNode() 537 { 538 List<Integer> lst = new List<Integer>(new Integer[] { 2, 6, 12 }); 539 showList(lst); 540 541 for (int i = -1; i <= 4; i++) 542 StdOut.printf("node(%d): %s ", i, lst.node(i) != null ? lst.node(i).item : null); 543 } 544 545 private static void testRemoveAfter() 546 { 547 List<Integer> lst = new List<Integer>(new Integer[] { 2, 6, 8, 10, 12 }); 548 showList(lst); 549 550 int[] k = { 0, 2, 1, 5, 3, 2, 1 }; 551 552 for (int i = 0; i < k.length; i++) 553 { 554 StdOut.printf("removeAfter(node(%d)): ", k[i]); 555 lst.removeAfter(lst.node(k[i])); 556 showList(lst); 557 } 558 } 559 560 private static void testInsertAfter() 561 { 562 List<Integer> lst = new List<Integer>(new Integer[] { 2, 6, 10, 12 }); 563 showList(lst); 564 565 StdOut.printf("insertAfter(node(%d), null): ", 1); 566 lst.insertAfter(lst.node(1), null); 567 showList(lst); 568 569 int ia = 1, 570 b = 3; 571 StdOut.printf("insertAfter(node(%d), createNode(%d)): ", ia, b); 572 lst.insertAfter(lst.node(ia), lst.createNode(b)); 573 showList(lst); 574 575 ia = 5; 576 b = 25; 577 StdOut.printf("insertAfter(node(%d), createNode(%d)): ", ia, b); 578 lst.insertAfter(lst.node(ia), lst.createNode(b)); 579 showList(lst); 580 } 581 582 private static void testMax() 583 { 584 for (int k = 0; k < 8; k++) 585 { 586 List<Integer> lst = randomList(10, 100, 1000); 587 StdOut.println(lst); 588 589 StdOut.printf("max(): %d ", lst.max(lst.node(1))); 590 StdOut.printf("maxRec(): %d ", lst.maxRec(lst.node(1))); 591 } 592 } 593 594 595 /******************* 596 * Unit test helpers 597 *******************/ 598 599 public static void showList(List lst) 600 { 601 StdOut.println(lst); 602 if (!lst.isEmpty()) 603 StdOut.printf("Size: %d, First: %s, Last: %s ", lst.size(), lst.first(), lst.last()); 604 else 605 StdOut.printf("Size: %d ", lst.size()); 606 } 607 608 private static List<Integer> randomList(int n, int a, int b) 609 { 610 Integer[] r = new Integer[n]; 611 for (int i = 0; i < n; i++) 612 r[i] = StdRandom.uniform(a, b); 613 return new List<Integer>(r); 614 } 615 616 public static void main(String[] args) 617 { 618 testBaseMethods(); 619 StdOut.println(); 620 621 testRemoveLast(); 622 StdOut.println(); 623 624 testDelete(); 625 StdOut.println(); 626 627 testContains(); 628 StdOut.println(); 629 630 testNode(); 631 StdOut.println(); 632 633 testRemoveAfter(); 634 StdOut.println(); 635 636 testInsertAfter(); 637 StdOut.println(); 638 639 testRemove(); 640 StdOut.println(); 641 642 testMax(); 643 StdOut.println(); 644 645 testReverse(); 646 StdOut.println(); 647 } 648 }