我创建了一个包含5个类型节点的链接列表:
typedef struct node
{
int i;
struct node* link;
}node;
node* head = NULL;
打印出来时,会显示:
4 3 2 1 0
头指针设置为指向4.然后我编写了一个函数来对链表进行冒泡排序,如下所示:
void sort(void)
{
node* cur = head;
node* next = cur->link;
node* prev = NULL;
while(cur->i > next->i)
{
printf("cur is greater than next\n");
while(prev != head)
{
cur->link = next->link;
next->link = cur;
head = next;
next = cur->link;
prev = head;
}
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
printf("second while loop exited\n");
for (node* ptr = head; ptr != NULL; ptr = ptr->link)
{
printf("%d", ptr->i);
}
cur = head;
next = cur->link;
}
}
有各种printf语句来检查程序是否正常工作。我发现在第一次运行之后,4成功地冒泡了如下:
3 2 1 0 4
但是,在将cur指针重新设置为3并且将2重新设置为2之后,下一个直播指针会提供以下内容:
2 1 0 4 3
最终,我们以
结束0 4 3 2 1
可以看出" 3"," 2"和" 1"正在冒泡太多。我已经尝试了各种conditonals代替第三个while循环来纠正这个问题,但在大多数情况下这会导致seg错误。当然,另一件事是我的逻辑完全错误,可能有更好的方法来实现它。你能不能仅仅交换节点的内容而不是指针本身?任何帮助将非常感激。提前致谢
答案 0 :(得分:1)
我会看第三个while
while(next != NULL)
{
prev->link = next;
cur->link = next->link;
next->link = cur;
prev = next;
next = cur->link;
}
在这里,您始终在不测试是否必须移动元素的情况下移动元素 - 即cur->i > next->i
。
顺便说一句,如果它的后卫是真的,那么第二个while
只执行一次,因此它与if
相同,所以我会使用{ {1}},至少为了清楚起见。
答案 1 :(得分:1)
用于排序数组的普通冒泡排序实现使用直接寻址和数组的已知大小:它们自然地使用索引,即项的序数,因此它们可以轻松缩小按工作进度排序的区域,因为他们知道有多少物品已经在最后的位置。
链接列表纯粹按顺序处理,因此它不允许这样的简单优化,而不会添加人工索引,并沿列表迭代递增。这就是为什么最简单的迭代总是在整个列表中进行迭代并在没有交换任何项目时终止,因此列表被排序:
void sort(void)
{
int swapped = 1;
while(swapped)
{
node **prev = &head, *curr, *next;
swapped = 0;
for(curr = head; curr; prev = & curr->link, curr = curr->link)
{
next = curr->link;
if(next && curr->i > next->i)
{
curr->link = next->link;
next->link = curr;
*prev = next;
swapped = 1;
}
}
}
}
编辑 - 一些解释回复Matthew2015评论中的问题。
C中的逻辑条件期望数字或指针表达式被认为是真正的'如果它们分别与零不同或不同于NULL。这意味着while(swapped)
基本上等同于while(swapped != 0)
,而next && ...
相当于next != NULL && ...
。 while(swapped != 0)
中的条件表示当内部for
的某些执行未将swapped
设置为1
时,循环将终止,这在列表中的任何项目都不大于其时发生后继 - 即列表排序时。
for
循环条件表达式仅为curr
,相当于curr != NULL
。这使得for
循环沿列表重复,直到没有当前的'节点
node **prev
变量指向指针,指针指向当前节点。当''当前'并且' next'节点需要交换,然后是先前的'链接不应再指向“当前'节点,但到了下一个'节点而不是。当然,可以将指针保持在前一个节点上。并为(previous node)->link
分配一个新值 - 但如果列表中的第一个节点没有“前一个节点”,则该值不起作用。但head
变量指出了这一点。必须使用附加条件来验证当前节点是否是解决此不一致的第一个节点。指向指针的指针(最初指向head
然后指向'previous node'.link
)使整个代码更简单,更短,也更快。