我正在尝试使用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);
答案 0 :(得分:3)
你的代码中有很多东西会跳出来。
你分配了很多东西,经常是不必要和无用的。正如rcgldr所指出的,交换函数不应该分配新节点。毕竟,在交换之后,列表由相同的节点组成,只是以不同的顺序。没有新节点。
您的“客户端代码”,即使用链接列表函数的函数(在您的示例中可能为main
)不应显式分配内存。也不应该手动填充节点。它应该只调用add_node
和delete_node
,您也应该编码以释放所有已分配的内存。
在您的情况下,无需将指针传递给指针。传递指向节点和列表结构的指针就足够了。这允许您更改结构的字段。指向struct的指针只有在你想改变结构句柄本身时才有意义,例如通过重新分配它,但你不这样做。 (指向指针通常用于单链表,其中头不存储在结构中。即使在那里,将单个指针包装在结构中也是有用的,这样就不需要指针指针了。 。)
所有逻辑都应该在你的功能中发生。不要修改'main`中的next
和prev
指针;这就是功能的用途。当你调用一个函数并从它返回时,某些“不变量”应该成立,例如:
head
和tail
都为NULL
。head
指向第一个节点; 'head-> prev is
NULL . The
tail points to the last node; ´tail->next
为NULL
。nd
具有上一个节点,然后nd->prev->next == nd
。nd
具有下一个节点时,则为nd->next->prev == nd
。您甚至可以编写一个完整性检查功能,以便在函数进入和退出时强制执行这些不变量。
您为所有字段分配数据。内存分配对于字符串是有意义的,字符串是你事先不知道的字符数组。标量变量id
和gpa
没有意义。您可以将它们声明为非指针并仅指定它们。 (分配内存并通过指针访问它们并没有错,但直接访问要简单得多。)
您的一些函数返回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;
}