问题描述
魔术师现在有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;
}