(六)循环链表 魔术师发牌 ---- 见证奇迹的时刻到了

魔术师发牌

舞台上:魔术师利用一副牌中的13张黑桃牌(其实神马花色都行),预先给他们排好后叠在一起,肯定是有固定的顺序,牌面朝下面,对观众们说“我不看牌,只需要数一数就可以猜到每张牌是什么~。”
然后呢,魔术师讲最上面的那张牌数为1 ,把它翻过来正好是黑桃A,将黑桃A放在桌子上,第二次数1,2,将第一张牌放在这些牌的下面,将第二张牌翻过来 正好是黑桃2 ,也将它放在 桌子上 ,这样,依次进行下去,13张牌被全部翻出,而且 准确无误。

实际上是这样的。一开始,把有序叠好的牌放在桌面上铺好 一列, 最上面的那张为 黑桃A 也就是 1,然后把它拿出来,扔掉 ,然后从上边取出1张牌放到最底下,打开第二张牌是黑桃2,扔掉;再依次将2张放到底下,第三张是黑桃3,扔掉;依次。。。。。知道最后剩一张牌,黑桃K。

先不要纠结魔术师如何洗牌,洗成固定顺序,咱们先看看是那种顺序能够实现这种神奇的发牌方式。

解决方案:
利用循环链表,初始化13个0的循环链表,第一个为1,然后走两步为2,再走三步为3,再走四步为4,到第五步的时候就出现问题了,已经循环到头部了,这时我们定个规则,如果步过的节点不为0,则跳过,直到0为止。说白了,就是步过的数量,必须是步过0的数量。

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


typedef struct node
{
	int data;
	struct node* next;
}node;

node* ghead = NULL;

//创建没有头节点的循环链表
void create_list(int num)
{
	node* ltail = NULL, * lnew = NULL;
	int i;
	/*ghead = (node*)malloc(sizeof(node));
	ltail = ghead;*/
	for (i = 0; i < num; i++)
	{
		lnew = (node*)malloc(sizeof(node));
		lnew->data = 0;
		if (i == 0)
		{
			ghead = lnew;
			lnew->next = lnew;
		}
		else
		{
			lnew->next = ltail->next;
			ltail->next = lnew;
		}
		ltail = lnew;
	}
}

void printlist(node* ll)
{
	node* llh = NULL;
	llh = ll;
	int i = 1;
	if (!ll)
	{
		printf("链表为空");
		return;
	}
	while (ll->next != llh)
	{
		printf("%d:\t%d\n", i++, ll->data);
		ll = ll->next;
	}
	printf("%d:\t%d\n", i++, ll->data);
}

void magicpoker(node* ll)
{
	int count_step = 0;
	int i = 0;
	//第一张始终是1
	ll->data = 1;

	count_step = 2;

	while (1)
	{
		for (i = 0; i < count_step; i++)
		{
			ll = ll->next;
			if (ll->data != 0)
			{
				i--; //增加循环次数,就变相步过不为0的节点。
			}
		}
		if (ll->data == 0)
		{
			ll->data = count_step;
			//ll = ll->next;
			count_step++;
			if (count_step == 14)
			{
				break;
			}
		}
	}
}

int main()
{
	create_list(13);
	
	magicpoker(ghead);
	printlist(ghead);
	system("pause");
}

结果:

1:      1
2:      8
3:      2
4:      5
5:      10
6:      3
7:      12
8:      11
9:      9
10:     4
11:     7
12:     6
13:     13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值