简体   繁体   English

在C程序中将链表中的节点随机化

[英]Randomizing nodes in linked list, C program

the following function is part of sort of a game with questions and answers. 以下功能是带有问题和答案的游戏的一部分。 I have a problem with the randomization of the questions by their complexity-some questions appear more than once and the first also appears in every level, which should not happen. 我对问题的随机性有一个问题,那就是它们的复杂性-有些问题不止一次出现,而且第一个问题也出现在每个级别,这是不应该发生的。 Please help! 请帮忙!

typedef struct
{
    char question[300];
    char date[30], author[30], ansr1[80], ansr2[80], ansr3[80], ansr4[80];
    int id, correctAnsr, level;
} game;

typedef struct Node
{
    game data;
    struct Node* next;
}  node;

void printRandom1(node *head)
{
    if (isEmpty(head))
        return;

    srand(time(NULL));

    node *result = head->data.question;

    node *current = head;
    int n;
    for (n = 17; current != NULL; n++)
    {
        if (rand() % n == 0 && current->data.level == 0)
            result = current->data.question;
        current = current->next;
    }
    printf("%s\n", result);
    int i, ans;

    printf("1.-%s\n", result->data.ansr1);
    printf("2.-%s\n", result->data.ansr2);
    printf("3.-%s\n", result->data.ansr3);
    printf("4.-%s\n", result->data.ansr4);

    printf("Enter the correct answer: ");
    scanf("%d", &ans);
    if (ans == result->data.correctAnsr)
        printf("CORRECT ANSWER!\n");
    else
    {
        printf("WRONG ANSWER\n");
        printf("GAME OVER");
        printf("The correct answer is: %d\n", result->data.correctAnsr);
        return menu();
        exit(1);
    }
}

Ad " some questions appear more than once ": this is because you do not track used questions anyhow -- your random choice method always selects from the list of all questions (regardless if they have already been asked or not). 广告“ 一些问题出现不止一次 ”:这是因为您无论如何都不会跟踪使用过的问题-您的随机选择方法总是从所有问题的列表中进行选择(无论是否已经提出问题)。

Ad " first also appears in every level ": my bet is that your random choice method (which is quite strange) is not guaranteed to select a question (ie the result = current->data.question part may not be executed with quite high probability). 广告“ 首先也出现在每个级别 ”:我敢打赌,您的随机选择方法(很奇怪)不能保证选择一个问题(即result = current->data.question部分可能执行得不是很高)可能性)。 The initial value of result is kept in this case (which happens to be the first question). 在这种情况下, result的初始值将保留(恰好是第一个问题)。

Below is a modified version of your code. 下面是代码的修改版本。 Some remarks: 一些说明:

  • counting the number of questions in linked list is added. 计算链接列表中的问题数量。 It is needed for the random choice which selects among the answers with equal probability (to be correct -- there is some negligible bias, but probably not important here) 需要以相等的概率从答案中进行选择的随机选择(正确的做法是-可以忽略不计,但在这里可能并不重要)

  • used answers are tracked in a new linked-list 在新的链接列表中跟踪使用的答案

  • there is no level logic implemented. 没有实现级别逻辑。 You may want to remove questions with inappropriate level from the linked list at the beginning of the game 您可能想在游戏开始时从链接列表中删除不适当级别的问题。

  • the current variable is a pointer-to-a-pointer which simplifies the unlinking process (you do not need to keep the previous entry pointer this way) current变量是一个指向指针的指针,它简化了取消链接的过程(您无需以这种方式保留先前的入口指针)

Code: 码:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct
    {
    char question[300];
    char date[30], author[30], ansr1[80], ansr2[80], ansr3[80], ansr4[80];
    int id, correctAnsr, level;
} question;

typedef struct questionListNode {
    question data;
    struct questionListNode* next;
} questionListNode;

typedef struct {
    questionListNode* headAvailable; // Your former head variable
    questionListNode* headUsed; // Initialize this to NULL
    int numberOfAvailableNodes; // Number of nodes in headAvailable
    int numberOfCorrectAnswers; // Number of nodes in headUsed
} game;

void printRandom1(game* currentGame)
{
    if (currentGame->headAvailable == NULL || currentGame->numberOfAvailableNodes <= 0) {
        printf("No more questions, you've won!\n");
        exit(1);
    }

    srand(time(NULL)); // Consider moving this to the start of main()

    int chosenIndex = rand() % currentGame->numberOfAvailableNodes;
    questionListNode** current = &(currentGame->headAvailable);
    while ((chosenIndex > 0) && (*current != NULL)) { // the second check is for safety
        current = &((*current)->next);
        chosenIndex--;
    }

    questionListNode* currentQuestion = (*current);
    if (currentQuestion == NULL) {
        printf("Internal error: available count mismatch!\n");
        exit(1);
    }
    printf("%s\n", currentQuestion->data.question);
    int i, ans;

    printf("1.-%s\n", currentQuestion->data.ansr1);
    printf("2.-%s\n", currentQuestion->data.ansr2);
    printf("3.-%s\n", currentQuestion->data.ansr3);
    printf("4.-%s\n", currentQuestion->data.ansr4);

    printf("Enter the correct answer: ");
    scanf("%d", &ans);
    if (ans != currentQuestion->data.correctAnsr) {
        printf("WRONG ANSWER\n");
        printf("GAME OVER\n");
        printf("The correct answer is: %d\n", currentQuestion->data.correctAnsr);
        exit(1);
    }
    printf("CORRECT ANSWER!\n");
    // Remove currentQuestion from the available list
    (*current) = currentQuestion->next;
    // Put currentQuestion into used list
    currentQuestion->next = currentGame->headUsed;
    currentGame->headUsed = currentQuestion;
    // Update counters
    currentGame->numberOfAvailableNodes--;
    currentGame->numberOfCorrectAnswers++;
}

int main(int c, char** t)
{
    game g;
    g.headAvailable = NULL;
    g.headUsed = NULL;
    g.numberOfAvailableNodes = 0;
    g.numberOfCorrectAnswers = 0;

    questionListNode q1 = { { "Question 1", "", "", "A1*", "B1", "C1", "D1", 1, 1, 0 }, NULL };
    questionListNode q2 = { { "Question 2", "", "", "A2", "B2*", "C2", "D2", 2, 2, 0 }, &q1 };
    questionListNode q3 = { { "Question 3", "", "", "A3", "B3*", "C3", "D3", 3, 2, 0 }, &q2 };

    g.headAvailable = &q3;
    g.numberOfAvailableNodes = 3;

    while (1)
        printRandom1(&g);
}

Some additional (random) notes: 其他一些(随机)注意事项:

  • I am not sure linked-list is the best data structure for this task 我不确定链表是否是此任务的最佳数据结构

  • Consider naming your typedefs with some prefix (eg t_game , t_node ) 考虑使用一些前缀来命名您的typedef(例如t_gamet_node

  • If you wanted to re-start the game (instead of exit() ) you would need to join the two linked lists back together and reset the counters 如果您想重新开始游戏(而不是exit() ),则需要将两个链接列表重新连接在一起并重置计数器

Good luck! 祝好运!

Disclaimer: I did not spend that much time checking the code so please take it just as an example... 免责声明:我没有花太多时间检查代码,因此请仅以它为例...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM