Ex1_3_31 双向链表DulLinkList
  1. import edu.princeton.cs.algs4.StdIn;
  2. import edu.princeton.cs.algs4.StdOut;
  3. public class DulLinkList<Item> {
  4. private class DulNode {
  5. Item item;
  6. DulNode left;
  7. DulNode right;
  8. }
  9. private DulNode head;
  10. private DulNode tail;
  11. private int size;
  12. public int getSize() {
  13. return size;
  14. }
  15. public boolean isEmpty() {
  16. return head == null;
  17. }
  18. //从表头插入节点
  19. public void headInsert(Item item) {
  20. DulNode current = head;
  21. head = new DulNode();
  22. head.item = item;
  23. if (isEmpty()) {
  24. tail = head;
  25. }//链表为空时head,tail指向一个节点
  26. else {
  27. head.right = current;
  28. }
  29. size++;
  30. }
  31. //从表尾插入节点
  32. public void tailInsert(Item item) {
  33. DulNode current = tail;
  34. tail = new DulNode();
  35. tail.item = item;
  36. tail.left = current;
  37. if (isEmpty()) {
  38. head = tail;//tail = head错误,两个永远为null
  39. }//链表为空时head,tail指向一个节点
  40. else {
  41. current.right = tail;
  42. }
  43. size++;
  44. }
  45. //从表头删除节点
  46. public Item headDel() {
  47. Item item = head.item;
  48. head = head.right;
  49. size--;
  50. return item;
  51. }
  52. //从表尾删除节点
  53. public Item tailDel() {
  54. Item item = tail.item;
  55. tail = tail.left;
  56. size--;
  57. return item;
  58. }
  59. //在指定节点前插入节点
  60. public void beforeInsert(DulNode exist, Item item) {
  61. DulNode dulNode = new DulNode();
  62. dulNode.item = item;
  63. if(exist.left == null) headInsert(item);
  64. else{
  65. exist.left.right = dulNode;
  66. dulNode.left = exist.left;
  67. exist.left = dulNode;
  68. dulNode.right = exist;
  69. size++;
  70. }
  71. }
  72. //在指定节点后插入节点
  73. public void afterInsert(DulNode exist, Item item){
  74. DulNode dulNode = new DulNode();
  75. dulNode.item = item;
  76. if(exist.right == null) tailInsert(item);
  77. else{
  78. exist.right.left = dulNode;
  79. dulNode.right = exist.right;
  80. exist.right = dulNode;
  81. dulNode.left = exist;
  82. size++;
  83. }
  84. }
  85. //删除指定节点
  86. public Item del(DulNode dulNode){
  87. Item item = dulNode.item;
  88. if (dulNode == head) headDel();
  89. else if(dulNode == tail) tailDel();
  90. else{
  91. dulNode.left.right = dulNode.right;
  92. dulNode.right.left = dulNode.left;
  93. }
  94. return item;
  95. }
  96. //测试用例
  97. public static void main(String[] args){
  98. DulLinkList linkList = new DulLinkList();
  99. while(!StdIn.isEmpty()){
  100. String s = StdIn.readString();
  101. linkList.tailInsert(s);
  102. }
  103. linkList.beforeInsert(linkList.head,-1);
  104. StdOut.println(linkList.size + " elements");
  105. StdOut.println(linkList.head.item);
  106. StdOut.println(linkList.tail.item);
  107. }
  108. }

要点:

  1. 插入节点时,当链表为空,head,tail都指向新节点,注意
  1. //实例化表头
  2. DulNode current = head;
  3. head = new DulNode();
  4. head.item = item;
  5. if (isEmpty()) {
  6. tail = head;
  7. }//链表为空时head,tail指向一个节点
  8. else {
  9. head.right = current;
  10. }
  11. //实例化表尾
  12. DulNode current = tail;
  13. tail = new DulNode();
  14. tail.item = item;
  15. tail.left = current;
  16. if (isEmpty()) {
  17. head = tail;//tail = head错误,两个永远为null
  18. }//链表为空时head,tail指向一个节点
  19. else {
  20. current.right = tail;
  21. }

将实例化的节点赋值给空引用,才能让tail与head都指向实例化节点,若赋值顺序颠倒,两节点用为null

  1. 注意在指定节点前/后插入节点,要判断指定节点是否是头/尾结点,否则会产生空指针错误
  2. 插入节点时连接顺序不同
  1. //前插
  2. if(exist.left == null) headInsert(item);
  3. else{
  4. exist.left.right = dulNode;
  5. dulNode.left = exist.left;
  6. exist.left = dulNode;
  7. dulNode.right = exist;
  8. size++;
  9. }
  10. //后插
  11. if(exist.right == null) tailInsert(item);
  12. else{
  13. exist.right.left = dulNode;
  14. dulNode.right = exist.right;
  15. exist.right = dulNode;
  16. dulNode.left = exist;
  17. size++;
  18. }

在指定节点前插入节点时:在AB中指定B插入C,则先连接A.right和B.left再连接BC

在指定节点后插入节点时:在AB中指定A插入C,则先连接C.right和B.left再连接AC