反转链表是数据结构和算法中一个有趣的问题。在本教程中,我们将讨论各种算法来反转一个链表,并使用Java实现它们。
反转链表
链表是一种以线性方式存储数据的数据结构,尽管不是连续的。每个链表元素包含一个数据部分和指向链表下一个元素的地址。链表元素通常被称为节点。
双向链表存储两个地址,分别是前一个元素的地址和下一个元素的地址。
為了在原地反轉鏈表,我們需要反轉指針,使下一個元素現在指向前一個元素。以下是輸入和輸出。
鏈表的頭是第一個節點。沒有其他元素存儲了此節點的地址。鏈表的尾部是最後一個節點。此節點中存儲的下一個地址為
null
。我們可以通過以下方式反轉鏈表,使頭和尾也發生變化:
- 迭代方法
- 遞歸方法
反轉鏈表的迭代方法
為了迭代地反轉 LinkedList,我們需要存儲下一個和前一個元素的引用,這樣當我們交換 LinkedList 中下一個元素的內存地址指針時,它們就不會丟失。以下插圖演示了我們將如何通過改變引用來反轉 LinkedList。
以下是反轉 LinkedList 的步驟。創建 3 個實例:current、next、previous。循環以下直到 current 不為空:
- 保存當前元素的下一個節點到 next 指針中。
- 將當前節點的下一個節點設置為 previous。這是 MVP 行。
- 將 previous 轉移到 current。
- 將當前元素轉移到 next。
最後,因為當前已經超前於最後一個元素一個位置,我們需要將頭部設置為我們到達的最後一個元素。這在 previous 中可用。將頭部設置為 previous。這樣我們就有了 LinkedList 的新頭部,它是舊 LinkedList 的最後一個元素。
這是 LinkedList 的一個非常簡單的實現。請注意,這不是一個可以投入生產的實現,我們保持它的簡單性,以便我們的重點集中在反轉鏈表的算法上。
package com.journaldev.linkedlist.reverse;
public class MyLinkedList {
public Node head;
public static class Node {
Node next;
Object data;
Node(Object data) {
this.data = data;
next = null;
}
}
}
下面是一個 Java 程序,用於迭代地反轉鏈表並打印其元素:
package com.journaldev.linkedlist.reverse;
import com.journaldev.linkedlist.reverse.MyLinkedList.Node;
public class ReverseLinkedList {
public static void main(String[] args) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.head = new Node(1);
myLinkedList.head.next = new Node(2);
myLinkedList.head.next.next = new Node(3);
printLinkedList(myLinkedList);
reverseLinkedList(myLinkedList);
printLinkedList(myLinkedList);
}
public static void printLinkedList(MyLinkedList linkedList) {
Node h = linkedList.head;
while (linkedList.head != null) {
System.out.print(linkedList.head.data + " ");
linkedList.head = linkedList.head.next;
}
System.out.println();
linkedList.head = h;
}
public static void reverseLinkedList(MyLinkedList linkedList) {
Node previous = null;
Node current = linkedList.head;
Node next;
while (current != null) {
next = current.next;
current.next = previous;
previous = current;
current = next;
}
linkedList.head = previous;
}
}
輸出:
1 2 3
3 2 1
以遞歸方式反轉鏈表
要以遞歸方式反轉LinkedList,我們需要將LinkedList分為兩部分:頭部和剩餘部分。頭部最初指向第一個元素。剩餘部分指向從頭部開始的下一個元素。
我們遞歸地遍歷LinkedList,直到倒數第二個元素。一旦我們到達最後一個元素,將其設置為頭部。從那裡開始,直到達到LinkedList的開頭,我們執行以下操作。node.next.next = node;
node.next = null;
為了不丟失原始頭部的軌跡,我們將保存頭部實例的副本。
以下是上述過程的示例。 以遞歸方式反轉LinkedList的Java程序為:
public static Node recursiveReverse(Node head) {
Node first;
if (head==null || head.next == null)
return head;
first = recursiveReverse(head.next);
head.next.next = head;
head.next = null;
return first;
}
我們只需在遞歸調用中傳遞head.next,以便前往LinkedList的末尾。一旦我們到達末尾,我們將倒數第二個元素設置為最後一個元素的下一個,並將倒數第二個元素的下一個指針設置為NULL。最後一個元素將被標記為新的頭部。使用以下代碼使用遞歸方法反轉鏈表。
myLinkedList.head = recursiveReverse(myLinkedList.head);
輸出將保持與以前的迭代方法相同。
反轉鏈表的時間與空間複雜度
時間複雜度 – O(n) 空間複雜度 – O(1)
您可以從我們的GitHub存儲庫查看完整代碼和更多DS&算法示例。
Source:
https://www.digitalocean.com/community/tutorials/reverse-a-linked-list