Java实现单向链表
Java实现链表的思想可以参考 LinkedList的源码
下面实现几点关于单向链表的一些操作:
1 public class LinkList<E> { 2 private Node<E> first; 3 private Node<E> last; 4 private int size; 5 6 public LinkList() { 7 first = last = null; 8 size = 0; 9 } 10 11 12 private static class Node<E> { 13 private Node<E> next; 14 private E data; 15 public Node(E data,Node<E> next) { 16 this.data = data; 17 this.next = next; 18 } 19 } 20 21 public void add(E e) { 22 Node<E> l = last; 23 Node<E> newNode = new Node<E>(e, null); 24 last = newNode; 25 if(first == null) { 26 first = newNode; 27 } else { 28 l.next = newNode; 29 } 30 size++; 31 } 32 33 34 35 public static void main(String[] args) { 36 LinkList<Integer> link = new LinkList<Integer>(); 37 //1.添加 38 link.add(1); 39 link.add(2); 40 link.add(3); 41 link.add(4); 42 43 System.out.println("节点个数:" + link.size); 44 45 //2.遍历 46 Node<Integer> node1 = link.first; 47 for(int i = 0;i<link.size;i++) { 48 if(link.first != null) { 49 System.out.println(node1.data); 50 node1 = node1.next; 51 } 52 } 53 54 //3.查找单链表中的倒数第k个结点 55 int k = 2; 56 //倒数第k个,就是正数第link.size-k+1,(因为是单向,只能正着数) 57 int index = link.size-k+1; 58 Node<Integer> node2 = link.first; 59 60 if(link.size <= 0) { 61 System.out.println("链表为空"); 62 return; 63 } 64 if(link.size <= k && link.size > 0) { 65 System.out.println(node2.data); 66 return; 67 } 68 69 for(int i = 1;i<index;i++) { 70 node2 = node2.next; 71 } 72 73 System.out.println("这个链表中倒数第" + k + "个节点的值为:" + node2.data); 74 75 //4.查找单链表中的中间节点(size + 1 / 2,然后遍历吧) 76 77 //5.合并两个有序的单链表,合并之后,仍然有序; 78 //这里自己的思路是,创建一个新的链表,将这两个有序的链表中的数据,按序放入到 新链表中 79 LinkList<Integer> link2 = new LinkList<Integer>(); 80 LinkList<Integer> link3 = new LinkList<Integer>(); 81 link2.add(0); 82 link2.add(2); 83 link2.add(3); 84 link2.add(2); 85 link2.add(7); 86 link2.add(7); 87 88 Node<Integer> node3 = link.first; 89 Node<Integer> node4 = link2.first; 90 91 //只有链表1和链表2中还有数据可以放入新链表 92 for(;node3 != null || node4 != null;) { 93 94 //当链表1和链表2中都有数据可以去比较, 95 if(node3 != null && node4 != null) { 96 if(node3.data < node4.data) { 97 link3.add(node3.data); 98 node3 = node3.next; 99 } 100 else if(node3.data > node4.data) { 101 link3.add(node4.data); 102 node4 = node4.next; 103 } else if(node3.data == node4.data) { 104 link3.add(node3.data); 105 link3.add(node4.data); 106 node3 = node3.next; 107 node4 = node4.next; 108 } 109 } 110 111 112 //若链表1的数据已经比较完了,链表2的还有数据存在,说明链表2这些剩下的数据都比链表1里面大,直接全部放到新链表后面 113 if(node3 == null && node4 != null) { 114 link3.add(node4.data); 115 node4 = node4.next; 116 } else if(node3 != null && node4 == null) { 117 link3.add(node3.data); 118 node3 = node3.next; 119 } 120 121 } 122 System.out.print("两个有序的单链表合并后:"); 123 for(int i = 0;i<link3.size;i++) { 124 System.out.print(link3.first.data + " "); 125 link3.first = link3.first.next; 126 } 127 System.out.println(""); 128 System.out.println("------------------华丽丽的分割线--------------------"); 129 130 //6.单链表的反转 131 Node<Integer> node5 = link.first; 132 133 Node<Integer> pre = null; 134 Node<Integer> next = null; 135 136 while(node5 != null) { 137 next = node5.next; 138 node5.next = pre; 139 pre = node5; 140 node5 = next; 141 142 } 143 144 while(pre != null) { 145 System.out.print(pre.data + " "); 146 pre = pre.next; 147 } 148 } 149 }
注:上面的代码写得比较糟糕,也有很多可以封装的地方,等有时间再整理
提比较重要的几点:
1.关于链表中的泛型,用到泛型的地方,
a)创建这个LinkList的时候,
b)创建Node节点的时候,
c)往Node中添加的数据
2.关于单向链表的添加,
a)添加就是添加在链表的末尾,添加之前,肯定要创建一个 Node节点出来,这个Node节点的下一个节点为null
b)先保存原来的last节点,将这个newNode作为新的last节点
c)如果原先列表中不存在节点,则这个newNode就为 first节点
d)将原来的last节点的next指向这个newNode,就完成添加了 ,最后size++
3.关于合并两个有序的单链表,
a)这里自己的思路是,创建一个新的链表,将这两个有序的链表中的数据,按序放入到 新链表中,当然还有别的思路
4.关于单向链表的反转,
a)首先要有一个pre节点和 next 节点,用于保存当前节点的前一个节点和后一个节点
b)
用前面定义的next,保存当前节点的下一个节点
当前节点下一节点重新指向当前节点的前一节点(箭头反向) 1->2->3 1<-2 3 这里体现上一句的必要性了,如果没有保存,那么后面就找不到这个 3 了
让pre,当前节点,next,依次向后移动,这样就可以对下一个节点进行反转
c)还有一种递归的方式,递归和直接遍历的区别就是,直接遍历是从前往后按顺序一个一个反转
递归是从后往前,先反转最后一个节点,再回头反转前面
这边给出一个递归的示例:
1 public static void main(String[] args) { 2 Node head = new Node(0); 3 Node node1 = new Node(1); 4 Node node2 = new Node(2); 5 Node node3 = new Node(3); 6 head.setNext(node1); 7 node1.setNext(node2); 8 node2.setNext(node3); 9 10 // 打印反转前的链表 11 Node h = head; 12 while (null != h) { 13 System.out.print(h.getData() + " "); 14 h = h.getNext(); 15 } 16 // 调用反转方法 17 head = Reverse1(head); 18 19 System.out.println("\n**************************"); 20 // 打印反转后的结果 21 while (null != head) { 22 System.out.print(head.getData() + " "); 23 head = head.getNext(); 24 } 25 } 26 27 /** 28 * 递归,在反转当前节点之前先反转后续节点 29 */ 30 public static Node Reverse1(Node head) { 31 // head看作是前一结点,head.getNext()是当前结点,reHead是反转后新链表的头结点 32 if (head == null || head.getNext() == null) { 33 return head;// 若为空链或者当前结点在尾结点,则直接还回 34 } 35 Node reHead = Reverse1(head.getNext());// 先反转后续节点head.getNext() 36 head.getNext().setNext(head);// 将当前结点的指针域指向前一结点 37 head.setNext(null);// 前一结点的指针域令为null; 38 return reHead;// 反转后新链表的头结点 39 } 40 } 41 42 class Node { 43 private int Data;// 数据域 44 private Node Next;// 指针域 45 46 public Node(int Data) { 47 // super(); 48 this.Data = Data; 49 } 50 51 public int getData() { 52 return Data; 53 } 54 55 public void setData(int Data) { 56 this.Data = Data; 57 } 58 59 public Node getNext() { 60 return Next; 61 } 62 63 public void setNext(Node Next) { 64 this.Next = Next; 65 }