[英]Trouble swapping nodes in doubly linked list
我正在嘗試使用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的值,而不是簡單地將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);
您的代碼中跳出了很多東西。
您分配了很多東西,通常是不必要和無用的。 正如rcgldr指出的那樣,交換功能不應分配新節點。 畢竟,列表在交換后由相同的節點組成,只是順序不同。 沒有新節點。
您的“客戶端代碼”,即使用鏈表功能的功能(在您的示例中可能是main
功能)不應顯式分配內存。 它也不應該手動填充節點。 它應該只調用add_node
和delete_node
,還應該對其進行編碼,以釋放所有分配的內存。
在您的情況下,無需將指針傳遞給指針。 將指針傳遞到節點和列表結構就足夠了。 這使您可以更改結構的字段。 僅當您要更改結構句柄本身(例如通過重新分配結構句柄)時,指向結構指針的指針才有意義,但您不這樣做。 (指向指針的指針通常用於單鏈列表,其中頭未存儲在結構中。即使在此處,將單個指針包裝在結構中也可能很有用,這樣就無需指向指針的指針)
所有邏輯都應在函數內部發生。 不要在“ main”中修改next
和prev
指針; 這就是功能的目的。 當您調用函數並從中返回時,某些“不變式”應為true,例如:
head
和tail
均為NULL
。 head
指向第一個節點;否則, head
指向第一個節點。 ´head-> prev is
NULL . The
. The
尾points to the last node; ´tail->next
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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.