麻烦交换双链表中的节点

时间:2015-01-27 02:43:47

标签: c list data-structures linked-list swap

我正在尝试使用C交换双链表中的两个节点。如果我传入一些值,例如列表的头部和尾部,以及介于两者之间的某些值,它就可以正常工作。然而,在其他人看来,一个人的价值似乎被另一个人所覆盖,我被抛入了一个循环中。

节点/列表:

struct node //node for linked list
{
    unsigned long int *id;
    char *firstname, *lastname, *department;
    float *gpa;
    struct node *next, *prev;
};
struct linked_list //doubly linked_list data structure
{
    struct node *head, *tail;
};

我可以成功地将节点添加到列表中并将尾部移动到新添加的节点。

void *add_node(struct node **tail, unsigned long int *id, char *first, char *last, char *dept, float *gpa) //create a node, add to tail
{
    struct node *newStudent = (struct node*)malloc(sizeof(struct node));
    newStudent->firstname = (char*)malloc(strlen(first)+1);
    newStudent->lastname = (char*)malloc(strlen(last)+1);
    newStudent->department = (char*)malloc(strlen(dept)+1);
    newStudent->id = (unsigned long int*)malloc(sizeof(unsigned long int));
    newStudent->gpa = (float*)malloc(sizeof(float));

    *(newStudent->id) = *id;
    *(newStudent->gpa) = *gpa;

    strcpy(newStudent->firstname, first);
    strcpy(newStudent->lastname, last);
    strcpy(newStudent->department, dept);

    newStudent->next = NULL;
    if(tail) //not the first node in the list
    {
        newStudent->prev = *tail;
        (*tail)->next = newStudent;
        *tail = newStudent;
    }
    else //head of the list
        return newStudent;
}

最后,我的交换功能:

void *_swap(struct node **x, struct node **y, struct linked_list **list)
{
    struct node *temp = (struct node*)malloc(sizeof(struct node));
    memcpy(temp, *x, sizeof(struct node));

    if( (*y)->prev ) /// if y has a previous...
    {
        (*x)->prev = (*y)->prev;
        (*y)->prev->next = *x;
    }
    else
        (*x)->prev = NULL;

    if( (*y)->next )  /// if y has a next...
    {
        (*x)->next = (*y)->next;
        (*y)->next->prev = *x;
    }
    else
        (*x)->next = NULL;

    if( temp->prev) /// if original x has a previous...
    {
        (*y)->prev = temp->prev;
        temp->prev->next = *y;
    }
    else
        (*y)->prev = NULL;

    if(temp->next) /// if original x has a next...
    {
        (*y)->next = temp->next;
        temp->next->prev = *y;
    }
    else
    (*y)->next = NULL;

    free(temp);

    if((*list)->head == *x && (*list)->tail == *y)
    {
        (*list)->head = *y;
        (*list)->tail=*x;
    }
    else if((*list)->head == *y && (*list)->tail == *x)
    {
        (*list)->head = *x;
        (*list)->tail=*y;
    }
    else if((*list)->head == *x)
        (*list)->head = *y;
    else if((*list)->head == *y)
        (*list)->head = *x;
    else if((*list)->tail == *x)
        (*list)->tail = *y;
    else if((*list)->tail == *y)
        (*list)->tail = *x;

    printf("%s %s %s %s %s\n\n\n\n", (*list)->head->firstname, (*list)->head->next->firstname, (*list)->head->next->next->firstname, (*list)->head->next->next->next->firstname, (*list)->head->next->next->next->next->firstname);
}

当我打电话的时候             temp-> next-> prev = * y; 它有时似乎覆盖了x的值,在这种情况下是x,而不是简单地将linked_list指针重新分配给y。

我能够很好地建立我的清单:

struct linked_list *list = (struct linked_list*)malloc(sizeof(struct linked_list));
list->head = (struct node*)malloc(sizeof(struct node));
list->tail = (struct node*)malloc(sizeof(struct node));
unsigned long int *id = malloc(sizeof(unsigned long int));
*id = 343232;
float gpa = 3.2;
list->head = add_node(NULL, id, "Matthew", "D", "CECS", &gpa);
list->tail = list->head;

add_node(&(list->tail), id, "John", "X", "PNY", &gpa);
add_node(&(list->tail), id, "Rebecca", "H", "ECE", &gpa);

1 个答案:

答案 0 :(得分:3)

你的代码中有很多东西会跳出来。

  • 你分配了很多东西,经常是不必要和无用的。正如rcgldr所指出的,交换函数不应该分配新节点。毕竟,在交换之后,列表由相同的节点组成,只是以不同的顺序。没有新节点。

  • 您的“客户端代码”,即使用链接列表函数的函数(在您的示例中可能为main)不应显式分配内存。也不应该手动填充节点。它应该只调用add_nodedelete_node,您也应该编码以释放所有已分配的内存。

  • 在您的情况下,无需将指针传递给指针。传递指向节点和列表结构的指针就足够了。这允许您更改结构的字段。指向struct的指针只有在你想改变结构句柄本身时才有意义,例如通过重新分配它,但你不这样做。 (指向指针通常用于单链表,其中头不存储在结构中。即使在那里,将单个指针包装在结构中也是有用的,这样就不需要指针指针了。 。)

  • 所有逻辑都应该在你的功能中发生。不要修改'main`中的nextprev指针;这就是功能的用途。当你调用一个函数并从它返回时,某些“不变量”应该成立,例如:

    • 当列表为空时,headtail都为NULL
    • 否则,head指向第一个节点; 'head-> prev is NULL . The tail points to the last node; ´tail->nextNULL
    • 当节点nd具有上一个节点,然后nd->prev->next == nd
    • 同样,当节点nd具有下一个节点时,则为nd->next->prev == nd

    您甚至可以编写一个完整性检查功能,以便在函数进入和退出时强制执行这些不变量。

  • 您为所有字段分配数据。内存分配对于字符串是有意义的,字符串是你事先不知道的字符数组。标量变量idgpa没有意义。您可以将它们声明为非指针并仅指定它们。 (分配内存并通过指针访问它们并没有错,但直接访问要简单得多。)

  • 您的一些函数返回void *,即void指针。那不是你想要的。您的函数应该是void,即没有返回值,或者它们应该返回指向节点的指针。 (void指针是一种合法的数据类型,它指的是指向任何数据类型的指针,你无法解除引用。它用于qsort这样的泛型函数,不应该在你的代码中使用。你是不编写通用函数,而是编写具体链表的函数。)

您可以将交换视为删除节点并将其重新插入各自的旧前辈之后。您仍然需要注意捕获节点相邻的情况。

这是一个尝试尊重我上面提到的要点的示例实现:

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

typedef unsigned long int ulong;

struct node
{
    ulong id;
    char *name;
    float gpa;
    struct node *next;
    struct node *prev;
};

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



/*
 *      Create a new, unconnected node
 */
struct node *node_new(ulong id, const char *name, float gpa)
{
    struct node *node = malloc(sizeof(*node));  // Error checking!

    node->prev = NULL;
    node->next = NULL;
    node->id = id;
    node->gpa = gpa;

    node->name = malloc(strlen(name) + 1);
    strcpy(node->name, name);

    return node;
}

/*
 *      Create a list
 */
struct list *list_new()
{
    struct list *list = malloc(sizeof(*list));  // Error checking!

    list->head = list->tail = NULL;
    return list;
}

/*
 *      Add a student to list
 */
struct node *list_add(struct list *list,
    ulong id, const char *name, float gpa)
{
    struct node *node = node_new(id, name, gpa);

    node->prev = list->tail;
    if (list->tail == NULL) {
        list->head = list->tail = node;
    } else {
        list->tail->next = node;
        list->tail = node;
    }

    return node;
}

/*
 *      Delete a node from the list.
 */
void list_delete(struct list *list, struct node *node)
{
    if (node->prev) node->prev->next = node->next;
    else list->head = node->next;

    if (node->next) node->next->prev = node->prev;
    else list->tail = node->prev;

    free(node->name);
    free(node);
}

/*
 *      Find student by id; return NULL if not found.
 */
struct node *list_find_by_id(const struct list *list, ulong id)
{
    struct node *node = list->head;

    while (node) {
        if (node->id == id) return node;
        node = node->next;
    }

    return NULL;
}

/*
 *      Extract a node without deleting
 */
void list_remove(struct list *list, struct node *node)
{
    if (node->prev) node->prev->next = node->next;
    else list->head = node->next;

    if (node->next) node->next->prev = node->prev;
    else list->tail = node->prev;

    node->prev = node->next = NULL;
}

/*
 *      Insert node after prev or at the front when prev is NULL
 */
void list_insert_after(struct list *list,
    struct node *node, struct node *prev)
{
    if (prev) {
        node->next = prev->next;
        prev->next = node;
    } else {
        node->next = list->head;
        list->head = node;
    }
    node->prev = prev;
    if (node->next) node->next->prev = node;
}

/*
 *      Swap two nodes' positions in the list
 */
void list_swap(struct list *list, struct node *x, struct node *y)
{
    if (x == y) return;

    struct node *xprev = x->prev;
    struct node *yprev = y->prev;

    if (xprev == y) {            
        list_remove(list, x);
        list_insert_after(list, x, yprev);
    } else if (yprev == x) {            
        list_remove(list, y);
        list_insert_after(list, y, xprev);
    } else {
        list_remove(list, x);
        list_remove(list, y);

        list_insert_after(list, x, yprev);
        list_insert_after(list, y, xprev);
    }
}

/*
 *      Print list
 */
void list_print(const struct list *list)
{
    const struct node *node = list->head;

    while (node) {
        printf("%8lu  %-20s  %8.1f\n", node->id, node->name, node->gpa);
        node = node->next;
    }
    printf("\n");
}

/*
 *      Delete a list and all its nodes
 */
void list_destroy(struct list *list)
{
    while (list->head) list_delete(list, list->head);
    free(list);
}

/*
 *      Example client code using the list
 */
int main()
{
    struct list *list = list_new();

    list_add(list, 342232, "Matthew",   3.2);
    list_add(list, 342856, "John",      1.9);
    list_add(list, 342109, "Rebecca",   6.4);
    list_add(list, 342834, "Shirley",   2.6);
    list_add(list, 343009, "Simon",     1.4);
    list_add(list, 342170, "Antonio",   3.5);

    list_print(list);

    struct node *simon = list_find_by_id(list, 343009);
    struct node *becky = list_find_by_id(list, 342109);

    if (simon && becky) {
        list_swap(list, simon, becky);
        list_print(list);
    }

    list_destroy(list);

    return 0;
}