Hàm đổi vị trí trong danh sách liên kết đôi không hoạt động

Hàm swapNode trong chương trình dưới đây đổi chỗ 2 node trong danh sách. Ý tưởng của em là dùng biến node p để đổi giá trị 2 node node *Anode *B rồi liên kết lại với các node bên cạnh. Khi cho chạy thì kết quả không có sự sắp xếp lại của 2 node được chọn mà chỉ in ra như khi không gọi hàm swapNode. Mọi người chỉ hco em lỗi sai với ạ. Dưới đây là phần code của em:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

struct node;
struct list;

typedef struct node node;
typedef struct list list;

struct node
{
    int point;
    char name[30];
    node *next;
    node *prev;
};

struct list
{
    node *head;
    node *tail;
    int count;
};

node *allocateNewNode(int point, char name[30], node *prev, node *next);
list *createList();
bool insertHead(list *listNode, int point, char name[30]);
bool compareName(char a[30], char b[30]);
bool swapNode(list *listNode, char nameA[30], char nameB[30]);

int main()
{
    list *listNode = createList();

    insertHead(listNode, 10, "abc def");
    insertHead(listNode, 9, "qwe rty");
    insertHead(listNode, 8, "ui op");
    insertHead(listNode, 30, "fgh jkl");
    insertHead(listNode, 1234, "akaka");

   swapNode(listNode, "ui op", "abc def");

    node *temp = listNode->head;
    while (temp != NULL)
    {
        printf("%-20s%d\n", temp->name, temp->point);
        temp = temp->next;
    }
    printf("\n%d", listNode->count);
    return 0;
}

node *allocateNewNode(int point, char name[30], node *prev, node *next)
{
    node *newNode = (node *)malloc(sizeof(node));
    newNode->point = point;
    strcpy(newNode->name, name);
    newNode->next = next;
    newNode->prev = prev;
    return newNode;
}

list *createList()
{
    list *listNode = (list *)malloc(sizeof(list));
    listNode->count = 0;
    listNode->head = NULL;
    listNode->tail = NULL;
    return listNode;
}

bool insertHead(list *listNode, int point, char name[30])
{
    node *newNode = allocateNewNode(point, name, NULL, listNode->head);
    if (listNode->head)
        listNode->head->prev = newNode;
    listNode->head = newNode;
    if (listNode->tail == NULL)
        listNode->tail = newNode;
    ++listNode->count;
    return true;
}
bool compareName(char a[30], char b[30])
{
    for (int i = 0; i < 31; i++)
    {
        if (a[i] != b[i])
            return false;
        if (a[i] == '\0')
            break;
    }
    return true;
}

bool swapNode(list *listNode, char nameA[30], char nameB[30])
{
    node *A = NULL, *B = NULL;
    node *temp = listNode->head;

    for (int i = 0; i < listNode->count ; i++)
    {
        if (compareName(temp->name, nameA))
            A = temp;
        else if (compareName(temp->name, nameB))
            B = temp;
        temp = temp->next;
        if (A && B)
            break;
    }
    if (!A || !B)
        return false;
    else if (A == B)
        return false;

    node p=*A;
    *A=*B;
    *B=p;

    if (A->prev)
        A->prev->next = A;
    if (A->next)
        A->next->prev = A;
    if (B->prev)
        B->prev->next = B;
    if (B->next)
        B->next->prev = B;

    return true;
}

Em cảm ơn mọi người

Nguyên đoạn này khá là vô lý.

A->prev->next = A;
...

Chẳng khác nào gán A = A cả.

Kiểu như “lày” cho dễ hiểu:
(Lấy riêng prevnext của AB rồi gán đảo lại)

node* Pa = A->prev;
node* Na = A->next;
Pa->next=B; B->prev=Pa;
Na->prev=B; B->next=Na;
...

Tối ưu thế nào tùy bạn.

3 Likes

đoạn này em nghĩ là do:

node p=*A;
    *A=*B;
    *B=p;

giá trị bao gồm cả next và prev của 2 node AB đã đổi cho nhau nên trong:

if (A->prev)
    A->prev->next = A;

A->prev mới chỉ là B->prev ban đầu, chứ A->prev->next chưa trỏ về A mà vẫn đang trỏ vào B. Vì vậy viết A->prev->next=A để có liên kết từ node trước sang node A.
Như vậy có sai không ạ?

Nhìn vào hình và chạy chay từng dòng code của bạn bên dưới xem nó làm những gì. :slight_smile:

    if (A->prev)
        A->prev->next = A;
    if (A->next)
        A->next->prev = A;
    if (B->prev)
        B->prev->next = B;
    if (B->next)
        B->next->prev = B;

Cái hình mình nối hơi sai đó, kệ nha. :kissing:

3 Likes

@Sherly1001 em là như này:

Vậy nhìn kỹ hình và chạy từng bước xem có phải bạn đang đưa A và D lại chỗ cũ không. :slight_smile:

Sửa lại như này nè. :kissing_smiling_eyes:

    node p = *A;
    *A = *B;
    *B = p;
    
    B->next = A->next;
    B->prev = A->prev;
    
    A->next = p.next;
    A->prev = p.prev;
3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?