【问题标题】:Printing random numbers to list打印随机数到列表
【发布时间】:2021-09-08 13:58:31
【问题描述】:

我的任务是生成 50 到 80 范围内的随机数,如果生成的数字是偶数,则将其添加到偶数列表中,如果是奇数,则将其添加到奇数列表中。程序应该一直运行到两个列表都填满 10 个数字。列表中不允许重复。此代码打印 20 个不同的数字,并将重复项存储在列表中。所以我认为问题出在 count_odd、count_even 和检查重复项上,但我找不到解决方案。我还必须打印所有生成的数字以及最后的两个列表。链表中的数字应按降序排列

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>

typedef struct list numbers;
typedef struct list* Pos;

int PrintRandom();
Pos CreateNew();
int PrintList(Pos);

struct list {
    int number;
    Pos next;
};

int PrintList(Pos P) {
    if (P == NULL)
        printf("Empty list.\n");
    while (P != NULL) {
        printf("%d\n", P->number);
        P = P->next;
    }
    return 0;
}

Pos CreateNew() {
    Pos q = NULL;
    q = (Pos)malloc(sizeof(struct list));
    if (q == NULL) return NULL;
    q->next = NULL;
    return q;
}

int PrintRandom() {
    int x = 0, max = 80, min = 50;
    x = (rand() % (max - min + 1) + min);
    printf("Random number is : %d\n", x);
    
    return x;
}

int main() {
    srand(time(0));
    Pos even, odd, q = NULL;
    even = malloc(sizeof(numbers));
    odd = malloc(sizeof(numbers));
    even->next = odd->next = NULL;
    int count_even = 0, count_odd = 0, j;
    Pos head_p =even, head_n=odd;

    while (count_even < 10 & count_odd < 10) {
        j = PrintRandom();
        if (j % 2 == 0) {
            q = CreateNew();
            if (q == NULL) return -1;
            q->number = j;
            while (even->next != NULL && even->next->number > q->number) {
                even = even->next;
            }
            if (even->number== q->number)
                free(q);
            else
                q->next = even->next;
            even->next = q;
            even =head_p;
            count_even++;
        }
        else {
            q = CreateNew();
            if (q == NULL) return -1;
            q->number = j;
            while (odd->next != NULL && odd->next->number > q->number) {
                odd = odd->next;
            }
            if (odd->number == q->number)
                free(q);
            else
                q->next = odd->next;
            odd->next = q;
            odd = head_n;
            count_odd++;
        }
    }

    printf("Even numbers in list are:\n");
    PrintList(head_p->next);
    printf("Odd numbers in list are:n");
    PrintList(head_n->next);

    return 0;
}

【问题讨论】:

  • 在你的问题中,你写的是:"Program should run till both lists are filled with 10 numbers." 这句话不清楚。如果奇数列包含10个数字,偶数列包含9个数字,然后又生成一个奇数,应该怎么办?将其添加到奇数列表中,使其包含 11 个数字?还是应该丢弃该数字?
  • 如果奇数列表包含 10 个数字,偶数列表包含 9 个数字,然后生成另一个奇数,则应该跳过它,因为奇数列表“已满”
  • 这是错误的:while (count_even &lt; 10 &amp; count_odd &lt; 10) { &amp; 运算符是按位与运算符,但您需要逻辑与运算符,即&amp;&amp;
  • 从一个预设值为 50 到 80 的数组开始。随机选择一个 index,将其替换为最上面的元素,并减少元素数。
  • 有这么多选择,我认为Fisher-Yates shuffle 将是一个有效的算法。

标签: c list random duplicates


【解决方案1】:

您的代码有几个错误:


第一个错误:

循环

while (count_even &lt; 10 &amp; count_odd &lt; 10) {

将在count_evencount_odd 到达10 时立即停止。但是,在您的问题中,您表示只有在两者都达到10 时才应该停止循环。

因此,您应该将该行更改为以下内容:

while ( count_even &lt; 10 || count_odd &lt; 10 ) {

另外,值得指出的是&amp; 是按位与运算符。您可能打算使用逻辑与运算符,即&amp;&amp;


第二个错误:

在 cmets 部分中,您声明如果其中一个列表已满(有 10 个元素),则应丢弃属于该列表的所有其他数字。但是,您的程序不包含任何代码来检查这一点。相反,您的程序将继续向列表中添加新元素,即使它已经有 10 个元素。


第三个错误:

以下代码错误:

if (even->number== q->number)
    free(q);
else
    q->next = even->next;
even->next = q;
even =head_p;
count_even++;

首先,你应该改变表达方式

even-&gt;number== q-&gt;number

到:

even-&gt;next-&gt;number== q-&gt;number

但是,由于even-&gt;next 可能为空,因此您必须事先对其进行测试,以便整行看起来像这样:

if ( even-&gt;next != NULL &amp;&amp; even-&gt;next-&gt;number== q-&gt;number)

还有线条

even-&gt;next = q;

count_even++;

如果数字已经存在,则不应执行。因此,您应该将这些行移到else 块内。执行这些更改后,您的代码应如下所示:

if ( even->next != NULL && even->next->number== q->number)
{
    free(q);
}
else
{
    q->next = even->next;
    even->next = q;
    count_even++;
}
even =head_p;

应该在奇数的代码分支上执行相同的更改。


第四个错误:

以下行中缺少反斜杠字符:

printf("Odd numbers in list are:n");

你应该把它改成:

printf("Odd numbers in list are:\n");


补充说明:

我认为您的代码中还有两点可以改进:

  • 链表的第一个元素只是一个虚拟节点,其中number 字段未初始化。您似乎只是将这个节点用于将头指针指向实际的链表。

  • 你有很多代码重复。您不必使用相同的代码来处理偶数和奇数,而是使用单独但非常相似的代码来处理每种情况。

在下面的代码中,我已经重写了您的大部分代码,以向您展示我将如何解决这个问题。如果您发现它难以理解,请不要感到惊讶,因为我使用的是指向指针的指针,这对于初学者来说可能很难理解。如您所见,我没有使用任何虚拟节点,并且我也使用相同的代码来处理偶数和奇数。只有在我的代码的两个地方我有不同的代码来处理偶数和奇数。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>

struct list_node
{
    int number;
    struct list_node *next;
};

int PrintRandom();
int PrintList( struct list_node * );

int PrintList( struct list_node *p)
{
    if ( p == NULL )
    {
        printf( "Empty list.\n" );
    }
    else
    {
        while ( p != NULL )
        {
            printf( "%d\n", p->number );
            p = p->next;
        }
    }
    return 0;
}

int PrintRandom() {
    int x = 0, max = 80, min = 50;
    x = (rand() % (max - min + 1) + min);
    printf("Random number is : %d\n", x);

    return x;
}

int main()
{
    srand( (unsigned)time(NULL) );

    struct list_node *head_even = NULL, *head_odd = NULL;
    int count_even = 0, count_odd = 0, random;
    bool is_even;

    while ( count_even < 10 || count_odd < 10 )
    {
        struct list_node **pp, *p, *q;

        //generate and print random number
        random = PrintRandom();

        //determine whether number is even or odd
        is_even = random % 2 == 0;

        //set pp to point to head pointer of the appropriate list
        //and check whether the appropriate list is already full
        if ( is_even )
        {
            if ( count_even >= 10 )
                continue;
            pp = &head_even;
        }
        else
        {
            if ( count_odd >= 10 )
                continue;
            pp = &head_odd;
        }

        for (;;) //infinite loop, equivalent to while (1)
        {
            p = *pp;

            //if we reached the end of the list, break out of the loop
            if ( p == NULL )
                break;

            if ( p->number <= random )
            {
                if ( p->number == random )
                {
                    //discard number, because it already exists in list

                    //cannot use `continue` here, because that would go to
                    //the next iteration of the innermost loop, but we
                    //want to go to the next iteration of the outer loop
                    goto next_outer_loop_iteration;
                }
                else
                {
                    break;
                }
            }

            pp = &p->next;
        }

        //allocate memory for new node
        q = malloc( sizeof *q );
        if ( q == NULL)
        {
            fprintf( stderr, "error allocating memory for new node!\n" );
            exit( EXIT_FAILURE );
        }

        //initialize new node
        q->number = random;
        q->next = p;

        //insert node into list
        *pp = q;

        //increment the appropriate counter
        if ( is_even )
            count_even++;
        else
            count_odd++;

    next_outer_loop_iteration:
        continue;
    }

    printf("Even numbers in list are:\n");
    PrintList( head_even );
    printf("Odd numbers in list are:\n");
    PrintList( head_odd );

    //NOTE: The memory of the linked lists is not being freed

    return 0;
}

【讨论】:

  • 现在可以正常使用了,谢谢!我唯一添加到您的答案中的东西,因为它仍然在偶数/奇数列表中打印超过 10 个数字,所以我在打印之前也将 if ( j%2 == 0) 更改为 if (j%2 == 0 && count_even
  • @duje.je:现在您的代码可以正常工作,我已将自己的解决方案添加到我的答案中。 (我不想在你自己解决之前给你解决方案)。
  • 你做了领主们写下整个答案的工作
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多