循环链表 之 魔术师发牌问题

问题描述

魔术师现在有13张黑桃扑克,现在要完成下面这个魔术:
将扑克整理好后,翻开第一张为黑桃1(黑桃A)并放在桌上(牌堆剩余12张),然后将剩余牌的第一张放置在牌堆最底部,翻开第二张是黑桃2并放在桌上(牌堆剩余11张),再将剩余扑克的第一张,第二张一次放到牌堆底,第三张亮出是黑桃3并放在桌上,以此类推,是黑桃几就抽到第几张并亮出,直到所以扑克按照这种方式,依次由黑桃1(黑桃A)到黑桃13(黑桃K)在桌上列出;
嘻嘻,放一张比较沙雕的图
在这里插入图片描述

图片描述

假设从左至右比作扑克从上向下,则前几张扑克应该是这样:
在这里插入图片描述

算法解决

解决这个问题,我们可以用到循环链表,首先,要创建一个有13个成员的链表,我们把他们的data都赋值为0,然后再按我们想要的顺序来给他们赋值,创建链表代码:

初始化链表

typedef struct node
{
    int data;
    struct node *next;
}sqlist,*linklist;

linklist CreateLinkList()  //创建一个循环链表
{
    linklist head = NULL;
    linklist s,r;
    int i;

    r = head;

    for(i = 1;i <= CardNumber;i++)
    {
        s = (linklist)malloc(sizeof(sqlist));  //分配存储空间
        s -> data = 0;

        if(head == NULL)  //表示空表
            head = s;
        else 
            r -> next = s;

        r = s;
    }

    r -> next = head;

    return head;

}

算法

首先,设置一个指针p指向头节点,将头节点的data域设置为1,因为接下来要翻两次,所以要将
p -> next ->next -> data = 2;即将头节点的下一个的下一个节点的data域设置为2;接下来是3点,需要翻到第三张牌,所以我们可以设置一个变量,在每一次赋值结束之后都自加,当然,对于扑克,牌堆中的牌是越来越少的,但对于链表来说不会,当我们赋值到后面时,会存在满足我们要求的节点位上已经赋值过了,所以这也是我们需要考虑的问题;
下面是代码:

void OrderCal(linklist head)
{
    linklist p;
    int j;
    int Countnumber = 2;

    p = head;

    p -> data = 1;

    while(1)
    {
    
        for(j = 1;j <= Countnumber;j++)
        {
            p = p -> next;  // p 指向下一个节点;
        
            if(p -> data != 0)  //若该节点已经有过数据了,j--可以让循环多执行一次;
            {
                j--;
            }
        }
        p -> data = Countnumber;
        Countnumber++;

        if(Countnumber == 14)
            break;
    }
}

运行


int main(int argc,char **argv)
{
    linklist p;
    int i;

    p = CreateLinkList();
    OrderCal(p);

    printf("按以下顺序放置扑克:\n");
    for(i = 0;i < CardNumber;i++)
    {
        printf("黑桃%d  ",p->data);
        p = p -> next;
    }

    printf("\n");

    return 0;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45121946/article/details/105465256