C语言实现分组及排名模拟并排位输出

问题遇到的现象和发生背景

C语言实现世界杯的小组分组。参赛队:英格兰、法国、德国、意大利、西班牙、荷兰、葡萄牙、克罗地亚、土耳其、俄罗斯、瑞典、捷克、塞尔维亚、加纳、科特迪瓦、突尼斯、尼日利亚、喀麦隆、日本、韩国、澳大利亚、伊朗、美国、墨西哥、哥斯达黎加、洪都拉斯、巴西、阿根廷、巴拉圭、智利、乌拉圭、厄瓜多尔。
世界杯的小组分组规则如下:八只种子球队,是:乌拉圭队、西班牙队、德国队、阿根廷队、哥伦比亚队、比利时队、瑞士队、巴西队。
这八只球队一定分别在A——H八个组中(八只球队不能碰面)。小组分为A——H一共八个小组。分组结果按行输出。每个小组四个球队。(参考循环赛)。

提示:1.可以用链表指针或者结构体数组;2.随机数;3.也许你能做到我没有想到的

问题相关代码,请勿粘贴截图

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

#define TreeHeigh 5

typedef struct tree_s tree_t;
struct tree_s {
int Score;
int Heigh;
tree_t *Left;
tree_t *Right;
const char *Name;
};

const char *Other[] =
{
"英格兰","意大利","葡萄牙","克罗地亚","土耳其","瑞典","捷克","塞尔维亚","加纳",
"科特迪瓦","突尼斯","尼日利亚","喀麦隆","日本","韩国","澳大利亚","伊朗","美国",
"墨西哥","哥斯达黎加","洪都拉斯","巴拉圭","智利","厄瓜多尔"
};
const char *Send[] = { "乌拉圭","西班牙","德国","阿根廷","荷兰","法国","巴西","俄罗斯" };
int F_Send[8];
int F_Other[24];

void tree_init(tree_t **root, int heigh);
void tree_print(tree_t *root);

int main(void)
{
tree_t *root;
int heigh;

heigh = 0;

root = NULL;
tree_init(&root, heigh);
tree_print(root);
return 0;

}

void tree_init(tree_t **root, int Heigh)
{
int f;
static int g = -1;
srand((unsigned)time(NULL));
if (NULL == *root)
{
tree_t *item = (tree_t *)malloc(sizeof(tree_t));
if (NULL == item)
exit(EXIT_FAILURE);
item->Left = NULL;
item->Right = NULL;
item->Name = NULL;
item->Score = -1;
item->Heigh = Heigh;
*root = item;
}

if (TreeHeigh == (*root)->Heigh)
{
    ++g;
    if (0 == g % 4)
    {
        while (1)
        {
            f = rand() % 8;
            if (0 == F_Send[f])
            {
                (*root)->Name = Send[f];
                F_Send[f] = 1;
                break;
            }
        }
    }
    else
    {
        while (1)
        {
            f = rand() % 24;
            if (0 == F_Other[f])
            {
                (*root)->Name = Other[f];
                F_Other[f] = 1;
                break;
            }
        }
    }

}

if (TreeHeigh == Heigh)
    return;

tree_init(&(*root)->Left, Heigh + 1);
tree_init(&(*root)->Right, Heigh + 1);

}
void tree_print(tree_t *root)
{
static int g = 0;
static char ch = 'A';

if (NULL == root)
    return;
if (NULL != root->Name)
{
    if (0 == g % 4)
        printf("%c\n", ch++);
    printf("%s ", root->Name);
    ++g;
    if (0 == g % 2)
        printf("\n");
}
tree_print(root->Left);
tree_print(root->Right);

}

运行结果及报错内容

能够正常运行,但功能不全面

我的解答思路和尝试过的方法

运行环境为Visual Studio 2022

我想要达到的结果

再上面代码的基础上添加一个随机分组后模拟比赛进行淘汰赛,输出排名的功能
假设八个小组均为种子球队出线晋级下一轮,目前需要进行八支球队随机分四组进行八进四赛制,四组决出胜者后再分组进行四进二,最后进行决赛。输出世界杯比赛排名。
因为不知道谁会胜利就随机模拟吧,最后按照结果输出前四名(能按结果排序输出前八名更好)
代码两百行左右,越多越好,感谢各位

在你代码基础上增加了功能,通过结构体数组实现,通过递归进行计算,从8进4、4进2,2进1为止,每轮比赛输出比赛的双方及结果。最后输出总排名,运行结果如下:

img

代码:


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


const char* Other[] =
{
    "英格兰","意大利","葡萄牙","克罗地亚","土耳其","瑞典","捷克","塞尔维亚","加纳",
    "科特迪瓦","突尼斯","尼日利亚","喀麦隆","日本","韩国","澳大利亚","伊朗","美国",
    "墨西哥","哥斯达黎加","洪都拉斯","巴拉圭","智利","厄瓜多尔"
};
const char* Send[] = { "乌拉圭","西班牙","德国","阿根廷","荷兰","法国","巴西","俄罗斯" };
int F_Send[8];
int F_Other[24];


//定义数据结构
typedef struct _teamnode
{
    int id; //球队编号,这个没太大影响
    char name[20];
}TeamNode;

void group();
void startgame();

int main(void)
{
    srand((unsigned int)time(NULL));
    //分组
    group();

    printf("\n\n----------------晋级赛------------------\n");
    startgame();

    system("pause"); 
    return 0;
}
void group()
{
    TeamNode teams[8][4];
    int flag[24]={0};
    int i,j;
    int index;
    char ch = 'A';
    //将8个种子队分别插入8个小组
    for(i=0;i<8;i++)
    {
        strcpy(teams[i][0].name,Send[i]);
    }
    //将21个球队分配给每个小组
    for(i=0;i<7;i++) 
    {
        for(j=1;j<4;j++)
        {
            while(1)
            {
                index = rand()%24;
                //判断index对应的小队是否已经被分配
                if(flag[index] == 0)
                {
                    flag[index] =1;
                    break;
                }
            }
            teams[i][j].id = index;
            strcpy(teams[i][j].name,Other[index]);

        }

    }
    //剩余的3个球队分配给最后一个小组,这里剩余3个不再用随机数,是因为当剩余的数量较少时,通过随机数得到正确的位置的概率会极低
    j = 1;
    for(i=0;i<24;i++)
    {
        if(flag[i]==0)
        {
            teams[7][j].id = i;
            strcpy(teams[7][j].name,Other[i]);
            flag[i] = 1;
            j++;
        }
        if(j== 4) break;
    }

    //显示分组
    for(i=0;i<8;i++)
    {
        printf("%c组:\n",(char)(ch+i));
        for(j=0;j<4;j++)
        {
            printf("    %s",teams[i][j].name);
            if(j==1 || j==3)
                printf("\n");
        }
        printf("\n");
    }

}

//两两分组比赛
void game(TeamNode teams[], int nmbTeams)
{
    int i, j, t;
    int index1,index2;
    TeamNode tmp;
    TeamNode arr[32];
    if (nmbTeams == 1 || nmbTeams == 0)
    {
        return;
    }
    //标识球队的状态
    t = nmbTeams;
    while (t)
    {
        index1 = rand() % t; //得到第一支球队
        //获取第一支球队的对手
        while (1)
        {
            index2 = rand() % t;
            if (index2 != index1)
                break;
        }
        //将这两只球队移动到数组末尾
        tmp = teams[t - 2];
        teams[t - 2] = teams[index1];
        teams[index1] = tmp;
        tmp = teams[t - 1];
        teams[t - 1] = teams[index2];
        teams[index2] = tmp;

        t -= 2;
    }
    //输出比赛的的球队,并通过随机数设置获胜的球队
    printf("%d进%d比赛\n", nmbTeams, nmbTeams / 2);
    for (i = 0; i < nmbTeams-1; i += 2)
    {
        printf("%s  VS   %s   ", teams[i].name, teams[i + 1].name);
        index1 = rand() % 2; //获取0到1的随机数,0表示前面的球队胜利,1表示后面的球队胜利
        if (index1 == 1) //交换两个球队的位置,并输出结果
        {
            printf("%s晋级\n", teams[i + 1].name); //将晋级的球队放在前面
            tmp = teams[i];
            teams[i] = teams[i + 1];
            teams[i + 1] = tmp;
        }
        else
            printf("%s晋级\n", teams[i].name);
    }
    //将所有获胜的球队 放在数组的最前面
    j = 0;
    for(i=1;i<nmbTeams;i+=2)
        arr[j++] = teams[i];
    j=0;
    for(i=0;i<nmbTeams;i+=2)
        teams[j++] = teams[i];
    for(j=0;j<nmbTeams/2;j++)
        teams[nmbTeams/2+j] = arr[j];

    

    //递归,直到得出总冠军

    game(teams, nmbTeams / 2);
}
void startgame()
{
    //生成球队数组,只考虑种子球队
    TeamNode teams[8];
    int i, nmbTeams = 8;
    for (int i = 0; i < nmbTeams; i++)
    {
        teams[i].id = i + 1;
        strcpy(teams[i].name, Send[i]); //只考虑种子球队
    }
    //每两个球队进行淘汰赛
    game(teams, nmbTeams);
    //输出最后的排名
    printf("\n\n--------------排名---------------\n");
    for (i = 0; i < nmbTeams; i++)
        printf("%-2d   %s\n", i + 1, teams[i].name);

}

如果全部都是淘汰赛,其实相对好模拟,直接用数组操作即可。因为只需要用数组记录队的ID即可,可以通过ID查询到原始队伍名称。

按现在的规则,只能输出 1、2和并列3名吧,没有说3、4名有比赛(当然添加一场比赛模拟也是可以的)。
分组其实用洗牌算法,种子队洗牌随机排序,其它队洗牌随机排序,然后依序取种子1队,其它3队组成一组,可以再在组内随机排序(意义不大,因为其他3队本身就是乱序的)。

因为后面比赛是淘汰赛,相对简单,对于小组赛,如果也是淘汰赛,也简单,如果是循环赛相对复杂!

对于淘汰赛,模拟得到0或者1分别表示2队中前序或者后序队伍获胜,把其对应ID写入下一轮待比赛队伍即可。

至于种子队全部进入第2轮,因为种子队ID一定,且其和最小,所以直接比较第二轮待进行队伍ID和是否为定值即可判断,如果是,再排序一次(其实这个分组的时候已经排序过,意义不大的)。

这样其实队伍ID可以一直在一个数组中,总是数组中2N与2N+1的队伍进行比赛淘汰,N是等待比赛队伍总数的一半。

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

const char* Name[32]={"乌拉圭","西班牙","德国","阿根廷","荷兰","法国","巴西","俄罗斯","英格兰","意大利","葡萄牙","克罗地亚","土耳其","瑞典","捷克","塞尔维亚","加纳",
"科特迪瓦","突尼斯","尼日利亚","喀麦隆","日本","韩国","澳大利亚","伊朗","美国","墨西哥","哥斯达黎加","洪都拉斯","巴拉圭","智利","厄瓜多尔"};



void sortTerm(unsigned int * IDArr,unsigned int len){
    /*利用洗牌算法,根据flen情况,对IDArr中前len元素进行随机排序*/ 
    unsigned int i,t,r;
    srand((unsigned)time(NULL));
    for(i=0;i<len;i++){
        t=IDArr[i];
        r=rand()%len;
        IDArr[i]=IDArr[r];
        IDArr[r]=t;
    }    
}

void getGame(unsigned  int *A) {
    /*模拟2队伍比赛情况,2元素根据数组,胜利队为A[0],失败队为A[1]*/ 
    unsigned int t,r;
    srand((unsigned)time(NULL));
    r=rand()%2;
    if (r!=0){
        t=A[0];
        A[0]=A[1];
        A[1]=t;
    }
}

int main(void) {
    unsigned int seedT[8]={0,1,2,3,4,5,6,7};
    unsigned int otherT[24]={8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};
    unsigned int tLen,i;
    unsigned int gameStar[32],VEnd[16],LEnd[16];
    
    /* 随机分组过程 */
    sortTerm(seedT , 8);
    sortTerm(otherT,24);
    for (i=0;i<8;i++){
        gameStar[i*4]=seedT[i];
        gameStar[i*4+1]=otherT[i*3];
        gameStar[i*4+2]=otherT[i*3+1];
        gameStar[i*4+3]=otherT[i*3+2];
    }
    
    /*小组赛,淘汰赛要进行2轮,下面是第一轮*/
    tLen=16; 
    for( i=0;i<tLen;i++){
        getGame(gameStar+i*2);
        VEnd[i] =  gameStar[i*2];
        LEnd[i] =  gameStar[i*2+1];
    }
    for(i=0;i<tLen;i++){
        gameStar[i]=VEnd[i];
        gameStar[i+tLen]=LEnd[i];
    }
    
    /*小组赛,淘汰赛要进行2轮,下面是第二轮*/
    tLen =8; 
    for( i=0;i<tLen;i++){
        getGame(gameStar+i*2);
        VEnd[i] =  gameStar[i*2];
        LEnd[i] =  gameStar[i*2+1];
    }
    for(i=0;i<tLen;i++){
        gameStar[i]=VEnd[i];
        gameStar[i+tLen]=LEnd[i];
    }
    
    /* 小组赛后的重新分组 */ 
    unsigned int sum=0;
    for(i=0;i<8;i++){
        sum=sum+gameStar[i];
    }
    if(sum==28) sortTerm(gameStar , 8);
    
    /*四分之一决赛*/
    tLen =4; 
    for( i=0;i<tLen;i++){
        getGame(gameStar+i*2);
        VEnd[i] =  gameStar[i*2];
        LEnd[i] =  gameStar[i*2+1];
    }
    for(i=0;i<tLen;i++){
        gameStar[i]=VEnd[i];
        gameStar[i+tLen]=LEnd[i];
    }
    
    /*半决赛*/
    tLen =2; 
    for( i=0;i<tLen;i++){
        getGame(gameStar+i*2);
        VEnd[i] =  gameStar[i*2];
        LEnd[i] =  gameStar[i*2+1];
    }
    for(i=0;i<tLen;i++){
        gameStar[i]=VEnd[i];
        gameStar[i+tLen]=LEnd[i];
    }
    
    /* 决赛 */
    getGame(gameStar);
    
    /*所有比赛结果都保存到 gameStar 中的*/
    /* 结果输出  */
    printf("冠军:%s\n",Name[gameStar[0]]);
    printf("亚军:%s\n",Name[gameStar[1]]);
    printf("止步半决赛:%s,%s\n",Name[gameStar[2]],Name[gameStar[3]]);
    printf("进入八强:%s,%s,%s,%s\n",Name[gameStar[4]],Name[gameStar[5]],Name[gameStar[6]],Name[gameStar[7]]);
    printf("小组赛胜利过1场:%s,%s,%s,%s,%s,%s,%s,%s\n",Name[gameStar[8]],Name[gameStar[9]],Name[gameStar[10]],Name[gameStar[11]],Name[gameStar[12]],Name[gameStar[13]],Name[gameStar[14]],Name[gameStar[15]]);
}

需要用Java实现榨干你吗?