1. 程式人生 > >單鏈表實現及其基本操作

單鏈表實現及其基本操作

rate || == tac rgs 是否 targe param val

  1. import java.util.HashMap;
  2. import java.util.Scanner;
  3. import java.util.Stack;
  4. /**
  5. *
  6. * @author kerryfish
  7. * 關於java中鏈表的操作
  8. * 1. 求單鏈表中結點的個數: getListLength
  9. * 2. 將單鏈表反轉: reverseList(遍歷),reverseListRec(遞歸)
  10. * 3. 查找單鏈表中的倒數第K個結點(k > 0): reGetKthNode
  11. * 4. 查找單鏈表的中間結點: getMiddleNode
  12. * 5. 從尾到頭打印單鏈表: reversePrintListStack,reversePrintListRec(遞歸)
  13. * 6. 已知兩個單鏈表pHead1 和pHead2 各自有序,把它們合並成一個鏈表依然有序: mergeSortedList, mergeSortedListRec
  14. * 7. 對單鏈表進行排序,listSort(歸並),insertionSortList(插入)
  15. * 8. 判斷一個單鏈表中是否有環: hasCycle
  16. * 9. 判斷兩個單鏈表是否相交: isIntersect
  17. * 10. 已知一個單鏈表中存在環,求進入環中的第一個節點: getFirstNodeInCycle, getFirstNodeInCycleHashMap
  18. * 11. 給出一單鏈表頭指針head和一節點指針delete,O(1)時間復雜度刪除節點delete: deleteNode
  19. */
  20. public class LinkedListSummary {
  21. /**
  22. * @param args
  23. *
  24. */
  25. public static class Node{
  26. int value;
  27. Node next;
  28. public Node(int n){
  29. this.value=n;
  30. this.next=null;
  31. }
  32. }
  33. public static void main(String[] args) {
  34. // TODO Auto-generated method stub
  35. Scanner in=new Scanner(System.in);
  36. Node head=null;
  37. if(in.hasNextInt()){
  38. head=new Node(in.nextInt());
  39. }
  40. Node temp=head;
  41. while(in.hasNextInt()){
  42. temp.next=new Node(in.nextInt());
  43. temp=temp.next;
  44. }
  45. in.close();
  46. //int len=getListLength(head);
  47. //Node reHead=reverseList(head);
  48. //reHead=reverseListRec(reHead);
  49. //Node node_k=reGetKthNode(head,3);
  50. //Node mid=getMiddleNode(head);
  51. //reversePrintListRec(head);
  52. //reversePrintListStack(head);
  53. //Node mergeHead=mergeSortedList(head,null);
  54. //Node sortHead=listSort(head);
  55. }
  56. //求單鏈表中結點的個數: getListLength
  57. public static int getListLength(Node head){
  58. int len=0;
  59. while(head!=null){
  60. len++;
  61. head=head.next;
  62. }
  63. return len;
  64. }
  65. //將單鏈表反轉,循環
  66. public static Node reverseList(Node head){
  67. if(head==null||head.next==null)return head;
  68. Node pre=null;
  69. Node nex=null;
  70. while(head!=null){
  71. nex=head.next;
  72. head.next=pre;
  73. pre=head;
  74. head=nex;
  75. }
  76. return pre;
  77. }
  78. //將單鏈表反轉,遞歸
  79. public static Node reverseListRec(Node head){
  80. if(head==null||head.next==null)return head;
  81. Node reHead=reverseListRec(head.next);
  82. head.next.next=head;
  83. head.next=null;
  84. return reHead;
  85. }
  86. //查找單鏈表中的倒數第K個結點(k > 0)
  87. public static Node reGetKthNode(Node head,int k){
  88. if(head==null)return head;
  89. int len=getListLength(head);
  90. if(k>len)return null;
  91. Node target=head;
  92. Node nexk=head;
  93. for(int i=0;i<k;i++){
  94. nexk=nexk.next;
  95. }
  96. while(nexk!=null){
  97. target=target.next;
  98. nexk=nexk.next;
  99. }
  100. return target;
  101. }
  102. //查找單鏈表的中間結點
  103. public static Node getMiddleNode(Node head){
  104. if(head==null||head.next==null)return head;
  105. Node target=head;
  106. Node temp=head;
  107. while(temp!=null&&temp.next!=null){
  108. target=target.next;
  109. temp=temp.next.next;
  110. }
  111. return target;
  112. }
  113. //從尾到頭打印單鏈表,遞歸
  114. public static void reversePrintListRec(Node head){
  115. if(head==null)return;
  116. else{
  117. reversePrintListRec(head.next);
  118. System.out.println(head.value);
  119. }
  120. }
  121. //從尾到頭打印單鏈表,棧
  122. public static void reversePrintListStack(Node head){
  123. Stack<Node> s=new Stack<Node>();
  124. while(head!=null){
  125. s.push(head);
  126. head=head.next;
  127. }
  128. while(!s.isEmpty()){
  129. System.out.println(s.pop().value);
  130. }
  131. }
  132. //合並兩個有序的單鏈表head1和head2,循環
  133. public static Node mergeSortedList(Node head1,Node head2){
  134. if(head1==null)return head2;
  135. if(head2==null)return head1;
  136. Node target=null;
  137. if(head1.value>head2.value){
  138. target=head2;
  139. head2=head2.next;
  140. }
  141. else{
  142. target=head1;
  143. head1=head1.next;
  144. }
  145. target.next=null;
  146. Node mergeHead=target;
  147. while(head1!=null && head2!=null){
  148. if(head1.value>head2.value){
  149. target.next=head2;
  150. head2=head2.next;
  151. }
  152. else{
  153. target.next=head1;
  154. head1=head1.next;
  155. }
  156. target=target.next;
  157. target.next=null;
  158. }
  159. if(head1==null)target.next=head2;
  160. else target.next=head1;
  161. return mergeHead;
  162. }
  163. //合並兩個有序的單鏈表head1和head2,遞歸
  164. public static Node mergeSortedListRec(Node head1,Node head2){
  165. if(head1==null)return head2;
  166. if(head2==null)return head1;
  167. if(head1.value>head2.value){
  168. head2.next=mergeSortedListRec(head2.next,head1);
  169. return head2;
  170. }
  171. else{
  172. head1.next=mergeSortedListRec(head1.next,head2);
  173. return head1;
  174. }
  175. }
  176. //對單鏈表進行排序,歸並排序,在排序裏面不建議選用遞歸的合並有序鏈表算法,如果鏈表長度較長,很容易出現棧溢出
  177. public static Node listSort(Node head){
  178. Node nex=null;
  179. if(head==null||head.next==null)return head;
  180. else if(head.next.next==null){
  181. nex=head.next;
  182. head.next=null;
  183. }
  184. else{
  185. Node mid=getMiddleNode(head);
  186. nex=mid.next;
  187. mid.next=null;
  188. }
  189. return mergeSortedList(listSort(head),listSort(nex));//合並兩個有序鏈表,不建議遞歸
  190. }
  191. //對單鏈表進行排序,插入排序
  192. public Node insertionSortList(Node head) {
  193. if(head==null||head.next==null)return head;
  194. Node pnex=head.next;
  195. Node pnex_nex=null;
  196. head.next=null;
  197. while(pnex!=null){
  198. pnex_nex=pnex.next;
  199. Node temp=head;
  200. Node temp_pre=null;
  201. while(temp!=null){
  202. if(temp.value>pnex.value)break;
  203. temp_pre=temp;
  204. temp=temp.next;
  205. }
  206. if(temp_pre==null){
  207. head=pnex;
  208. pnex.next=temp;
  209. }
  210. else{
  211. temp_pre.next=pnex;
  212. pnex.next=temp;
  213. }
  214. pnex=pnex_nex;
  215. }
  216. return head;
  217. }
  218. //判斷一個單鏈表中是否有環,快慢指針
  219. public static boolean hasCycle(Node head){
  220. boolean flag=false;
  221. Node p1=head;
  222. Node p2=head;
  223. while(p1!=null&&p2!=null){
  224. p1=p1.next;
  225. p2=p2.next.next;
  226. if(p2==p1){
  227. flag=true;
  228. break;
  229. }
  230. }
  231. return flag;
  232. }
  233. //判斷兩個單鏈表是否相交,如果相交返回第一個節點,否則返回null
  234. //如果單純的判斷是否相交,只需要看最後一個指針是否相等
  235. public static Node isIntersect(Node head1,Node head2){
  236. Node target=null;
  237. if(head1==null||head2==null)return target;
  238. int len1=getListLength(head1);
  239. int len2=getListLength(head2);
  240. if(len1>=len2){
  241. for(int i=0;i<len1-len2;i++){
  242. head1=head1.next;
  243. }
  244. }else{
  245. for(int i=0;i<len2-len1;i++){
  246. head2=head2.next;
  247. }
  248. }
  249. while(head1!=null&&head2!=null){
  250. if(head1==head2){
  251. target=head1;
  252. break;
  253. }
  254. else{
  255. head1=head1.next;
  256. head2=head2.next;
  257. }
  258. }
  259. return target;
  260. }
  261. //已知一個單鏈表中存在環,求進入環中的第一個節點,利用hashmap,不要用ArrayList,因為判斷ArrayList是否包含某個元素的效率不高
  262. public static Node getFirstNodeInCycleHashMap(Node head){
  263. Node target=null;
  264. HashMap<Node,Boolean> map=new HashMap<Node,Boolean>();
  265. while(head!=null){
  266. if(map.containsKey(head))target=head;
  267. else{
  268. map.put(head, true);
  269. }
  270. head=head.next;
  271. }
  272. return target;
  273. }
  274. //已知一個單鏈表中存在環,求進入環中的第一個節點,不用hashmap
  275. //用快慢指針,與判斷一個單鏈表中是否有環一樣,找到快慢指針第一次相交的節點,此時這個節點距離環開始節點的長度和鏈表投距離環開始的節點的長度相等
  276. public static Node getFirstNodeInCycle(Node head){
  277. Node fast=head;
  278. Node slow=head;
  279. while(fast!=null&&fast.next!=null){
  280. slow=slow.next;
  281. fast=fast.next.next;
  282. if(slow==fast)break;
  283. }
  284. if(fast==null||fast.next==null)return null;//判斷是否包含環
  285. //相遇節點距離環開始節點的長度和鏈表投距離環開始的節點的長度相等
  286. slow=head;
  287. while(slow!=fast){
  288. slow=slow.next;
  289. fast=fast.next;
  290. }//同步走
  291. return slow;
  292. }
  293. //給出一單鏈表頭指針head和一節點指針delete,O(1)時間復雜度刪除節點delete
  294. //可惜采用將delete節點value值與它下個節點的值互換的方法,但是如果delete是最後一個節點,則不行,但是總得復雜度還是O(1)
  295. public static void deleteNode(Node head,Node delete){
  296. //首先處理delete節點為最後一個節點的情況
  297. if(delete==null)return;
  298. if(delete.next==null){
  299. if(head==delete)head=null;
  300. else{
  301. Node temp=head;
  302. while(temp.next!=delete){
  303. temp=temp.next;
  304. }
  305. temp.next=null;
  306. }
  307. }
  308. else{
  309. delete.value=delete.next.value;
  310. delete.next=delete.next.next;
  311. }
  312. return;
  313. }
  314. }

單鏈表實現及其基本操作