魔术师发牌问题、拉丁方阵问题循环链表实现

目录



魔术师发牌问题


问题描述:魔术师利用一副普通的扑克牌中的13张黑桃,预先将他们排好后叠放在一起,牌面朝下,对观众说:“我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?现场演示。”
一开始,魔术师数1,然后把最上面的那张牌翻过来,是黑桃A;然后将其放到桌面上;第二次,魔术师数1、2;将第一张牌放到手中未翻过的扑克牌的最下面,将第二张牌翻转过来,正好是黑桃2;第三次,魔术师数1、2、3;将第1、2张牌依次放到手中未翻过的扑克牌的最下面,将第三张牌翻过来正好是黑桃3;……直到将所有的牌都翻出来为止。问原来牌的顺序是如何的。

实现结果:

魔术师发牌

完成方法如下:


宏定义及结构体类型声明

typedef int ElemType ;
#define MAX_CARDS 13
typedef struct magician
{
    ElemType data;
    struct magician *next;
}magician , * Ptrmagician;

初始化

/*******************************************
 * 函数名称:MagicianInit()
 * 功能描述:魔术师发牌问题链表初始化
 * 传入参数:无
 * 返回值: 循环链表头指针
********************************************/
Ptrmagician MagicianInit()
{
    Ptrmagician list = NULL;
    Ptrmagician p,q;
    int i;
    q = list;
    for(i =0; i< MAX_CARDS;i++)
    {
        p = (Ptrmagician)malloc(sizeof(magician));
        p -> data = 0;/*初始状态不保存数据*/
        if(list == NULL)
        {
            list = p;/*头结点*/
        }
        else
        {
            q -> next = p;
        }
        q = p;
    }
    q -> next = list;/*首尾相连*/
}

计算牌的顺序

/*******************************************
 * 函数名称:Magician(Ptrmagician list)
 * 功能描述:魔术师发牌问题中牌的顺序计算
 * 传入参数:Ptrmagician list   传入的链表
 * 返回值: 无
********************************************/
void Magician(Ptrmagician list)
{
    Ptrmagician s;
    int i;
    int count = 2;/*第一张牌存有数据1,第二张牌在1之后的第二张*/
    s = list;
    s -> data = 1;
    while(1)
    {
        for (i = 0; i < count; i++)
        {
            s = s -> next;
            if(s -> data != 0)
            {
                s -> next;/*这里是指向,而不是赋值*/
                i--;/*当前位置存有数据*/
            }
        }
        if(s -> data == 0)
        {
            s -> data = count;
            count++;
            if(count == MAX_CARDS+1)
            {
                break;/*牌的顺序计算完成*/
            }
        }
    }
}

最终实现

/*****************************************************************
 * 函数名称:main()
 * 功能描述:主函数
 * 传入参数:无
 * 返回值:0
 * 魔术师发牌问题描述:
 *                  魔术师利用一副普通的扑克牌中的13张黑桃,预先将
 *                  他们排好后叠放在一起,牌面朝下,对观众说:“我不
 *                  看牌,只数数就可以猜到每张牌是什么,我大声数数,
 *                  你们听,不信?现场演示。”
 *                  一开始,魔术师数1,然后把最上面的那张牌翻过来,
 *                  是黑桃A;然后将其放到桌面上;第二次,魔术师数1、
 *                  2;将第一张牌放到手中未翻过的扑克牌的最下面,将
 *                  第二张牌翻转过来,正好是黑桃2;第三次,魔术师数
 *                  1、2、3;将第1、2张牌依次放到手中未翻过的扑克牌
 *                  的最下面,将第三张牌翻过来正好是黑桃3;……直到将
 *                  所有的牌都翻出来为止。问原来牌的顺序是如何的。
******************************************************************/
int main()
{
    Ptrmagician m;
    int i;
    m = MagicianInit();
    Magician(m);
    printf("魔术师发牌问题中牌的顺序如下:\n");
    for(i = 0; i< MAX_CARDS; i++)
    {
        printf("黑桃%d ", m ->data);
        m = m -> next;
    }
    printf("\n");
    DestoryList(m);
    return 0;
}

拉丁方阵问题


拉丁方阵(Latin square):是一种 n × n 的方阵,在这种 n x n 的方阵里,恰有 n 种不同的元素,每一种不同的元素在同一行或同一列里只出现一次。

n等于5时方阵如下图:
12345
23451
34512
45123
51234

实现结果:

拉丁方阵

实现方法:


宏定义及结构体类型声明

/*待处理数据类型*/
typedef int ElemType ;
/*结点结构*/
typedef struct latin
{
    ElemType data;
    struct latin *next;
}latin , * Ptrlatin;

循环链表初始化

/**********************************************
 * 函数名称:LatinInit(int n)
 * 功能描述:初始化一个循环链表
 * 传入参数:int n   循环链表的长度
 * 返回值:循环链表的头结点
***********************************************/
Ptrlatin LatinInit(int n)
{
    Ptrlatin list = NULL;/*头结点*/
    Ptrlatin p,q;
    int i;
    p = list;
    for(i = 1; i <= n; i++)
    {
        q = (Ptrlatin)malloc(sizeof(latin));
        q ->data = i;
        if (list == NULL )
        {
            list = q;
        }
        else
        {
            p -> next = q;
        }
        p = q;
    }
    p ->next = list;
    return list;
}

方阵生成

/**********************************************
 * 函数名称:Latin(Ptrlatin list, int n)
 * 功能描述:拉丁方阵问题主要计算过程
 * 传入参数:Ptrlatin list 传入的循环链表
 *           int n          循环链表的长度
 * 返回值:无
***********************************************/
void Latin(Ptrlatin list, int n)
{
    Ptrlatin s = list;
    int i,j;
    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            printf("%d ",s ->data);
            s = s -> next;
        }
        printf("\n");
        s = s ->next;
    }
}

最终实现

/**********************************************
 * 函数名称:main()
 * 功能描述:主函数
 * 传入参数:无
 * 返回值:0
 * 问题:用循环链表实现拉丁方阵:
 *                      ---------------------
 *                      | 1 | 2 | 3 | 4 | 5 |
 *                      ---------------------
 *                      | 2 | 3 | 4 | 5 | 1 |
 *                      ---------------------
 *                      | 3 | 4 | 5 | 1 | 2 |
 *                      ---------------------
 *                      | 4 | 5 | 1 | 2 | 3 |
 *                      ---------------------
 *                      | 5 | 1 | 2 | 3 | 4 |
 *                      ---------------------
 * 方法:首先建立一个单向循环链表,之后进行双层
 *       循环,内层循环打印,内层循环结束后,外
 *       层循环对链表头指针后移一位
***********************************************/
int main()
{
    Ptrlatin list;
    int n;
    printf("请输入拉丁方阵的大小:");
    scanf("%d",&n);
    list = LatinInit(n);
    Latin(list,n);
    return 0;
}

😜
🙃
O(∩_∩)O

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值