LATEST

Xóa node trong DSLK đôi

Trong bài viết này, codehow sẽ hướng dẫn các bạn cách xóa node trong DSLK đôi. Đây là một trong các thao tác cơ bản khi sử dụng danh sách liên kết đôi, vì vậy hãy tìm hiểu nó thật kĩ nhé.

Tương tự như việc thêm node vào DSLK đôi ở bài trước mình đã hướng dẫn. Việc xóa node trong DSLK đôi cũng có hai cách xóa đó là xóa node đầu tiên và xóa node cuối cùng của danh sách.

Vậy làm thế nào để thực hiện chương trình xóa node trong C / C++ thì hãy bắt đầu cùng mình ngay thôi nhé.

Xóa node đầu trong DSLK đôi

Như các bạn đã biết thì trong DSLK đôi node head luôn luôn quản lý node đầu tiên của danh sách. Vậy nếu chúng ta muốn xóa node đầu thì có nghĩa là xóa node head, như vậy thì sẽ không còn node nào quản lý node đầu nữa.

bai35 01 png

Vì vậy để node head vẫn tồn tại và quản lý node đầu tiên của danh sách, chúng ta cần phải chuyển node head đến node tiếp theo. Sau khi xóa node đầu tiên thì node thứ hai chính là node head.

head = head -> next

Thêm một điều nữa là node head sẽ có con trỏ prev trỏ về NULL, vậy nên sau khi xóa chúng ta cần cập nhật lại con trỏ prev của head trỏ về NULL nữa nhé.

head -> prev = NULL

Lưu ý rằng chúng ta cần kiểm tra xem danh sách có rỗng không nhé, nếu rỗng thì chúng ta sẽ không thực hiện xóa node mà chỉ thông báo cho người dùng.

Hàm xóa node đầu trong DSLK đôi.

/* Xóa node đầu trong danh sách */
void DelFirst() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //ngược lại nếu danh sách có phần tử thì 
    head = head->next;//thực hiện dịch chuyển node head đến node kế tiếp
    head->prev = NULL;//sau đó cho con trỏ prev của head = null
}

Xóa node cuối trong DSLK đôi

Đối với trường hợp chúng ta muốn xóa node cuối cũng sẽ thực hiện tương tự như việc xóa node đầu.

Để đảm bảo rằng trong danh sách đã tồn tại phần tử, chúng ta cần kiểm tra xem danh sách có rỗng không nhé. Nếu rỗng thì chỉ thông báo cho người dùng rồi thoát khỏi hàm. Trường hợp danh sách đã tồn tại phần tử thì chúng ta mới thực hiện xóa node cuối.

//Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }

bai35 02 png

Để xóa node cuối thì việc đầu tiên ta cần dịch chuyển node tail về node trước đó đã nhé. Bởi vì node tail luôn quản lý node cuối, nếu chúng ta không dịch chuyển mà xóa luôn thì sẽ không còn node tail để quản lý ndoe cuối nữa.

tail = tail -> prev

Sau khi dịch chuyển ta cần thiết lập lại mối liên kết của con trỏ next == NULL, vì con trỏ next của node tail luôn luôn trỏ về NULL nhé.

tail->next = NULL;

Hàm xóa node cuối trong DSLK đôi.

/* Xóa node cuối trong danh sách */
void DelLast() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //Ngược lại nếu danh sách có phần tử thì 
    tail = tail->prev;//thực hiện dịch chuyển tail về node trước đó
    tail->next = NULL;//sau đó cho con trỏ next của tail == null
}

Ví dụ xóa node trong DSLK đôi

Trong phần này mình sẽ thực hiện một chương trình để xóa node trong DSLK đôi. Chương trình sẽ sử dụng dữ liệu từ các bài trước, điều này giúp các bạn vừa ôn lại kiến thức cũ và vừa áp dụng kiến thức mới. Cụ thể như sau:

  • Xây dụng cấu trúc dữ liệu của DSLK đôi.
  • Tạo mới node.
  • Chèn node vào đầu, vào cuối dánh sách.
  • Duyệt danh sách từ đầu về cuối và từ cuối về đầu.
  • Xóa node đầu và xóa node cuối trong DSLK đôi.

Bây giờ chúng ta sẽ bắt đầu thực hiện từng yêu cầu mà đề bài đưa ra nhé.

Bước 1: Xây dụng cấu trúc dữ liệu của DSLK đôi.

/* tạo cấu trúc node */
struct Node  {
    int data;
    struct Node* next;
    struct Node* prev;
};
 
struct Node *head, *tail; // Khởi tạo Node head global của dslk đôi.

Bước 2: Tạo mới node.

/* tạo node mới */
struct Node* CreateNode(int x) {
    struct Node* newNode
        = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = x;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}

Bước 3: Chèn node vào đầu, vào cuối danh sách.

/* thêm node vào đầu danh sách */
void InsertFirst(int x) {
  //sử dụng hàm tạo Node tạo một Node mới
    struct Node* newNode = CreateNode(x);
   //nếu danh sách rỗng thì node chèn vào vừa là node đầu vừa là node cuối
    if(head == NULL) {
        head = newNode;
        tail = newNode;
        return;
    }
    //Nếu danh sách không rỗng thì, dịch chuyển Node head về node mới chèn, và cho con trỏ của newNode trỏ đến Node head
    head->prev = newNode;
    newNode->next = head;
    head = newNode;
}
/* thêm node vào cuối danh sách */
void InsertLast(int x) {
  //sử dụng hàm tạo Node để tạo node mới newNode
    struct Node* newNode = CreateNode(x);
    //Nếu danh sách rỗng thì newNode vừa là node đầu vừa là node cuối
    if(head == NULL) {
        head = newNode;
        tail = newNode;
        return;
    }
    //Nếu danh sách có phần tử thì, 
    tail->next = newNode;// con trỏ next của tail trỏ đến newNode
    newNode->prev = tail;// con trỏ prev của newNode trỏ đến tail
    tail = newNode;//dịch chuyển tail về newNode, vì tail luôn luôn quản lý phần tử cuối cùng trong danh sách
}

Bước 4: Duyệt danh sách từ đầu về cuối và từ cuối về đầu.

/* hiển thị từ đầu đến cuối */
void Print() {
    struct Node* temp = head;
    printf("\nĐầu đến cuối: ");
    while(temp != NULL) {
        printf("%d ",temp->data);
        temp = temp->next;
    }
    printf("\n");
}
  
/* hiển thị từ cuối về đầu */
void ReversePrint() {
    struct Node* temp = tail;
    if(temp == NULL) return; // empty list, exit
    // Traversing backward using prev pointer
    printf("\nCuối về đầu: ");
    while(temp != NULL) {
        printf("%d ",temp->data);
        temp = temp->prev;
    }
    printf("\n");
}

Bước 5: Xóa node đầu và xóa node cuối trong DSLK đôi.

/* Xóa node đầu trong danh sách */
void DelFirst() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //ngược lại nếu danh sách có phần tử thì 
    head = head->next;//thực hiện dịch chuyển node head đến node kế tiếp
    head->prev = NULL;//sau đó cho con trỏ prev của head = null
}
/* Xóa node cuối trong danh sách */
void DelLast() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //Ngược lại nếu danh sách có phần tử thì 
    tail = tail->prev;//thực hiện dịch chuyển tail về node trước đó
    tail->next = NULL;//sau đó cho con trỏ next của tail == null
}

Dưới đây là chương trình mình đã viết sẵn bằng ngôn ngữ C++, các bạn có thể tham khảo nhé.

Full code:

#include <iostream>
using namespace std;
/* tạo cấu trúc node */
struct Node  {
    int data;
    struct Node* next;
    struct Node* prev;
};
 
struct Node *head, *tail; // Khởi tạo Node head global của dslk đôi.
  
/* tạo node mới */
struct Node* CreateNode(int x) {
    struct Node* newNode
        = (struct Node*)malloc(sizeof(struct Node));
    newNode->data = x;
    newNode->prev = NULL;
    newNode->next = NULL;
    return newNode;
}
/* hiển thị từ đầu đến cuối */
void Print() {
    struct Node* temp = head;
    printf("\nĐầu đến cuối: ");
    while(temp != NULL) {
        printf("%d ",temp->data);
        temp = temp->next;
    }
    printf("\n");
}
  
/* hiển thị từ cuối về đầu */
void ReversePrint() {
    struct Node* temp = tail;
    if(temp == NULL) return; // empty list, exit
    // Traversing backward using prev pointer
    printf("\nCuối về đầu: ");
    while(temp != NULL) {
        printf("%d ",temp->data);
        temp = temp->prev;
    }
    printf("\n");
}
/* thêm node vào đầu danh sách */
void InsertFirst(int x) {
  //sử dụng hàm tạo Node tạo một Node mới
    struct Node* newNode = CreateNode(x);
   //nếu danh sách rỗng thì node chèn vào vừa là node đầu vừa là node cuối
    if(head == NULL) {
        head = newNode;
        tail = newNode;
        return;
    }
    //Nếu danh sách không rỗng thì, dịch chuyển Node head về node mới chèn, và cho con trỏ của newNode trỏ đến Node head
    head->prev = newNode;
    newNode->next = head;
    head = newNode;
}
/* thêm node vào cuối danh sách */
void InsertLast(int x) {
  //sử dụng hàm tạo Node để tạo node mới newNode
    struct Node* newNode = CreateNode(x);
    //Nếu danh sách rỗng thì newNode vừa là node đầu vừa là node cuối
    if(head == NULL) {
        head = newNode;
        tail = newNode;
        return;
    }
    //Nếu danh sách có phần tử thì, 
    tail->next = newNode;// con trỏ next của tail trỏ đến newNode
    newNode->prev = tail;// con trỏ prev của newNode trỏ đến tail
    tail = newNode;//dịch chuyển tail về newNode, vì tail luôn luôn quản lý phần tử cuối cùng trong danh sách
}
/* Xóa node đầu trong danh sách */
void DelFirst() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //ngược lại nếu danh sách có phần tử thì 
    head = head->next;//thực hiện dịch chuyển node head đến node kế tiếp
    head->prev = NULL;//sau đó cho con trỏ prev của head = null
}
/* Xóa node cuối trong danh sách */
void DelLast() {
  //Nếu danh sách rỗng thì return và thoát khỏi hàm
    if(head == NULL) {
        return;
    }
    //Ngược lại nếu danh sách có phần tử thì 
    tail = tail->prev;//thực hiện dịch chuyển tail về node trước đó
    tail->next = NULL;//sau đó cho con trỏ next của tail == null
}
int main() {
  
    head = NULL;
 //gọi hàm thêm node vào đầu danh sách
     
    InsertFirst(2);
    InsertFirst(3);
    InsertFirst(4);
    cout<<"Danh sách sau khi thêm node vào đầu: \n";
    Print();
    ReversePrint(); 
    cout<<"\n----------end--------------\n";
 //gọi hàm thêm node vào cuối danh sách
    InsertLast(5);
    InsertLast(6);
    InsertLast(7);
    cout<<"Danh sách sau khi thêm node vào cuối: \n";
    Print(); 
    ReversePrint();
    cout<<"\n----------end--------------\n";
  //gọi hàm xóa đầu danh sách
    DelFirst();
    cout<<"Danh sách sau khi xóa đầu : \n";
    Print();
    ReversePrint();
    cout<<"\n----------end--------------\n";
  //gọi hàm xóa cuối danh sách
    DelLast();
    cout<<"Danh sách sau khi xóa cuối : \n";
    Print();
    ReversePrint();
 
    cout<<"\n---------------------------------------\n";
    cout<<"Chương trình này được đăng tại codehow.net";
}

bai35 03 png

Như vậy là chúng ta đã cùng nhau tìm hiểu về cách xóa node trong DSLK đôi. Ở bài tiếp theo, mình sẽ hướng dẫn các bạn cách tìm kiềm phần tử k trong danh sách liên kết đôi. Các bạn chú ý theo dõi nhé, cảm ơn các bạn rất nhiều !!!!

Cùng chuyên mục:

Xóa node khỏi cây nhị phân tìm kiếm

Xóa node khỏi cây nhị phân tìm kiếm

Tìm node Max và Min trong cây nhị phân tìm kiếm

Tìm node Max và Min trong cây nhị phân tìm kiếm

Xuất node con và node lá trong cây nhị phân tìm kiếm

Xuất node con và node lá trong cây nhị phân tìm kiếm

Tìm kiếm trên cây nhị phân tìm kiếm

Tìm kiếm trên cây nhị phân tìm kiếm

Duyệt cây nhị phân tìm kiếm

Duyệt cây nhị phân tìm kiếm

Thêm node vào cây nhị phân tìm kiếm

Thêm node vào cây nhị phân tìm kiếm

Cây nhị phân (Binary tree) là gì? Cơ chế hoạt động của nó

Cây nhị phân (Binary tree) là gì? Cơ chế hoạt động của nó

Cách gộp hai danh sách liên kết đôi

Cách gộp hai danh sách liên kết đôi

Tìm kiếm phần tử trong DSLK đôi

Tìm kiếm phần tử trong DSLK đôi

Chèn node (Insert node) vào DSLK đôi

Chèn node (Insert node) vào DSLK đôi

Duyệt danh sách liên kết đôi

Duyệt danh sách liên kết đôi

Tạo node mới trong DSLK đôi

Tạo node mới trong DSLK đôi

DSLK đôi là gì? Cấu trúc dữ liệu của DSLK đôi

DSLK đôi là gì? Cấu trúc dữ liệu của DSLK đôi

Quản lý sinh viên bằng DSLK đơn

Quản lý sinh viên bằng DSLK đơn

Tìm kiếm và sắp xếp trong DSLK đơn

Tìm kiếm và sắp xếp trong DSLK đơn

Xóa node (Delete node) trong DSLK đơn

Xóa node (Delete node) trong DSLK đơn

Chèn node (Insert node) vào DSLK đơn

Chèn node (Insert node) vào DSLK đơn

Tạo node mới trong DSLK đơn

Tạo node mới trong DSLK đơn

Cấu trúc dữ liệu của DSLK đơn

Cấu trúc dữ liệu của DSLK đơn

Danh sách liên kết (Linked List) là gì? Các loại danh sách liên kết

Danh sách liên kết (Linked List) là gì? Các loại danh sách liên kết

Top