好的,我想交换两个节点的 POSITION (不是值)。
我的程序运行时出现任何错误或警告,但我不确定是否交换位置或值
这是我的排序功能:
void sort(struct node **recordsHead,int (*compare_fcn)(struct node*, struct node*))
{
void swap(struct node**, struct node**);
struct node *tmp,*lastPtr = NULL;
int swapped;
do {
swapped = 0;
tmp = *recordsHead;
while (tmp->next_ != lastPtr)
{
if (compare_fcn(tmp, tmp->next_))
{
swap(&tmp, &(tmp->next_));
swapped = 1;
}
tmp = tmp->next_;
}
lastPtr = tmp;
} while (swapped);
}
这是我的交换功能
void swap(struct node** node1, struct node** node2)
{
student_record *tmp;
tmp = (*node1)->record_;
(*node1)->record_ = (*node2)->record_;
(*node2)->record_ = tmp;
}
谢谢。
答案 0 :(得分:0)
Rachel,继续发表评论,因为你似乎试图在链接列表中'交换指针',你不能简单地交换列表中的相邻指针而不破坏之间的联系。节点(例如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
...)
因此,如果您希望按某些成员值排序而不是交换值,而是交换指针,则必须“重新连接”每个next
指针以指向具有该节点的节点正确排序顺序中的下一个升序(或降序)成员值,与简单地交换a
,b
,c
指针值不同。
接下来,您必须考虑两个不同的案例。重新连接第一个节点,从而更改列表本身的地址(例如head
指针),然后是所有其他节点的一般情况(单个) -linked-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)
始终确认已释放已分配的所有内存并且没有内存错误。
仔细看看,如果您有任何其他问题,请告诉我。