使用尾随指针将节点插入链表C
我正在尝试创建一个按字母顺序排列的名称链接列表,我注意到这是一个半常见的问题,但是我在实现上有点困难 所以,在我看来,项目可以添加到链接列表的开头、中间或结尾,我想我正在努力将其添加到末尾 以下是我对布尔值的实现:使用尾随指针将节点插入链表C,c,C,我正在尝试创建一个按字母顺序排列的名称链接列表,我注意到这是一个半常见的问题,但是我在实现上有点困难 所以,在我看来,项目可以添加到链接列表的开头、中间或结尾,我想我正在努力将其添加到末尾 以下是我对布尔值的实现: typedef int bool; #define TRUE 1 #define FALSE 0 这是我的节点/项目/结构: typedef struct student_s Student; struct student_s { char name[MAX_NAME_S
typedef int bool;
#define TRUE 1
#define FALSE 0
这是我的节点/项目/结构:
typedef struct student_s Student;
struct student_s {
char name[MAX_NAME_SIZE];
int age;
Student* next; // Pointer to next student in a list
};
我的比较功能:
// Compares two student structs based on their name and age, and returns true
// if student1 should come before student2 in alphabetical order
bool comesBefore(const Student* student1, const Student* student2) {
int name_compare = strcmp(student1->name, student2->name);
if (name_compare < 0) {
return TRUE;
}
else if (name_compare == 0) {
int age1 = student1->age;
int age2 = student2->age;
if (age1 < age2) {
return TRUE;
}
}
return FALSE;
}
Student* insert(Student* student, Student* list) {
Student* curr = NULL;
Student* prev = NULL;
if (list == NULL) {
printf("list == null\n");
return student;
}
if (comesBefore(student, list)) {
printf("Student comes before list\n");
printf("Student age = %d\n", student->age);
printf("List age = %d\n", list->age);
student->next = list;
return student;
}
for (curr = list, prev = NULL; curr != NULL && comesBefore(student,
curr) != TRUE; prev = curr, curr = curr->next) {
printf("Stage 1\n\n");
printf("curr age = %d\n", curr->age);
printf("student age = %d\n", student->age);
if (comesBefore(student, curr)) {
printf("Stage 2\n");
if (prev != NULL) {
prev->next = student;
}
student->next = curr;
break;
}
if ((curr->next) == NULL) {
printf("Appended at the end of the list\n");
curr->next = student;
break;
}
}
return list;
}
我的主要功能包括所有测试:
int main(void)
{
Student* student1 = malloc(sizeof(Student));
Student* student2 = malloc(sizeof(Student));
Student* student3 = malloc(sizeof(Student));
strncpy(student1->name, "AAAAA", MAX_NAME_SIZE);
student1->age = 10;
student1->next = NULL;
student2->next = NULL;
student3->next = NULL;
strncpy((*student2).name, "BBBBB", MAX_NAME_SIZE);
(*student2).age = 100;
strncpy((*student3).name, "CCCC", MAX_NAME_SIZE);
(*student3).age = 1000;
Student* list1 = insert(student1, NULL);
Student* list2 = insert(student3, list1);
Student* list3 = insert(student2, list2);
printf("head %d\n", list3->age);
printf("second element %d\n", (list3->next)->age);
printf("third element %d\n", ((list3->next)->next)->age);
}
问题是我不断地遇到分割错误。我认为这是当我试图访问列表中的下一个节点(curr->next)时,next被设置为NULL,但无论出于什么原因,我的if语句
if ((curr->next) == NULL) {
printf("Appended at the end of the list\n");
curr->next = student;
break;
}
永远不会被触发。为什么?还是我完全错了?问题是,在一般情况下,插入函数并不能真正插入。看看循环体:
for (curr = list, prev = NULL; curr != NULL && comesBefore(student,
curr) != TRUE; prev = curr, curr = curr->next) {
printf("Stage 1\n\n");
printf("curr age = %d\n", curr->age);
printf("student age = %d\n", student->age);
if (comesBefore(student, curr)) {
printf("Stage 2\n");
if (prev != NULL) {
prev->next = student;
}
student->next = curr;
break;
}
if ((curr->next) == NULL) {
printf("Appended at the end of the list\n");
curr->next = student;
break;
}
}
仅当curr!=空值(&comesBefore)(学生,当前)!=TRUE
,因此if(comesBefore(student,curr))
在循环中永远不会为TRUE
相反,您希望在循环终止后即循环结束后插入。如果((curr->next)==NULL)在循环中,您也不需要该if;如果这是真的,那么循环将再次迭代,curr
将是NULL
,prev
将是您感兴趣的指针。循环条件写得很好,只是在错误的地方做了一些事情
这将有助于:
for (curr = list, prev = NULL;
curr != NULL && comesBefore(student, curr) != TRUE;
prev = curr, curr = curr->next) {
printf("Stage 1\n\n");
printf("curr age = %d\n", curr->age);
printf("student age = %d\n", student->age);
}
student->next = curr;
prev->next = student;
return list;
以下是此修复程序的整个功能:
Student* insert(Student* student, Student* list) {
Student* curr = NULL;
Student* prev = NULL;
if (list == NULL) {
printf("list == null\n");
return student;
}
if (comesBefore(student, list)) {
printf("Student comes before list\n");
printf("Student age = %d\n", student->age);
printf("List age = %d\n", list->age);
student->next = list;
return student;
}
for (curr = list, prev = NULL;
curr != NULL && comesBefore(student, curr) != TRUE;
prev = curr, curr = curr->next) {
printf("Stage 1\n\n");
printf("curr age = %d\n", curr->age);
printf("student age = %d\n", student->age);
}
student->next = curr;
prev->next = student;
return list;
}
调试完成后,循环体将为空;您可能希望添加一条注释,说明这是故意的(我通常喜欢这样做,以便其他阅读代码的人知道这不是bug)。比如:
Student* insert(Student* student, Student* list) {
Student* curr = NULL;
Student* prev = NULL;
if (list == NULL)
return student;
if (comesBefore(student, list)) {
student->next = list;
return student;
}
for (curr = list, prev = NULL;
curr != NULL && comesBefore(student, curr) != TRUE;
prev = curr, curr = curr->next)
; /* Intentionally left blank */
student->next = curr;
prev->next = student;
return list;
}
此外,您不需要测试prev!=NULL
,因为如果达到循环,那么我们知道comesBefore(student,list)
为false(因为我们在代码前面进行了测试),因此循环将始终至少执行一次。对于自我文档(并确保此变量不会因将来的代码更改而被违反),您可能希望在循环之后添加一个assert(3)
,如下所示:
Student* insert(Student* student, Student* list) {
Student* curr = NULL;
Student* prev = NULL;
if (list == NULL)
return student;
if (comesBefore(student, list)) {
student->next = list;
return student;
}
for (curr = list, prev = NULL;
curr != NULL && comesBefore(student, curr) != TRUE;
prev = curr, curr = curr->next)
; /* Intentionally left blank */
assert(prev != NULL);
student->next = curr;
prev->next = student;
return list;
}
您需要#包括才能使用断言(3)
最大名称大小的值是多少旁注:您不应该实现自己的bool
,如果您的编译器支持stdbool.h
。我将投票结束这个问题,因为标准DCV'cos将在没有调试的情况下完成问题。最大名称大小为50左右,对于我使用的字符串来说肯定足够长。不知道,用户694733,谢谢!马丁,很抱歉我是一个完全的新手,但是我该如何去调试。。。对不起,为什么不试着用gdb调试insert函数呢?