Chào ace, bài này chúng ta sẽ tìm hiểu về Thao tác xóa node trong danh sách liên kết vòng trong series tự học về cấu trúc dữ liệu(CTDL) 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 các bài trước, chúng ta đã tìm hiểu về danh sách liên kết vòng và cách duyệt qua danh sách liên kết vòng. Trong bài hôm nay, chúng ta sẽ học cách xóa một node khỏi danh sách liên kết vòng. Xét danh sách liên kết vòng như hình vẽ sau:

Giả sử, chúng ta được cho trước một node, và nhiệm vụ cần làm là xóa node đó khỏi danh sách liên kết vòng.

Ví dụ:

Input: 2->5->7->8->10->(head node)

       data = 5

Output : 2->7->8->10->(head node)

Input : 2->5->7->8->10->(head node)

        data = 7

Output : 2->5->8->10->2(head node)

Thuật toán

1. Trường hợp 1: Danh sách liên kết vòng đang trống

– Nếu danh sách đang trống, chúng ta chỉ cần return.

2. Trường hợp 2: Danh sách liên kết vòng không trống

– Nếu danh sách không trống, chúng ta sẽ khai báo hai con trỏ là curr và prev, rồi khởi tạo con trỏ curr với node head.

– Sử dụng con trỏ curr để duyệt qua danh sách liên kết vòng để tìm thấy node muốn xóa, và bạn cần nhớ là, trước khi di chuyển con trỏ curr tới node tiếp theo, luôn luôn phải thiết lập prev = curr.

– Nếu tìm thấy được node muốn xóa, kiểm tra xem liệu rằng nó có phải node duy nhất trong danh sách mang giá trị mà chúng ta muốn xóa hay không. Nếu nó là node duy nhất mang giá trị mà chúng ta đang muốn xóa, hãy thiết lập cho head = NULL và giải phóng con trỏ curr free(curr).

– Nếu trong danh sách liên kết vòng có nhiều hơn một node mang giá trị mà chúng ta muốn xóa, kiểm tra xem liệu rằng nó có phải là node đầu tiên trong danh sách không, câu lệnh để kiểm tra điều này là (curr == head). Nếu câu lệnh trên là TRUE, chúng ta sẽ di chuyển con trỏ prev cho đến khi đi tới node cuối cùng của danh sách. Sau khi con trỏ prev đã đi tới node cuối cùng của danh sách, chúng ta cần thiết lập head = head -> next và prev -> next = head. Cuối cùng là xóa đi node curr bằng câu lệnh free(curr).

– Nếu curr không phải là node đầu tiên, chúng ta sẽ kiểm tra xem liệu rằng nó có phải node cuối cùng trong danh sách không. Câu lệnh để kiểm tra điều này là (curr -> next == head).

– Nếu curr là node cuối cùng trong danh sách liên kết vòng. Hãy thiết lập prev -> next = head và sau đó xóa đi node curr bằng câu lệnh free(curr).

– Nếu node muốn xóa không phải là node đầu và cũng không phải là node cuối trong danh sách liên kết vòng, vậy thì hãy thiết lập prev -> next = temp -> next và sau đó xóa đi node curr bằng câu lệnh free(curr).

Sau đây là đoạn chương trình hoàn thiện minh họa thao tác xóa node khỏi danh sách liên kết vòng:

ĐOẠN CODE VÍ DỤ ĐƯỢC VIẾT BẰNG NHIỀU NGÔN NGỮ KHÁC NHAU

C


// C program to delete a given key from 
// linked list. 
#include <stdio.h> 
#include <stdlib.h> 
  
/* structure for a node */
struct Node { 
    int data; 
    struct Node* next; 
}; 
  
/* Function to insert a node at the beginning of 
   a Circular linked list */
void push(struct Node** head_ref, int data) 
{ 
    // Create a new node and make head as next 
    // of it. 
    struct Node* ptr1 = (struct Node*)malloc(sizeof(struct Node)); 
    ptr1->data = data; 
    ptr1->next = *head_ref; 
  
    /* If linked list is not NULL then set the 
       next of last node */
    if (*head_ref != NULL) { 
        // Find the node before head and update 
        // next of it. 
        struct Node* temp = *head_ref; 
        while (temp->next != *head_ref) 
            temp = temp->next; 
        temp->next = ptr1; 
    } 
    else
        ptr1->next = ptr1; /*For the first node */
  
    *head_ref = ptr1; 
} 
  
/* Function to print nodes in a given 
  circular linked list */
void printList(struct Node* head) 
{ 
    struct Node* temp = head; 
    if (head != NULL) { 
        do { 
            printf("%d ", temp->data); 
            temp = temp->next; 
        } while (temp != head); 
    } 
  
    printf("\n"); 
} 
  
/* Function to delete a given node from the list */
void deleteNode(struct Node* head, int key) 
{ 
    if (head == NULL) 
        return; 
  
    // Find the required node 
    struct Node *curr = head, *prev; 
    while (curr->data != key) { 
        if (curr->next == head) { 
            printf("\nGiven node is not found"
                   " in the list!!!"); 
            break; 
        } 
  
        prev = curr; 
        curr = curr->next; 
    } 
  
    // Check if node is only node 
    if (curr->next == head) { 
        head = NULL; 
        free(curr); 
        return; 
    } 
  
    // If more than one node, check if 
    // it is first node 
    if (curr == head) { 
        prev = head; 
        while (prev->next != head) 
            prev = prev->next; 
        head = curr->next; 
        prev->next = head; 
        free(curr); 
    } 
  
    // check if node is last node 
    else if (curr->next == head) { 
        prev->next = head; 
        free(curr); 
    } 
    else { 
        prev->next = curr->next; 
        free(curr); 
    } 
} 
  
/* Driver program to test above functions */
int main() 
{ 
    /* Initialize lists as empty */
    struct Node* head = NULL; 
  
    /* Created linked list will be 2->5->7->8->10 */
    push(&head, 2); 
    push(&head, 5); 
    push(&head, 7); 
    push(&head, 8); 
    push(&head, 10); 
  
    printf("List Before Deletion: "); 
    printList(head); 
  
    deleteNode(head, 7); 
  
    printf("List After Deletion: "); 
    printList(head); 
  
    return 0; 
} 

C++

// C++ program to delete a given key from 
// linked list. 
#include <bits/stdc++.h> 
using namespace std; 
  
/* structure for a node */
class Node { 
public: 
    int data; 
    Node* next; 
}; 
  
/* Function to insert a node at the beginning of  
a Circular linked list */
void push(Node** head_ref, int data) 
{ 
    // Create a new node and make head as next 
    // of it. 
    Node* ptr1 = new Node(); 
    ptr1->data = data; 
    ptr1->next = *head_ref; 
  
    /* If linked list is not NULL then set the  
    next of last node */
    if (*head_ref != NULL) { 
        // Find the node before head and update 
        // next of it. 
        Node* temp = *head_ref; 
        while (temp->next != *head_ref) 
            temp = temp->next; 
        temp->next = ptr1; 
    } 
    else
        ptr1->next = ptr1; /*For the first node */
  
    *head_ref = ptr1; 
} 
  
/* Function to print nodes in a given  
circular linked list */
void printList(Node* head) 
{ 
    Node* temp = head; 
    if (head != NULL) { 
        do { 
            cout << temp->data << " "; 
            temp = temp->next; 
        } while (temp != head); 
    } 
  
    cout << endl; 
} 
  
/* Function to delete a given node from the list */
void deleteNode(Node** head, int key)  
{ 
      
    // If linked list is empty 
    if (*head == NULL) 
        return; 
          
    // If the list contains only a single node 
    if((*head)->data==key && (*head)->next==*head) 
    { 
        free(*head); 
        *head=NULL; 
        return; 
    } 
      
    Node *last=*head,*d; 
      
    // If head is to be deleted 
    if((*head)->data==key) { 
          
        // Find the last node of the list 
        while(last->next!=*head) 
            last=last->next; 
              
        // Point last node to the next of head i.e.  
        // the second node of the list 
        last->next=(*head)->next; 
        free(*head); 
        *head=last->next; 
    } 
      
    // Either the node to be deleted is not found  
    // or the end of list is not reached 
    while(last->next!=*head&&last->next->data!=key) { 
        last=last->next; 
    } 
      
    // If node to be deleted was found 
    if(last->next->data==key) { 
        d=last->next; 
        last->next=d->next; 
        free(d); 
    } 
    else
        cout<<"no such keyfound"; 
    } 
  
/* Driver program to test above functions */
int main() 
{ 
    /* Initialize lists as empty */
    Node* head = NULL; 
  
    /* Created linked list will be 2->5->7->8->10 */
    push(&head, 2); 
    push(&head, 5); 
    push(&head, 7); 
    push(&head, 8); 
    push(&head, 10); 
  
    cout << "List Before Deletion: "; 
    printList(head); 
  
    deleteNode(&head, 7); 
  
    cout << "List After Deletion: "; 
    printList(head); 
  
    return 0; 
} 

Java

// Java program to delete a given key from 
// linked list. 
class GFG { 
  
    /* ure for a node */
    static class Node { 
        int data; 
        Node next; 
    }; 
  
    /* Function to insert a node at the beginning of  
a Circular linked list */
    static Node push(Node head_ref, int data) 
    { 
        // Create a new node and make head as next 
        // of it. 
        Node ptr1 = new Node(); 
        ptr1.data = data; 
        ptr1.next = head_ref; 
  
        /* If linked list is not null then set the  
    next of last node */
        if (head_ref != null) { 
            // Find the node before head and update 
            // next of it. 
            Node temp = head_ref; 
            while (temp.next != head_ref) 
                temp = temp.next; 
            temp.next = ptr1; 
        } 
        else
            ptr1.next = ptr1; /*For the first node */
  
        head_ref = ptr1; 
        return head_ref; 
    } 
  
    /* Function to print nodes in a given  
circular linked list */
    static void printList(Node head) 
    { 
        Node temp = head; 
        if (head != null) { 
            do { 
                System.out.printf("%d ", temp.data); 
                temp = temp.next; 
            } while (temp != head); 
        } 
  
        System.out.printf("\n"); 
    } 
  
    /* Function to delete a given node from the list */
    static Node deleteNode(Node head, int key) 
    { 
        if (head == null) 
            return null; 
  
        // Find the required node 
        Node curr = head, prev = new Node(); 
        while (curr.data != key) { 
            if (curr.next == head) { 
                System.out.printf("\nGiven node is not found"
                                  + " in the list!!!"); 
                break; 
            } 
  
            prev = curr; 
            curr = curr.next; 
        } 
  
        // Check if node is only node 
        if (curr.next == head) { 
            head = null; 
            return head; 
        } 
  
        // If more than one node, check if 
        // it is first node 
        if (curr == head) { 
            prev = head; 
            while (prev.next != head) 
                prev = prev.next; 
            head = curr.next; 
            prev.next = head; 
        } 
  
        // check if node is last node 
        else if (curr.next == head) { 
            prev.next = head; 
        } 
        else { 
            prev.next = curr.next; 
        } 
        return head; 
    } 
  
    /* Driver program to test above functions */
    public static void main(String args[]) 
    { 
        /* Initialize lists as empty */
        Node head = null; 
  
        /* Created linked list will be 2.5.7.8.10 */
        head = push(head, 2); 
        head = push(head, 5); 
        head = push(head, 7); 
        head = push(head, 8); 
        head = push(head, 10); 
  
        System.out.printf("List Before Deletion: "); 
        printList(head); 
  
        head = deleteNode(head, 7); 
  
        System.out.printf("List After Deletion: "); 
        printList(head); 
    } 
} 

Python

# Python program to delete a given key from 
# linked list. 
  
# Node of a doubly linked list  
class Node:  
    def __init__(self, next = None, data = None):  
        self.next = next
        self.data = data  
  
# Function to insert a node at the beginning of  
# a Circular linked list  
def push(head_ref, data): 
  
    # Create a new node and make head as next 
    # of it. 
    ptr1 = Node() 
    ptr1.data = data 
    ptr1.next = head_ref 
  
    # If linked list is not None then set the  
    # next of last node  
    if (head_ref != None) : 
          
        # Find the node before head and update 
        # next of it. 
        temp = head_ref 
        while (temp.next != head_ref): 
            temp = temp.next
        temp.next = ptr1 
      
    else: 
        ptr1.next = ptr1 # For the first node  
  
    head_ref = ptr1 
    return head_ref 
  
# Function to print nodes in a given  
# circular linked list  
def printList( head): 
  
    temp = head 
    if (head != None) : 
        while(True) : 
            print( temp.data, end = " ") 
            temp = temp.next
            if (temp == head): 
                break
    print() 
  
# Function to delete a given node from the list  
def deleteNode( head, key) : 
  
    # If linked list is empty 
    if (head == None): 
        return
          
    # If the list contains only a single node 
    if((head).data == key and (head).next == head): 
      
        head = None
      
    last = head 
    d = None
      
    # If head is to be deleted 
    if((head).data == key) : 
          
        # Find the last node of the list 
        while(last.next != head): 
            last = last.next
              
        # Point last node to the next of head i.e.  
        # the second node of the list 
        last.next = (head).next
        head = last.next
      
    # Either the node to be deleted is not found  
    # or the end of list is not reached 
    while(last.next != head and last.next.data != key) : 
        last = last.next
  
    # If node to be deleted was found 
    if(last.next.data == key) : 
        d = last.next
        last.next = d.next
      
    else: 
        print("no such keyfound") 
      
    return head 
  
# Driver program to test above functions  
  
# Initialize lists as empty  
head = None
  
# Created linked list will be 2.5.7.8.10  
head = push(head, 2) 
head = push(head, 5) 
head = push(head, 7) 
head = push(head, 8) 
head = push(head, 10) 
  
print("List Before Deletion: ") 
printList(head) 
  
head = deleteNode(head, 7) 
  
print( "List After Deletion: ") 
printList(head) 

C#

// C# program to delete a given key from 
// linked list. 
using System; 
  
class GFG { 
  
    /* structure for a node */
    public class Node { 
        public int data; 
        public Node next; 
    }; 
  
    /* Function to insert a node at the beginning of  
a Circular linked list */
    static Node push(Node head_ref, int data) 
    { 
        // Create a new node and make head as next 
        // of it. 
        Node ptr1 = new Node(); 
        ptr1.data = data; 
        ptr1.next = head_ref; 
  
        /* If linked list is not null then set the  
    next of last node */
        if (head_ref != null) { 
            // Find the node before head and update 
            // next of it. 
            Node temp = head_ref; 
            while (temp.next != head_ref) 
                temp = temp.next; 
            temp.next = ptr1; 
        } 
        else
            ptr1.next = ptr1; /*For the first node */
  
        head_ref = ptr1; 
        return head_ref; 
    } 
  
    /* Function to print nodes in a given  
circular linked list */
    static void printList(Node head) 
    { 
        Node temp = head; 
        if (head != null) { 
            do { 
                Console.Write("{0} ", temp.data); 
                temp = temp.next; 
            } while (temp != head); 
        } 
  
        Console.Write("\n"); 
    } 
  
    /* Function to delete a given node from the list */
    static Node deleteNode(Node head, int key) 
    { 
        if (head == null) 
            return null; 
  
        // Find the required node 
        Node curr = head, prev = new Node(); 
        while (curr.data != key) { 
            if (curr.next == head) { 
                Console.Write("\nGiven node is not found"
                              + " in the list!!!"); 
                break; 
            } 
  
            prev = curr; 
            curr = curr.next; 
        } 
  
        // Check if node is only node 
        if (curr.next == head) { 
            head = null; 
            return head; 
        } 
  
        // If more than one node, check if 
        // it is first node 
        if (curr == head) { 
            prev = head; 
            while (prev.next != head) 
                prev = prev.next; 
            head = curr.next; 
            prev.next = head; 
        } 
  
        // check if node is last node 
        else if (curr.next == head) { 
            prev.next = head; 
        } 
        else { 
            prev.next = curr.next; 
        } 
        return head; 
    } 
  
    /* Driver code */
    public static void Main(String[] args) 
    { 
        /* Initialize lists as empty */
        Node head = null; 
  
        /* Created linked list will be 2.5.7.8.10 */
        head = push(head, 2); 
        head = push(head, 5); 
        head = push(head, 7); 
        head = push(head, 8); 
        head = push(head, 10); 
  
        Console.Write("List Before Deletion: "); 
        printList(head); 
  
        head = deleteNode(head, 7); 
  
        Console.Write("List After Deletion: "); 
        printList(head); 
    } 
} 

Kết quả in ra là:

List Before Deletion: 10 8 7 5 2
List After Deletion: 10 8 5 2

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

Tài liệu từ cafedev:

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:

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!