Rachel,从 cmets 继续,因为您似乎试图在 linked-list 中“交换指针”,所以您不能简单地交换列表中的相邻指针而不破坏节点(例如,node->next 指针将不再指向列表中的 next 节点)。考虑以下几点:
+------+ +------+ +------+
| a | +-->| b | +-->| c | +--> ...
+------+ | +------+ | +------+ |
| next |--+ | next |--+ | next |--+
+------+ +------+ +------+
在哪里
a->next = b;
b->next = c;
c->next ...
如果你只是交换a和b指针,a->next和b-next指向哪里?例如
+------+ +------+ +------+
| b | +-->| a | +-->| c | +--> ...
+------+ | +------+ | +------+ |
| next |--+ | next |--+ | next |--+
+------+ +------+ +------+
由于您没有交换(或重新连接)next 指针,它们仍然保存(指向)原始内存位置,例如a->next = b; 和 b->next = c; (这是不对的,你会完全跳过'a',如果你确实点击了a,a->next 会备份到b,然后b->next 会跳到c .. .)
所以如果你想按一些成员值排序而不是交换值,而是交换指针,你必须“re-wire”每个next指针指向与下一个节点以正确的排序顺序升序(或降序)成员值,这不同于简单地交换 a、b、c 指针值。
接下来,您必须考虑两种不同的情况。重新连接 first 节点,从而更改列表本身的地址(例如 head 指针),然后是所有其他节点的一般情况(对于 单链接-list、循环列表和双向链表需要额外注意prev 和last->first 链接)。您需要可视化和考虑的两种情况是涉及第一个节点的交换:
head next next->next
(iter) (iter->next) (iter->next->next)
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->+
+------------+ +------------+ +------------+
和你的一般情况:
prev current next
(last) iter (iter->next)
+------------+ +------------+ +------------+
| Payload | | Payload | | Payload |
+------------+ +------------+ +------------+
| Next |------->| Next |------->| Next |--->+
+------------+ +------------+ +------------+
对于涉及head 节点的情况(并使用struct node *iter = *head; 并选择tmp = iter->next; 进行替换,您可以执行以下操作:
if (iter == *head) {
struct node *tmp = iter->next;
iter->next = tmp->next;
tmp->next = iter;
*head = tmp;
iter = *head;
}
要处理一般情况(在以下else 子句中,您可以执行以下操作:
else {
struct node *tmp = iter->next;
iter->next = tmp->next;
tmp->next = last->next;
last->next = tmp;
iter = tmp;
}
swapped = 1;
您将在您的代码中完全不使用 swap 函数(您可以,但您需要传递列表地址,以便与 head 进行比较。
在一个简短的示例中将所有部分放在一起,并按每个节点内的整数值升序排序,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXN 10
typedef struct node {
int val;
struct node *next;
} node;
int cmp (struct node *a, struct node *b) {
/* (a > b) - (a < b) */
return (a->val > b->val) - (a->val < b->val);
}
void sort (struct node **recordsHead,
int (*compare_fcn)(struct node*, struct node*));
int main (void) {
srand (time (NULL));
node *head = NULL;
for (int i = 0; i < MAXN; i++)
{
node *newnode = malloc (sizeof *newnode);
if (!newnode) { /* allocate node and validate memory */
fprintf (stderr, "error: memory exhausted node '%d'.\n", i);
break;
}
newnode->val = rand() % 100; /* initialize pointers */
newnode->next = NULL;
if (!head) /* new list, assign to head */
head = newnode;
else { /* otherwise iterate and add to end */
node *iter = head;
for (; iter->next; iter = iter->next) {}
iter->next = newnode;
}
}
int j = 0; /* output list (including pointer addresses) */
printf ("\noriginal pointer and value order:\n\n");
for (node *iter = head; iter; iter = iter->next)
printf ("node[%3d] : %3d, addr: %p, next: %p\n",
j++, iter->val, (void*)iter, (void*)iter->next);
sort (&head, cmp); /* sort by swapping pointers */
j = 0; /* output sorted list (with addresses */
printf ("\nsorted pointer and value order:\n\n");
for (node *iter = head; iter; iter = iter->next)
printf ("node[%3d] : %3d, addr: %p, next: %p\n",
j++, iter->val, (void*)iter, (void*)iter->next);
/* free list memory */
node *victim = NULL; /* node to delete */
for (node *iter = head; iter; iter = iter->next) {
if (victim) /* cannot delete until after loop increment */
free (victim);
victim = iter; /* so save node as victim, delete next iteration */
}
if (victim) /* free last node */
free (victim);
return 0;
}
/* sort (ascending) by rewiring nodes */
void sort (struct node **head, int (*compare_fcn)(struct node*, struct node*))
{
struct node *iter, *last = NULL;
int swapped;
do { /* while a swap occurs during iterating list */
swapped = 0;
iter = *head;
while (iter->next != NULL) /* traverse each node in list */
{
if (compare_fcn (iter, iter->next) > 0) /* sort ascending */
{
if (iter == *head) { /* swap head pointers (rewire) */
struct node *tmp = iter->next;
iter->next = tmp->next;
tmp->next = iter;
*head = tmp;
iter = *head;
}
else { /* swap of remaining nondes (rewire pointers) */
struct node *tmp = iter->next;
iter->next = tmp->next;
tmp->next = last->next;
last->next = tmp;
iter = tmp;
}
swapped = 1; /* swap flag */
}
last = iter; /* update last */
iter = iter->next; /* advance ptr */
}
} while (swapped);
}
使用/输出示例
$ ./bin/llminsort
original pointer and value order:
node[ 0] : 63, addr: 0x9fb010, next: 0x9fb030
node[ 1] : 76, addr: 0x9fb030, next: 0x9fb050
node[ 2] : 4, addr: 0x9fb050, next: 0x9fb070
node[ 3] : 95, addr: 0x9fb070, next: 0x9fb090
node[ 4] : 76, addr: 0x9fb090, next: 0x9fb0b0
node[ 5] : 64, addr: 0x9fb0b0, next: 0x9fb0d0
node[ 6] : 81, addr: 0x9fb0d0, next: 0x9fb0f0
node[ 7] : 43, addr: 0x9fb0f0, next: 0x9fb110
node[ 8] : 51, addr: 0x9fb110, next: 0x9fb130
node[ 9] : 68, addr: 0x9fb130, next: (nil)
sorted pointer and value order:
node[ 0] : 4, addr: 0x9fb050, next: 0x9fb0f0
node[ 1] : 43, addr: 0x9fb0f0, next: 0x9fb110
node[ 2] : 51, addr: 0x9fb110, next: 0x9fb010
node[ 3] : 63, addr: 0x9fb010, next: 0x9fb0b0
node[ 4] : 64, addr: 0x9fb0b0, next: 0x9fb130
node[ 5] : 68, addr: 0x9fb130, next: 0x9fb030
node[ 6] : 76, addr: 0x9fb030, next: 0x9fb090
node[ 7] : 76, addr: 0x9fb090, next: 0x9fb0d0
node[ 8] : 81, addr: 0x9fb0d0, next: 0x9fb070
node[ 9] : 95, addr: 0x9fb070, next: (nil)
内存泄漏/错误检查
您必须使用内存错误检查程序来确保您不会尝试写入超出/超出分配的内存块的范围,尝试读取或基于未初始化的值进行条件跳转,最后,确认您释放了所有已分配的内存。
对于 Linux,valgrind 是正常的选择。每个平台都有类似的内存检查器。它们都易于使用,只需通过它运行您的程序即可。
$ valgrind ./bin/llminsort
==1844== Memcheck, a memory error detector
==1844== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1844== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==1844== Command: ./bin/llminsort
==1844==
original pointer and value order:
node[ 0] : 27, addr: 0x51d8040, next: 0x51d8090
node[ 1] : 68, addr: 0x51d8090, next: 0x51d80e0
node[ 2] : 55, addr: 0x51d80e0, next: 0x51d8130
node[ 3] : 44, addr: 0x51d8130, next: 0x51d8180
node[ 4] : 47, addr: 0x51d8180, next: 0x51d81d0
node[ 5] : 10, addr: 0x51d81d0, next: 0x51d8220
node[ 6] : 8, addr: 0x51d8220, next: 0x51d8270
node[ 7] : 13, addr: 0x51d8270, next: 0x51d82c0
node[ 8] : 73, addr: 0x51d82c0, next: 0x51d8310
node[ 9] : 11, addr: 0x51d8310, next: (nil)
sorted pointer and value order:
node[ 0] : 8, addr: 0x51d8220, next: 0x51d81d0
node[ 1] : 10, addr: 0x51d81d0, next: 0x51d8310
node[ 2] : 11, addr: 0x51d8310, next: 0x51d8270
node[ 3] : 13, addr: 0x51d8270, next: 0x51d8040
node[ 4] : 27, addr: 0x51d8040, next: 0x51d8130
node[ 5] : 44, addr: 0x51d8130, next: 0x51d8180
node[ 6] : 47, addr: 0x51d8180, next: 0x51d80e0
node[ 7] : 55, addr: 0x51d80e0, next: 0x51d8090
node[ 8] : 68, addr: 0x51d8090, next: 0x51d82c0
node[ 9] : 73, addr: 0x51d82c0, next: (nil)
==1844==
==1844== HEAP SUMMARY:
==1844== in use at exit: 0 bytes in 0 blocks
==1844== total heap usage: 10 allocs, 10 frees, 160 bytes allocated
==1844==
==1844== All heap blocks were freed -- no leaks are possible
==1844==
==1844== For counts of detected and suppressed errors, rerun with: -v
==1844== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认您已释放已分配的所有内存并且没有内存错误。
查看一下,如果您有任何其他问题,请告诉我。