C中带指针的合并函数

C中带指针的合并函数,c,mergesort,C,Mergesort,我被指派创建一个函数,该函数合并2个排序越来越高的列表,而不创建额外的列表,只使用指针。如果有人能给我一个提示或一个理由,说明我的代码为什么没有做到这一点,那将是非常好的:( node\t*merge(node\t*l1,node\t*l2){ 节点_t*i; 节点虚拟; i=&dummy; 如果(l1->valuevalue){ dummy.next=l1; l1=l1->next; }否则{ dummy.next=l2; l2=l2->next; } while(i->next!=NULL)

我被指派创建一个函数,该函数合并2个排序越来越高的列表,而不创建额外的列表,只使用指针。如果有人能给我一个提示或一个理由,说明我的代码为什么没有做到这一点,那将是非常好的:(

node\t*merge(node\t*l1,node\t*l2){
节点_t*i;
节点虚拟;
i=&dummy;
如果(l1->valuevalue){
dummy.next=l1;
l1=l1->next;
}否则{
dummy.next=l2;
l2=l2->next;
}
while(i->next!=NULL){
如果(l1->valuevalue&&l1->next!=NULL){
i->next=l1;
l1=l1->next;
}
如果(l1->value>=l2->value&&l2->next!=NULL){
i->next=l2;
l2=l2->next;
}
}
返回dummy.next;
}
不要使用虚拟节点,您拥有所有必要的节点…只需更改链接

首先确定哪个列表包含较低的元素:

node *finalList;
if (l1->value<l2->value) {
    finalList = l1;
    l1 = l1->next;
} else {
    finalList = l1;
    l1 = l1->next;
}
现在在列表上循环:

while(true) {
    if (l1->value<l2->value) {
        current->next = l1;
        current = current->next; // one more in the final list from l1
        l1 = l1->next;           // move in l1
        if (l1==NULL) {          // l1 empty, everything remains in l2
            current = l2;
            break;
        }
    } else {
        current->next = l2;
        current = current->next;
        l2 = l2->next;
        if (l2==NULL) {
            current = l1;
            break;
        }
    }
}
while(true){
如果(l1->valuevalue){
当前->下一步=l1;
current=current->next;//在l1的最终列表中还有一个
l1=l1->next;//移入l1
如果(l1==NULL){//l1为空,则所有内容都保留在l2中
电流=l2;
打破
}
}否则{
当前->下一步=l2;
当前=当前->下一步;
l2=l2->next;
if(l2==NULL){
电流=l1;
打破
}
}
}

您只需在开始时处理空列表…

您的函数有一些问题:

  • 如果任一参数列表为空,则它将具有未定义的行为
  • 对列表末尾的测试是不正确的:一旦包含较低元素的子列表减少为单个元素,循环将永远运行而不产生任何影响
使用虚拟节点简化代码不是问题,以下是如何修复函数:

node\t*merge(node\t*l1,node\t*l2){
节点虚拟;
节点_t*i=&dummy;
对于(;;){
if(l1==NULL){
//列表1:列表2其余部分中的链接
i->next=l2;
打破
}
if(l2==NULL){
//列表2:列表1其余部分中的链接
i->next=l1;
打破
}
如果(l1->value){
//列表1元素位于前面:链接它并跳到下一个
i=i->next=l1;
l1=l1->next;
}否则{
//列表2元素位于前面:链接它并跳到下一个
i=i->next=l2;
l2=l2->next;
}
}
//返回组合列表头
返回dummy.next;
}
更典型的C实现将使用指向列表链接的指针:

node\t*merge(node\t*l1,node\t*l2){
节点头;
节点**pp=&head;
对于(;;){
if(l1==NULL){
//列表1:列表2其余部分中的链接
*pp=l2;
打破
}
if(l2==NULL){
//列表2:列表1其余部分中的链接
*pp=l1;
打破
}
如果(l1->value){
//列表1元素位于前面:链接它并跳到下一个
*pp=l1;
pp=&l1->next;
l1=l1->next;
}否则{
//列表2元素位于前面:链接它并跳到下一个
*pp=l2;
pp=&l2->next;
l2=l2->next;
}
}
//返回组合列表头
回流头;
}
这里有一个简单得多的函数,可以在没有伪节点或双指针的情况下合并列表。但是请注意,此递归函数不使用尾部递归:它将使用与参数列表的组合长度成比例的堆栈空间进行多次递归,可能会导致堆栈溢出

node\t*merge(node\t*l1,node\t*l2){
if(l1==NULL)
返回l2;
if(l2==NULL)
返回l1;
如果(l1->value){
l1->next=合并(l1->next,l2);
返回l1;
}否则{
l2->next=合并(l1,l2->next);
返回l2;
}
}

您知道您正在销毁现有列表吗?在您的while循环中,即使第一个if被执行,第二个if也会被执行。这不应该是一个
else if
?您的while循环即使在其中一个列表尚未用尽时也会终止。最好的方法是:使用调试器并逐步完成代码。您可以从初始化开始g dummy..下一个指针可能是某个任意地址
node *current = finalList;
while(true) {
    if (l1->value<l2->value) {
        current->next = l1;
        current = current->next; // one more in the final list from l1
        l1 = l1->next;           // move in l1
        if (l1==NULL) {          // l1 empty, everything remains in l2
            current = l2;
            break;
        }
    } else {
        current->next = l2;
        current = current->next;
        l2 = l2->next;
        if (l2==NULL) {
            current = l1;
            break;
        }
    }
}