【问题标题】:Split linked list in CC中的拆分链表
【发布时间】:2020-05-13 04:36:27
【问题描述】:

我需要使用链表实现一些分而治之的算法(二分查找、归并排序等)。
为此,我需要定义一个方法,将某个列表一分为二,使它们之间的大小差异最大为 1 个元素。
这是我的结构:

typedef struct linked_list *L;
typedef struct linked_list{
    int info;
    L next;
};

L 是指向linked_list 的指针。

下面的代码是我尝试将给定列表分成前后两半的算法。
我想不出返回两个生成列表的方法,所以我将两个空列表作为参数传递。

void split_list(L r, L front, L back){
    L a = r->next;
    L b = r;

    while( a ){
        a = a->next; 
        if ( a->next ){
            a = a->next;
            b = b->next;
        }
    }

    back = b->next;
    front = r;
    b->next = NULL;

}

但是,当您在 main 上运行该函数时,它无法按预期工作。

L z = NULL;
/ insert some nodes in z /

L x = NULL;
L y = NULL;

split_list(z, x, y);

尝试打印xy,它们是空的(显然)。
我认为问题在于列表作为参数传递的方式,但我不知道如何解决这个问题。

【问题讨论】:

    标签: c linked-list structured-data


    【解决方案1】:

    你有一个经典的 C 误解。

    您试图通过将x 传递给函数来更改main 中的x,然后更改函数中的相应变量。你不能那样做!

    不起作用的方法的简化示例

    void foo(int x)
    {
        x = 55;
    }
    
    int globalInt = 42;
    
    void bar(int* p)
    {
        p = &globalInt;
    }
    
    void main(void)
    {
        int x = 0;
        foo(x);
        printf("%d\n", x);  // Will print 0
    
        int* p = NULL;
        bar(p);
        printf("%p\n", (void*)p); // Will print NULL (nil)
    
        return 0;
    }
    

    原因是 C 通过值(而不是通过引用)传递变量。因此,当您将x 传递给函数时,您实际上传递了值0,并且函数知道值0 来自名为x 的变量。

    因此,在您的情况下,main 中的 xy 在函数调用后仍将为 NULL。

    要更改main 中的变量,您需要传递变量的地址

    void foo(int* x)  // Notice the extra *
    {
        *x = 55;      // Notice the extra *
    }
    
    int globalInt = 42;
    
    void bar(int** p)      // Notice the extra *
    {
        *p = &globalInt;   // Notice the extra *
    }
    
    void main(void)
    {
        int x = 0;
        foo(&x);            // Notice the & operator
        printf("%d\n", x);  // Will print 55
    
        int* p = NULL;
        bar(&p);                  // Notice the & operator
        printf("%p\n", (void*)p); // Will print address of the global variable
    
        return 0;
    }
    

    一般规则

    如果你看到像这样的 C 代码:

    TYPE x = SomeValue;
    func(x);
    

    您肯定知道x 在函数调用之后 也将具有值SomeValue

    关于您的代码

    所以在你的情况下你需要:

    void split_list(L r, L* front, L* back)
    

    但是,由于您将 front 分配给 r,因此在函数中更改它似乎有点过头了,您可以简单地这样做:

    L split_list(L r) {...}
    

    然后这样称呼它:

    L back = split_list(head);
    // Now head contains first half and back contains second half
    

    顺便说一句:

    这是基于意见的,但指针的 typedef 通常不是一个好主意。

    【讨论】:

    • 很好的解释,谢谢。我去搜索一下指针的typedef。
    • 另一个问题:如何保持原始列表不变?
    • 对于指针的typedef,您可以从这里开始stackoverflow.com/questions/33188589/typedef-with-pointer-in-c 并点击一些链接
    • 如果你想保持原始列表不变,你需要一个完全不同的程序,它需要复制所有节点。
    • 是的,我想过那样做,但我想知道我是否可以稍微改变一下我的算法来做到这一点。再次感谢您。
    猜你喜欢
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多