import java.util.ArrayList; import java.util.Stack; /** * 鏈表的反轉 */ public class ReverseLinkedList { /** * 非遞歸地反轉鏈表: * * 特色:沒有進行節點間的兩兩反轉,而是採用依次插入到新鏈表的方式來實現反轉。 * * 過程:遍歷一次鏈表,將遍歷的節點依次插入到新鏈表的頭部便可實現鏈表的反轉。 * * 複雜度:時間複雜度爲O(N),輔助的空間複雜度爲O(1) * * [@param](https://my.oschina.net/u/2303379) head * * [@return](https://my.oschina.net/u/556800) 將反轉後的新鏈表的頭節點返回。 */ public static Node reverseByInsertToNewList(Node head) { Node current = head; // 正在遍歷的節點 Node next = null; // 下一個要遍歷的節點 Node newHead = null; // 新鏈表頭節點的引用(指向新鏈表頭節點的指針) while (null != current) { next = current.next; // 將下一個要遍歷的節點暫存起來 /** * 將當前節點放到新鏈表的頭部: * 1>將當前節點指向新鏈表的頭部 * 2>更新newHead */ current.next = newHead; newHead = current; current = next; // 向後繼續遍歷 } return newHead; } /** * 遞歸地反轉鏈表: * * 特色:從後往前兩兩反轉。 * * 過程:遞歸地將當前節點(current)和它的後繼節點(current.next)反轉。 * * 注意: * 1)最後一個節點沒有後繼節點,故最後一個節點不須要進行反轉操做,只需將最後一個節點(做爲新鏈表的頭節點)直接返回便可。 * 2)當前節點爲鏈表倒數第二個節點時,開始第一次的反轉操做。 * 3)每次的反轉操做都不會對新鏈表的頭節點形成影響,只是將新的頭結點返回而已。 * * 解析: * 1)將 A->B->C->D 反轉的操做能夠分爲: * 1>將 C->D 反轉 ==> A->B->C D->C->null * 2>將 B->C 反轉 ==> A->B D->C->B->null * 3>將 A->B 反轉 ==> D->C->B->A->null * * 2)將 A->B 反轉的操做: * 1>將B的後繼節點指向A, 即 B.next = A 即 A.next.next = A * 2>將A的後繼節點設爲null, 即 A.next = null * * [@param](https://my.oschina.net/u/2303379) current * * [@return](https://my.oschina.net/u/556800) 將反轉後的新鏈表的頭節點返回。 */ private static Node reverseByRecursion(Node current) { if (null == current) { // 若該鏈表爲空鏈表,則直接返回 return current; } if (null == current.next) { // 當前結點是尾結點時,直接返回。注:鏈表的尾節點即新鏈表的頭節點 return current; } Node newHead = reverseByRecursion(current.next); // newHead是鏈表的尾節點,即新鏈表的頭節點。 // 反轉操做:將current和current.next進行反轉,即:將當前節點放到新鏈表的尾部,故在遞歸的過程當中新鏈表的頭部不會變。 current.next.next = current; current.next = null; // 將新鏈表的頭節點返回。 return newHead; } // ------- /** * 利用棧的先進後出特性來完成鏈表的反轉。 * * 時間複雜度爲O(N),輔助的空間複雜度也爲O(N) * * [@param](https://my.oschina.net/u/2303379) head * @return 將反轉後的新鏈表的頭節點返回。 */ public static Node reverseWithStack(Node head) { Stack<Node> stack = new Stack<Node>(); while (null != head) { stack.push(head); head = head.next; } return stack.peek(); } /** * 反轉雙向鏈表 * * 複雜度:時間複雜度爲O(N),輔助的空間複雜度爲O(1) * * @param head * @return 將反轉後的新鏈表的頭節點返回。 */ public static Node reverseBidirectionalList(Node head) { if (null == head) { // 若該鏈表爲空鏈表,則直接返回 return null; } Node current = head; Node next = null; Node newHead = null; while (null != current) { // 反轉 next = current.next; // 將當前節點的後繼節點暫存起來 current.next = current.prev; current.prev = next; if (null == next) { // 若下一個要遍歷的節點爲null,則說明已經到達鏈表的尾部,此時current即鏈表的尾節點 newHead = current; } current = next; // 繼續向後遍歷 } return newHead; } // ------- /** * 將鏈表從頭至尾依次打印出來 * * @param head */ public static void print(Node head) { ArrayList<Object> list = new ArrayList<>(); while (null != head.next) { list.add(head.value); head = head.next; } list.add(head.value); System.out.println(list.toString()); } /** * 將雙向鏈表從尾到頭依次打印出來 * * @param tail */ public static void printBidirectionList(Node tail) { ArrayList<Object> list = new ArrayList<>(); while (null != tail.prev) { list.add(tail.value); tail = tail.prev; } list.add(tail.value); System.out.println(list.toString()); } /** * 初始化鏈表 * * @return */ public static Node init() { Node head = new Node(5); Node node1 = new Node(3); Node node2 = new Node(2); Node node3 = new Node(6); Node node4 = new Node(7); Node node5 = new Node(17); Node node6 = new Node(9); head.next = node1; node1.prev = head; node1.next = node2; node2.prev = node1; node2.next = node3; node3.prev = node2; node3.next = node4; node4.prev = node3; node4.next = node5; node5.prev = node4; node5.next = node6; node6.prev = node5; node6.next = null; return head; } public static void main(String[] args) { Node head = init(); print(head); // 反轉單向鏈表 // Node newHead = reverseByInsertToNewList(head); // Node newHead = reverseByRecursion(head); // 反轉雙向鏈表 Node newHead = reverseBidirectionalList(head); print(newHead); // 利用stack反轉雙向鏈表 Node newHeadByStack = reverseWithStack(head); printBidirectionList(newHeadByStack); }
}java