任务是按字母顺序对列表进行排序。这可以通过更改指针变量来完成,而不仅仅是切换节点的内容。
我首先想实现交换功能。该功能应交换2个节点。之后,我想实现一种排序算法。我的问题是,交换功能并未真正发挥应有的作用,算法也不起作用(ofc,因为交换功能甚至不起作用)。
struct student {
char Vorname[51];
char Nachname[51];
int MatNr;
char Adresse[51];
int Kurse;
struct student *next;
struct student *previous;
};
struct student *first = NULL;
struct student *last = NULL;
void swap(struct student *pointer) {
struct student *pointer1, *pointer3, *pointer4;
pointer1 = pointer->previous;
pointer3 = pointer->next;
pointer4 = pointer->next->next;
pointer4->previous = pointer;
pointer->next = pointer4;
pointer1->next = pointer3;
pointer3->previous = pointer1;
pointer->previous = pointer3;
pointer3->next = pointer;
}
这是尚未完成的排序功能。我尚未正确实现它,因为交换功能首先引起了我的注意。
void sort(void) {
struct student *pointer1, *pointer2, *pointer3, *pointer4;
pointer1 = first->previous;
pointer2 = pointer1->next;
pointer3 = pointer2->next;
pointer4 = pointer3->next;
while(pointer2 != NULL){
if((strcmp(pointer2->Nachname, pointer3->Nachname)) > 0) {
swap(pointer2);
}
pointer1 = pointer1->next;
printList();
}
}
当我运行swap(first);
时,第一个元素没有显示,因为指针first
现在指向第二个节点。好的,使用first = pointer3;
当我运行swap(first->next);
时,存在一个类似的问题,因为它也遗漏了列表的一个节点。
我不太确定如何正确使用此功能,因为first
不应参与交换列表的第二和第三节点。
我非常感谢能帮助我解决此问题的任何帮助,也许我只是忽略了一些小错误,但我真的无法解决此问题。 谢谢!
答案 0 :(得分:1)
通过交换双向链接的节点对列表进行排序似乎效率很低,因为您不能使用诸如合并排序之类的快速算法。
您可以改为在递归合并排序函数中仅使用next
链接,并在结果列表上重建反向链接。
这是方法:
struct student {
char Vorname[51];
char Nachname[51];
int MatNr;
char Adresse[51];
int Kurse;
struct student *next;
struct student *previous;
};
struct student *first = NULL;
struct student *last = NULL;
/* Merge two sorted lists. p1 and p2 are != NULL */
struct student *merge(struct student *p1, struct student *p2) {
struct student *head, **pp;
pp = &head;
for (;;) {
if (strcmp(p1->Nachname, p2->Nachname) <= 0) {
*pp = p1;
pp = &p1->next;
p1 = p1->next;
if (p1 == NULL) {
*pp = p2;
break;
}
} else {
*pp = p2;
pp = &p2->next;
p2 = p2->next;
if (p2 == NULL) {
*pp = p1;
break;
}
}
}
return head;
}
/* Recursive top-down merge sort */
struct student *msort(struct student *np) {
struct student *p1, *p2;
/* trivial lists are sorted */
if (np == NULL || np->next == NULL)
return np;
/* locate mid-point using 2 finger method */
for (p1 = np, p2 = np->next; p2 && p2->next; p2 = p2->next->next)
p1 = p1->next;
/* split the list at mid-point */
p2 = p1->next;
p1->next = NULL;
p1 = np;
/* sort the sublists recursively */
p1 = msort(p1);
p2 = msort(p2);
return merge(p1, p2);
}
void sort(void) {
struct student *p1, *p2;
/* sort the list as a singly linked list */
first = msort(first);
/* reconstruct the backlinks */
p1 = NULL;
for (p2 = first; p2; p2 = p2->next) {
p2->last = p1;
p1 = p2;
}
last = p1;
}
如 rcgldr 所建议,使用自下而上的合并排序来避免重复扫描列表可能更有效。这是备用代码:
/* bottom-up merge sort with sublist array */
struct student *msort(struct student *head) {
struct student *array[32] = { NULL };
int i;
/* handle trivial lists */
if (head == NULL || head->next == NULL)
return head;
i = 0; /* avoid warning */
p1 = head;
/* merge nodes into pending lists of increasing lengths */
while (head != NULL) {
struct student *next = head->next;
head->next = NULL;
for (i = 0; i < 32 && array[i] != NULL; i++) {
head = merge(array[i], head);
array[i] = NULL;
}
/* do not go past end of array */
if (i == 32)
i--;
array[i] = head;
head = next;
}
/* merge pending lists into single list:
* the last element stored into the array is at offset i and
* all entries before it are NULL pointers. */
for (head = array[i++]; i < 32; i++) {
if (array[i] != NULL)
head = merge(array[i], head);
}
return head;
}