[CTDL]Đảo Ngược Một Linked List(Danh Sách Liên Kết đơn) - Cafedev

🔥CHỌN LỌC TOP NHỮNG KHOÁ HỌC LẬP TRÌNH ONLINE NHIỀU NGƯỜI THEO HOC TẠI ĐÂY🔥

Chào ace, bài này chúng ta sẽ tìm hiểu về Đảo ngược một linked list(Danh sách liên kết đơn) trong series tự học về cấu trúc dữ liệu và giải thuật, sau đây cafedev sẽ giới thiệu và chia sẻ chi tiết(khái niệm, độ phức tạp, ứng dụng của nó, code ví dụ…) về nó thông qua các phần sau.

Trong bài học này, chúng ta sẽ được cho trước một con trỏ trỏ đến node head của một linked list, nhiệm vụ cần làm là hãy đảo ngược lại linked list này. Bạn thấy đó, để có thể đảo ngược được linked list, chúng ta sẽ cần phải thay đổi các liên kết giữa các nodes.

Ví dụ:

Input: con trỏ Head của linked list sau đây

1->2->3->4->NULL

Output: Linked list cần phải được thay đổi thành,

4->3->2->1->NULL

Input: con trỏ Head của linked list sau đây

1->2->3->4->5->NULL

Output: Linked list cần phải được thay đổi thành,

5->4->3->2->1->NULL

Input: NULL

Output: NULL

Input: 1->NULL

Output: 1->NULL

1. Đảo ngược linked list bằng cách sử dụng vòng lặp

1. Khởi tạo ba con trỏ: prev bằng với NULL, curr bằng với head, và next bằng với NULL.

2. Lặp/duyệt qua toàn bộ linked list. Bên trong vòng lặp, làm những việc sau:

// Trước khi thay đổi con trỏ next của con trỏ current,

// hãy lưu lại node next

next = curr -> next

// Bây giờ, thay đổi con trỏ next của con trỏ current

// Đây là nơi mà sự đảo ngược diễn ra

curr -> next = prev

// Di chuyển con trỏ prev và con trỏ curr một bước về phía trước

prev = curr

curr = next

Sau đây sẽ là đoạn code cài đặt cái thuật toán đảo ngược một linked list sử dụng vòng lặp đã nêu ở trên, được viết bằng nhiều ngôn ngữ lập trình:

CODE VÍ DỤ ĐƯỢC VIẾT BẰNG C++ C Java Python C#

C

// Iterative C program to reverse a linked list #include <stdio.h> #include <stdlib.h> /* Link list node */ struct Node { int data; struct Node* next; }; /* Function to reverse the linked list */ static void reverse(struct Node** head_ref) { struct Node* prev = NULL; struct Node* current = *head_ref; struct Node* next = NULL; while (current != NULL) { // Store next next = current->next; // Reverse current node's pointer current->next = prev; // Move pointers one position ahead. prev = current; current = next; } *head_ref = prev; } /* Function to push a node */ void push(struct Node** head_ref, int new_data) { struct Node* new_node = (struct Node*)malloc(sizeof(struct Node)); new_node->data = new_data; new_node->next = (*head_ref); (*head_ref) = new_node; } /* Function to print linked list */ void printList(struct Node* head) { struct Node* temp = head; while (temp != NULL) { printf("%d ", temp->data); temp = temp->next; } } /* Driver program to test above function*/ int main() { /* Start with the empty list */ struct Node* head = NULL; push(&head, 20); push(&head, 4); push(&head, 15); push(&head, 85); printf("Given linked list\n"); printList(head); reverse(&head); printf("\nReversed Linked list \n"); printList(head); getchar(); }

C++

// Iterative C++ program to reverse // a linked list #include <iostream> using namespace std; /* Link list node */ struct Node { int data; struct Node* next; Node(int data) { this->data = data; next = NULL; } }; struct LinkedList { Node* head; LinkedList() { head = NULL; } /* Function to reverse the linked list */ void reverse() { // Initialize current, previous and // next pointers Node* current = head; Node *prev = NULL, *next = NULL; while (current != NULL) { // Store next next = current->next; // Reverse current node's pointer current->next = prev; // Move pointers one position ahead. prev = current; current = next; } head = prev; } /* Function to print linked list */ void print() { struct Node* temp = head; while (temp != NULL) { cout << temp->data << " "; temp = temp->next; } } void push(int data) { Node* temp = new Node(data); temp->next = head; head = temp; } }; /* Driver program to test above function*/ int main() { /* Start with the empty list */ LinkedList ll; ll.push(20); ll.push(4); ll.push(15); ll.push(85); cout << "Given linked list\n"; ll.print(); ll.reverse(); cout << "\nReversed Linked list \n"; ll.print(); return 0; }

Java

// Java program for reversing the linked list class LinkedList { static Node head; static class Node { int data; Node next; Node(int d) { data = d; next = null; } } /* Function to reverse the linked list */ Node reverse(Node node) { Node prev = null; Node current = node; Node next = null; while (current != null) { next = current.next; current.next = prev; prev = current; current = next; } node = prev; return node; } // prints content of double linked list void printList(Node node) { while (node != null) { System.out.print(node.data + " "); node = node.next; } } public static void main(String[] args) { LinkedList list = new LinkedList(); list.head = new Node(85); list.head.next = new Node(15); list.head.next.next = new Node(4); list.head.next.next.next = new Node(20); System.out.println("Given Linked list"); list.printList(head); head = list.reverse(head); System.out.println(""); System.out.println("Reversed linked list "); list.printList(head); } }

Python

# Python program to reverse a linked list # Time Complexity : O(n) # Space Complexity : O(1) # Node class class Node: # Constructor to initialize the node object def __init__(self, data): self.data = data self.next = None class LinkedList: # Function to initialize head def __init__(self): self.head = None # Function to reverse the linked list def reverse(self): prev = None current = self.head while(current is not None): next = current.next current.next = prev prev = current current = next self.head = prev # Function to insert a new node at the beginning def push(self, new_data): new_node = Node(new_data) new_node.next = self.head self.head = new_node # Utility function to print the linked LinkedList def printList(self): temp = self.head while(temp): print temp.data, temp = temp.next # Driver program to test above functions llist = LinkedList() llist.push(20) llist.push(4) llist.push(15) llist.push(85) print "Given Linked List" llist.printList() llist.reverse() print "\nReversed Linked List" llist.printList()

C#

// C# program for reversing the linked list using System; class GFG { static void Main(string[] args) { LinkedList list = new LinkedList(); list.AddNode(new LinkedList.Node(85)); list.AddNode(new LinkedList.Node(15)); list.AddNode(new LinkedList.Node(4)); list.AddNode(new LinkedList.Node(20)); // List before reversal Console.WriteLine("Given linked list:"); list.PrintList(); // Reverse the list list.ReverseList(); // List after reversal Console.WriteLine("Reversed linked list:"); list.PrintList(); } } class LinkedList { Node head; public class Node { public int data; public Node next; public Node(int d) { data = d; next = null; } } // function to add a new node at // the end of the list public void AddNode(Node node) { if (head == null) head = node; else { Node temp = head; while (temp.next != null) { temp = temp.next; } temp.next = node; } } // function to reverse the list public void ReverseList() { Node prev = null, current = head, next = null; while (current != null) { next = current.next; current.next = prev; prev = current; current = next; } head = prev; } // function to print the list data public void PrintList() { Node current = head; while (current != null) { Console.Write(current.data + " "); current = current.next; } Console.WriteLine(); } }

Kết quả in ra là:

Given linked list 85 15 4 20 Reversed Linked list 20 4 15 85

Độ phức tạp về thời gian: O (n)Độ phức tạp không gian: O (1)

2. Đảo ngược linked list bằng cách sử dụng đệ quy

1. Chia linked list thành hai phần – node đầu tiên và phần còn lại của linked list

2. Gọi đến hàm reverse cho phần còn lại của linked list

3. Kết nối phần còn lại của linked list với node đầu tiên của linked list

4. Thay đổi con trỏ head

Sau đây sẽ là đoạn code cài đặt cái thuật toán đảo ngược một linked list sử dụng đệ quy đã nêu ở trên, được viết bằng nhiều ngôn ngữ lập trình:

ĐOẠN CODE VÍ DỤ ĐƯỢC VIẾT BẰNG C++ Java Python3

C++

// Recursive C++ program to reverse // a linked list #include <iostream> using namespace std; /* Link list node */ struct Node { int data; struct Node* next; Node(int data) { this->data = data; next = NULL; } }; struct LinkedList { Node* head; LinkedList() { head = NULL; } Node* reverse(Node* head) { if (head == NULL || head->next == NULL) return head; /* reverse the rest list and put the first element at the end */ Node* rest = reverse(head->next); head->next->next = head; /* tricky step -- see the diagram */ head->next = NULL; /* fix the head pointer */ return rest; } /* Function to print linked list */ void print() { struct Node* temp = head; while (temp != NULL) { cout << temp->data << " "; temp = temp->next; } } void push(int data) { Node* temp = new Node(data); temp->next = head; head = temp; } }; /* Driver program to test above function*/ int main() { /* Start with the empty list */ LinkedList ll; ll.push(20); ll.push(4); ll.push(15); ll.push(85); cout << "Given linked list\n"; ll.print(); ll.head = ll.reverse(ll.head); cout << "\nReversed Linked list \n"; ll.print(); return 0; }

Java

// Recursive Java program to reverse // a linked list class recursion { static Node head; // head of list static class Node { int data; Node next; Node(int d) { data = d; next = null; } } static Node reverse(Node head) { if (head == null || head.next == null) return head; /* reverse the rest list and put the first element at the end */ Node rest = reverse(head.next); head.next.next = head; /* tricky step -- see the diagram */ head.next = null; /* fix the head pointer */ return rest; } /* Function to print linked list */ static void print() { Node temp = head; while (temp != null) { System.out.print(temp.data + " "); temp = temp.next; } System.out.println(); } static void push(int data) { Node temp = new Node(data); temp.next = head; head = temp; } /* Driver program to test above function*/ public static void main(String args[]) { /* Start with the empty list */ push(20); push(4); push(15); push(85); System.out.println("Given linked list"); print(); head = reverse(head); System.out.println("Reversed Linked list"); print(); } }

Python3

"""Python3 program to reverse linked list using recursive method""" # Linked List Node class Node: def __init__(self, data): self.data = data self.next = None # Create and Handle list operations class LinkedList: def __init__(self): self.head = None # Head of list # Method to reverse the list def reverse(self, head): # If head is empty or has reached the list end if head is None or head.next is None: return head # Reverse the rest list rest = self.reverse(head.next) # Put first element at the end head.next.next = head head.next = None # Fix the header pointer return rest # Returns the linked list in display format def __str__(self): linkedListStr = "" temp = self.head while temp: linkedListStr = (linkedListStr + str(temp.data) + " ") temp = temp.next return linkedListStr # Pushes new data to the head of the list def push(self, data): temp = Node(data) temp.next = self.head self.head = temp # Driver code linkedList = LinkedList() linkedList.push(20) linkedList.push(4) linkedList.push(15) linkedList.push(85) print("Given linked list") print(linkedList) linkedList.head = linkedList.reverse(linkedList.head) print("Reversed linked list") print(linkedList)

Kết quả in ra là:

Given linked list 85 15 4 20 Reversed Linked list 20 4 15 85

Độ phức tạp về thời gian: O(n)

Độ phức tạp về không gian: O(1)

3. Đảo ngược linked list một cách đơn giản hơn bằng Tail Recursive – đệ quy đuôi

Dưới đây sẽ là phần code cài đặt cho cách làm này:

ĐOẠN CODE VÍ DỤ ĐƯỢC VIẾT BẰNG C++ Java Python3 C#

C++

// A simple and tail recursive C++ program to reverse // a linked list #include <bits/stdc++.h> using namespace std; struct Node { int data; struct Node* next; }; void reverseUtil(Node* curr, Node* prev, Node** head); // This function mainly calls reverseUtil() // with prev as NULL void reverse(Node** head) { if (!head) return; reverseUtil(*head, NULL, head); } // A simple and tail recursive function to reverse // a linked list. prev is passed as NULL initially. void reverseUtil(Node* curr, Node* prev, Node** head) { /* If last node mark it head*/ if (!curr->next) { *head = curr; /* Update next to prev node */ curr->next = prev; return; } /* Save curr->next node for recursive call */ Node* next = curr->next; /* and update next ..*/ curr->next = prev; reverseUtil(next, curr, head); } // A utility function to create a new node Node* newNode(int key) { Node* temp = new Node; temp->data = key; temp->next = NULL; return temp; } // A utility function to print a linked list void printlist(Node* head) { while (head != NULL) { cout << head->data << " "; head = head->next; } cout << endl; } // Driver program to test above functions int main() { Node* head1 = newNode(1); head1->next = newNode(2); head1->next->next = newNode(3); head1->next->next->next = newNode(4); head1->next->next->next->next = newNode(5); head1->next->next->next->next->next = newNode(6); head1->next->next->next->next->next->next = newNode(7); head1->next->next->next->next->next->next->next = newNode(8); cout << "Given linked list\n"; printlist(head1); reverse(&head1); cout << "\nReversed linked list\n"; printlist(head1); return 0; }

Java

// Java program for reversing the Linked list class LinkedList { static Node head; static class Node { int data; Node next; Node(int d) { data = d; next = null; } } // A simple and tail recursive function to reverse // a linked list. prev is passed as NULL initially. Node reverseUtil(Node curr, Node prev) { /* If last node mark it head*/ if (curr.next == null) { head = curr; /* Update next to prev node */ curr.next = prev; return head; } /* Save curr->next node for recursive call */ Node next1 = curr.next; /* and update next ..*/ curr.next = prev; reverseUtil(next1, curr); return head; } // prints content of double linked list void printList(Node node) { while (node != null) { System.out.print(node.data + " "); node = node.next; } } public static void main(String[] args) { LinkedList list = new LinkedList(); list.head = new Node(1); list.head.next = new Node(2); list.head.next.next = new Node(3); list.head.next.next.next = new Node(4); list.head.next.next.next.next = new Node(5); list.head.next.next.next.next.next = new Node(6); list.head.next.next.next.next.next.next = new Node(7); list.head.next.next.next.next.next.next.next = new Node(8); System.out.println("Original Linked list "); list.printList(head); Node res = list.reverseUtil(head, null); System.out.println(""); System.out.println(""); System.out.println("Reversed linked list "); list.printList(res); } }

Python

# Simple and tail recursive Python program to # reverse a linked list # Node class class Node: # Constructor to initialize the node object def __init__(self, data): self.data = data self.next = None class LinkedList: # Function to initialize head def __init__(self): self.head = None def reverseUtil(self, curr, prev): # If last node mark it head if curr.next is None : self.head = curr # Update next to prev node curr.next = prev return # Save curr.next node for recursive call next = curr.next # And update next curr.next = prev self.reverseUtil(next, curr) # This function mainly calls reverseUtil() # with previous as None def reverse(self): if self.head is None: return self.reverseUtil(self.head, None) # Function to insert a new node at the beginning def push(self, new_data): new_node = Node(new_data) new_node.next = self.head self.head = new_node # Utility function to print the linked LinkedList def printList(self): temp = self.head while(temp): print temp.data, temp = temp.next # Driver program llist = LinkedList() llist.push(8) llist.push(7) llist.push(6) llist.push(5) llist.push(4) llist.push(3) llist.push(2) llist.push(1) print "Given linked list" llist.printList() llist.reverse() print "\nReverse linked list" llist.printList()

C#

// C# program for reversing the Linked list using System; public class LinkedList { Node head; public class Node { public int data; public Node next; public Node(int d) { data = d; next = null; } } // A simple and tail recursive function to reverse // a linked list. prev is passed as NULL initially. Node reverseUtil(Node curr, Node prev) { /* If last node mark it head*/ if (curr.next == null) { head = curr; /* Update next to prev node */ curr.next = prev; return head; } /* Save curr->next node for recursive call */ Node next1 = curr.next; /* and update next ..*/ curr.next = prev; reverseUtil(next1, curr); return head; } // prints content of double linked list void printList(Node node) { while (node != null) { Console.Write(node.data + " "); node = node.next; } } // Driver code public static void Main(String[] args) { LinkedList list = new LinkedList(); list.head = new Node(1); list.head.next = new Node(2); list.head.next.next = new Node(3); list.head.next.next.next = new Node(4); list.head.next.next.next.next = new Node(5); list.head.next.next.next.next.next = new Node(6); list.head.next.next.next.next.next.next = new Node(7); list.head.next.next.next.next.next.next.next = new Node(8); Console.WriteLine("Original Linked list "); list.printList(list.head); Node res = list.reverseUtil(list.head, null); Console.WriteLine(""); Console.WriteLine(""); Console.WriteLine("Reversed linked list "); list.printList(res); } }

Kết quả in ra là:

Given linked list 1 2 3 4 5 6 7 8 Reversed linked list 8 7 6 5 4 3 2 1

Nguồn và Tài liệu tiếng anh tham khảo:

  • w3schools
  • Geeksforgeeks
  • codechef
  • dev.to

Tài liệu từ cafedev:

  • Full series tự học Cấu trúc dữ liệu và giải thuật từ cơ bản tới nâng cao tại đây nha.
  • Ebook về Cấu trúc dữ liệu và giải thuật tại đây.
  • Các series tự học lập trình khác

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

  • Group Facebook
  • Fanpage
  • Youtube
  • Instagram
  • Twitter
  • Linkedin
  • Pinterest
  • Trang chủ

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!

Từ khóa » Duyệt Ngược Danh Sách Liên Kết