【问题标题】:Problem splitting a linked list into two other linked lists in c在c中将链表拆分为其他两个链表的问题
【发布时间】:2021-11-09 22:53:27
【问题描述】:

我的代码应该在一个链表中存储 10 个 int 数字,将这 10 个数字平均分成两个其他链表。但是我的两个列表都返回空

我的结构:

typedef struct no
{
    int value;
    struct no *next;
} no;

变量大小来自一个循环遍历我的主列表并返回其大小的函数。 然后创建了两个“几乎相等”的函数来从主列表中获取值并将其存储在 ListB 和 ListC 中。

我的功能:

no* copylist(no *list, no *listReceive,int size)
{
    no *aux = list;
    no *receive=listReceive;

    int count=0;


    while(aux!=NULL&&count<size/2)
    {
        insert(receive, aux->value);

        aux=aux->next;
    }
    count = size/2;


    return receive;
}
no* copylist1(no *list, no *listReceive,int size)
{
    no *aux = list;
    no *receive=listReceive;

    int count=0;

    while(aux!=NULL&&count<size/2)
    {
        aux=aux->next;
        count++;
    }

    count = size/2;
    aux=aux->next;

    while(aux!=NULL&&count<size)
    {
        insert(receive, aux->value);

        aux=aux->next;
    }


    return receive;
}

Obs:对我来说链表是一个非常混乱的内容

【问题讨论】:

  • 您的insert 调用没有任何意义——您似乎对参数传递感到困惑。在 C 函数中,参数总是按值传递,因此函数具有调用者值的一个副本。函数中参数的更改不会影响调用者中的变量,除非您使用&amp; 显式传递地址
  • [不提供任何解决方案,但是...]您的方法似乎是创建另一个列表(包含原始列表的一半)-我认为这个过程很慢,使用两个指针(一个指向node-&gt;next,另一个指向node-&gt;next-&gt;next,即双倍速度)找到列表的中间位置,然后重新分配head - 这样您就不需要复制整个列表。跨度>
  • 如果您格式化代码以提高可读性,您将帮助自己和他人,例如而不是while(aux!=NULL&amp;&amp;count&lt;size)while (aux != NULL &amp;&amp; count &lt; size)

标签: c linked-list


【解决方案1】:

如果我们使用两个指针,则可以在单个遍中完成拆分。一个通过cur1 = cur1-&gt;next 遍历,另一个以两倍的速度遍历(例如cur2 = cur2-&gt;next-&gt;next);

cur2 到达终点时,cur1 将位于中点。

当我们将作为列表开始的“单星”指针传递给必须调整并返回列表头部的函数时,调整将不会反映回来电者

除了节点 struct 之外,使用单独的列表 struct 更容易/更好,而不是为此列表传递“双星”指针。

请注意,我们可以共同选择/重用 [dummy] 节点作为列表指针,但如果我们使用单独的结构会更清楚。

下面是一些带注释的代码。不幸的是,我不得不对其进行大量重构才能使其正常工作。


这是一个[取决于程序参数]的版本:

  1. 一个简单的两个版本。一次计算计数,第二次根据该计数进行拆分
  2. 一个改进的版本,通过使用上面提到的“双指针”技术在 单个 传递中进行拆分
#include <stdio.h>
#include <stdlib.h>

int passno;

// node
typedef struct no {
    int value;
    struct no *next;
} no;

// list
typedef struct li {
    no *head;
} li;

// show -- show a list
void
show(li *lst,const char *sym)
{

    printf("%s:",sym);

    for (no *cur = lst->head;  cur != NULL;  cur = cur->next)
        printf(" %2d",cur->value);

    printf("\n");
}

// newlist -- create a new list with N elements
li *
newlist(int count)
{
    li *lst = malloc(sizeof(*lst));
    no *cur;
    no *prev;

    lst->head = NULL;

    prev = NULL;
    for (int idx = 0;  idx < count;  ++idx) {
        cur = malloc(sizeof(*cur));
        cur->next = NULL;

        cur->value = idx + 1;

        if (prev != NULL)
            prev->next = cur;
        else
            lst->head = cur;

        prev = cur;
    }

    return lst;
}

// lstcount -- count number of elements in the list
int
lstcount(li *lst)
{
    no *cur;
    int count = 0;

    for (cur = lst->head;  cur != NULL;  cur = cur->next)
        ++count;

    return count;
}

// splitA -- split a list into two halves (single pointer, two pass version)
void
splitA(li *lstleft,li *lstright,li *lstfrom)
{
    int count;
    int idx;
    no *cur;
    no *left;

    count = lstcount(lstfrom);
    count = (count + 1) / 2;

    left = NULL;
    lstleft->head = NULL;

    idx = 0;
    for (cur = lstfrom->head;  cur != NULL;  cur = cur->next) {
        if (++idx > count)
            break;

        // append to left list
        if (left == NULL)
            lstleft->head = cur;

        left = cur;
    }

    // disconnect/cut the tail of the left list from the right list
    if (left != NULL)
        left->next = NULL;

    // start the right list
    lstright->head = cur;

    // zap the original list
    lstfrom->head = NULL;
}

// splitB -- split a list into two halves (two pointer, one pass version)
void
splitB(li *lstleft,li *lstright,li *lstfrom)
{
    no *cur1;
    no *cur2;
    no *left;

    left = NULL;
    lstleft->head = NULL;

    cur2 = lstfrom->head;
    for (cur1 = lstfrom->head;  cur1 != NULL;  cur1 = cur1->next) {
        // wait for double speed pointer to end
        if (cur2 == NULL)
            break;
        cur2 = cur2->next;

        // append to left list
        if (left == NULL)
            lstleft->head = cur1;
        left = cur1;

        // advance at twice the rate
        if (cur2 != NULL)
            cur2 = cur2->next;
    }

    // disconnect/cut the tail of the left list from the right list
    if (left != NULL)
        left->next = NULL;

    // start the right list
    lstright->head = cur1;

    // zap the original list
    lstfrom->head = NULL;
}

// clean -- free up list elements and list descriptor
void
clean(li *lst)
{
    no *cur;
    no *next;

    for (cur = lst->head;  cur != NULL;  cur = next) {
        next = cur->next;
        free(cur);
    }

    free(lst);
}

// dotest -- test the split for a given number of nodes
void
dotest(int count)
{
    li *big;
    li *left;
    li *right;

    printf("\n");
    printf("dotest: count=%d\n",count);

    big = newlist(count);
    show(big,"big");

    left = newlist(0);
    right = newlist(0);

    switch (passno) {
    case 1:
        splitA(left,right,big);
        break;
    case 2:
        splitB(left,right,big);
        break;
    }

    show(left,"lhs");
    show(right,"rhs");

    clean(left);
    clean(right);
    clean(big);
}

int
main(int argc,char **argv)
{

    --argc;
    ++argv;

    if (argc > 0)
        passno = atoi(*argv);
    if (passno <= 0)
        passno = 1;
    if (passno > 2)
        passno = 2;
    printf("passno=%d\n",passno);

    for (int count = 0;  count <= 12;  ++count)
        dotest(count);
}

这是程序输出:

passno=1

dotest: count=0
big:
lhs:
rhs:

dotest: count=1
big:  1
lhs:  1
rhs:

dotest: count=2
big:  1  2
lhs:  1
rhs:  2

dotest: count=3
big:  1  2  3
lhs:  1  2
rhs:  3

dotest: count=4
big:  1  2  3  4
lhs:  1  2
rhs:  3  4

dotest: count=5
big:  1  2  3  4  5
lhs:  1  2  3
rhs:  4  5

dotest: count=6
big:  1  2  3  4  5  6
lhs:  1  2  3
rhs:  4  5  6

dotest: count=7
big:  1  2  3  4  5  6  7
lhs:  1  2  3  4
rhs:  5  6  7

dotest: count=8
big:  1  2  3  4  5  6  7  8
lhs:  1  2  3  4
rhs:  5  6  7  8

dotest: count=9
big:  1  2  3  4  5  6  7  8  9
lhs:  1  2  3  4  5
rhs:  6  7  8  9

dotest: count=10
big:  1  2  3  4  5  6  7  8  9 10
lhs:  1  2  3  4  5
rhs:  6  7  8  9 10

dotest: count=11
big:  1  2  3  4  5  6  7  8  9 10 11
lhs:  1  2  3  4  5  6
rhs:  7  8  9 10 11

dotest: count=12
big:  1  2  3  4  5  6  7  8  9 10 11 12
lhs:  1  2  3  4  5  6
rhs:  7  8  9 10 11 12

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多