栈,队列的综合应用及讲解

栈与队列的综合应用

【栈的定义】

栈是限定仅在表尾进行插入和删除操作的线性表,栈的插入就是压栈,栈的删除就是出栈,为后进先出结构,出栈的地方叫做栈顶。

一共有两种栈的存储方式,一种顺序栈,通常由数组实现,另一种链栈,由单链表指针实现,顺序栈选择数组首元素作为栈顶,链栈选择头指针位置作为栈顶。

【队列定义】

1、队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
2、与栈相反,队列是一种先进先出的线性表.
3、实现一个队列同样需要顺序表或链表作为基础。
(头结点不是必要的,但为了方便操作还是加上)
栈,队列的综合应用及讲解
(空队列时,front和rear都指向头结点。)
栈,队列的综合应用及讲解

【纸牌游戏】

“小猫钓鱼”的游戏规则是这样的:将一副扑克牌平均分成两份,每人拿一份。玩家U1先拿出手中的第一张扑克牌放在桌上,然后玩家U2也拿出手中的第一张扑克牌,并放在玩家U1刚打出的扑克牌的上面,就像这样两个玩家交替出牌。出牌时,如果某人打出的牌与桌上某张牌的牌面相同,即可将两张相同的牌及其中间所夹的牌全部取走,并依次放到自己手中牌的末尾。当任意一个人手中的牌全部出完时,游戏结束,对手获胜。

现在要求你写一个算法来模拟这场游戏,并判断出谁最后获胜,获胜的同事打印出获胜者手中的牌以及桌上可能剩余的牌。

在写程序开始前,我们暂且先做一个约定,玩家U1和U2手中牌的牌面值只有1~9。

解法思路
我们可以先分析一下这个游戏存在哪几种操作。玩家U1有两种操作,分别是出牌和赢牌,出牌时将手中的牌打出去,赢牌的时候将桌上的牌放到手中牌的末尾,这恰好对应了队列的两个操作,出牌就是队列出队,赢牌就是队列入队。玩家U1和玩家U2的操作是一样的。而桌子很明显就可以看作是一个栈,玩家没打出一站牌就放到桌上,相当于入栈,因为顺序是往后的,当有人赢牌的时候,依次将牌从桌上拿走,这就相当于出栈。那如何判断是否赢牌呢?赢牌的判断就是:如果某人打出的牌与桌上的某张牌相同,即可将两张牌及其中间的所夹得牌全部取走。那如何直到桌上现在有哪些牌呢,很容易想到的就是每次打出牌之后遍历一遍桌上已有的牌然后比对,存在相同的牌则算赢牌。这是简单而且粗暴一点的方法,其实有更好的方法,那就是用桶来解决这个问题,牌面值只有1-9,我们可以设置一个大小为10的数组作为桶,每打出一张牌,就以此牌的牌面值作为下标找到数组对应位置,如果该位置存在值,则说明桌上有存在的牌,如果没有值,则说明桌上没有相同的牌,同时在通上做标记,即数组该下标位置设置为1。那如果赢牌了,桌上的牌拿走了桶应该怎么办呢?也很简单,出栈的时候依次按照牌面值清空桶就行了。最终怎么判断哪个玩家获得最终胜利呢,获得最终胜利的标准就是对方手上已经没牌了,如果从队列角度看,那就是头指针和尾指针相等了。

从上面的思路分析可以看出,为了模拟这场游戏,我们需要准备两个队列、一个栈和一个桶,分别表示玩家U1U2手中的牌、桌上的牌以及桌上牌的牌面值。下面我们写具体的代码,为了方便阅读,关键代码上面我都给出非常详细的注释。

首先创建两个结构体,一个表示栈一个表示队列

struct duilie
{
	int head;
	int tail;
	int data[1000];
};
struct zhan
{
	int top;
	int data[1000];
};

初始化队列的头结点尾节点,利用for循环初始化桶
两个for循环输入分别输入6个数字进入队列

struct duilie q1,q2;
	struct zhan s;
	int book[10];
	int i,t;
	q1.head=0;
	q1.tail=0;
	q2.head=0;
	q2.tail=0;
	s.top=0;
	for(i=0;i<10;i++)
	{
		book[i]=0;
	}
	for(i=0;i<6;i++)
	{
		scanf("%d",&q1.data[q1.tail]);
		q1.tail++;//每输入一个数字队尾加一
	}
	for(i=0;i<6;i++)
	{
		scanf("%d",&q2.data[q2.tail]);
		q2.tail++;//每输入一个数字队尾加一
	}

小哼出牌

		t=q1.data[q1.head];//将小哼打出的牌存放在临时变量t中
		if(book[t]==0)//如果桶中没有这张牌,表示此回合并没有赢牌
		{	
			q1.head++;//将牌从队列中取出
			s.top++;//将取出的牌放在桌子上,由于桌子代表栈,所以栈顶+1
			s.data[s.top]=t;//将取出的牌放在桌子上			
			book[t]=1;//将桌子上的牌放入桶中,标记为1,证明桌子上存在刚刚打出的这张牌
		}
		else//赢牌
		{
			q1.head++;//将牌从队列中取出
			q1.data[q1.tail]=t;//由于赢牌将刚刚打出的牌放回手中,也就是队尾
			q1.tail++;//队尾+1
			while(s.data[s.top]!=t)//如果桌子上的牌不是刚刚打出的牌,则全部收走
			{
				book[s.data[s.top]]=0;//取消桶中的标记
				q1.data[q1.tail]=s.data[s.top];//讲桌上的牌放入手中
				q1.tail++;//队尾+1			
				s.top--;//由于在桌子上取走牌,所以栈顶-1
			}
			book[s.data[s.top]]=0;//这张牌是t的牌,也就是与刚打出牌相同的牌,取消标记
			q1.data[q1.tail]=s.data[s.top];//取出这张牌,放手里
			q1.tail++;//手里多张牌,队尾+1
			s.top--;//桌上少一张牌,栈顶-1
		}
		if(q1.head==q1.tail)//如果小哈没牌,则结束循环
		{
			break;
		}

小哈出牌
同理

	t=q2.data[q2.head];
		if(book[t]==0)
		{	
			q2.head++;
			s.top++;
			s.data[s.top]=t;	
			book[t]=1;
		}
		else
		{
			q2.head++;
			q2.data[q2.tail]=t;
			q2.tail++;
			while(s.data[s.top]!=t)
			{
				book[s.data[s.top]]=0;
				q2.data[q2.tail]=s.data[s.top];		
				q2.tail++;
				s.top--;
			}
			book[s.data[s.top]]=0;
			q2.data[q2.tail]=s.data[s.top];
			q2.tail++;
			s.top--;
		}
	}

判断如果小哼没牌时,则小哈赢


	if(q1.head==q1.tail)
	{
		printf("小哈win\n");
		printf("小哈手中的牌是");
		for(i=q2.head;i<q2.tail;i++)//将队列的牌取出
		{
			printf("%d ",q2.data[i]);
		}
		printf("\n");
		if(s.top>0)//如果桌子上还有牌
		{
			printf("桌上还有牌为");
			for(i=1;i<s.top;i++)//将桌子上的牌取出
			{
				printf("%d ",s.data[i]);
			}
		}
		printf("\n");
	}

判断如果小哈没牌时,则小哼赢

	else
	{
		printf("小哼win\n");
		printf("小哼手中的牌是");
		for(i=q1.head;i<q1.tail;i++)
		{
			printf("%d ",q1.data[i]);
		}
		printf("\n");
		if(s.top>0)
		{
			printf("桌上还有牌为");
			for(i=1;i<s.top;i++)
			{
				printf("%d ",s.data[i]);
			}
		}
		printf("\n");
	}

完整代码

#include<stdio.h>//玩牌游戏
struct duilie
{
	int head;
	int tail;
	int data[1000];
};
struct zhan
{
	int top;
	int data[1000];
};
int main()
{
	struct duilie q1,q2;
	struct zhan s;
	int book[10];
	int i,t;
	q1.head=0;
	q1.tail=0;
	q2.head=0;
	q2.tail=0;
	s.top=0;
	for(i=0;i<10;i++)
	{
		book[i]=0;
	}
	for(i=0;i<6;i++)
	{
		scanf("%d",&q1.data[q1.tail]);
		q1.tail++;
	}
	for(i=0;i<6;i++)
	{
		scanf("%d",&q2.data[q2.tail]);
		q2.tail++;
	}
	while(q1.head<q1.tail&&q2.head<q2.tail)
	{
		t=q1.data[q1.head];
		if(book[t]==0)
		{	
			q1.head++;
			s.top++;
			s.data[s.top]=t;			
			book[t]=1;
		}
		else
		{
			q1.head++;
			q1.data[q1.tail]=t;
			q1.tail++;
			while(s.data[s.top]!=t)
			{
				book[s.data[s.top]]=0;
				q1.data[q1.tail]=s.data[s.top];
				q1.tail++;		
				s.top--;
			}
			book[s.data[s.top]]=0;
			q1.data[q1.tail]=s.data[s.top];
			q1.tail++;
			s.top--;
		}
		if(q1.head==q1.tail)
		{
			break;
		}

		t=q2.data[q2.head];
		if(book[t]==0)
		{	
			q2.head++;
			s.top++;
			s.data[s.top]=t;	
			book[t]=1;
		}
		else
		{
			q2.head++;
			q2.data[q2.tail]=t;
			q2.tail++;
			while(s.data[s.top]!=t)
			{
				book[s.data[s.top]]=0;
				q2.data[q2.tail]=s.data[s.top];		
				q2.tail++;
				s.top--;
			}
			book[s.data[s.top]]=0;
			q2.data[q2.tail]=s.data[s.top];
			q2.tail++;
			s.top--;
		}
	}


	if(q1.head==q1.tail)
	{
		printf("小哈win\n");
		printf("小哈手中的牌是");
		for(i=q2.head;i<q2.tail;i++)
		{
			printf("%d ",q2.data[i]);
		}
		printf("\n");
		if(s.top>0)
		{
			printf("桌上还有牌为");
			for(i=1;i<s.top;i++)
			{
				printf("%d ",s.data[i]);
			}
		}
		printf("\n");
	}
	else
	{
		printf("小哼win\n");
		printf("小哼手中的牌是");
		for(i=q1.head;i<q1.tail;i++)
		{
			printf("%d ",q1.data[i]);
		}
		printf("\n");
		if(s.top>0)
		{
			printf("桌上还有牌为");
			for(i=1;i<s.top;i++)
			{
				printf("%d ",s.data[i]);
			}
		}
		printf("\n");
	}
	return 0;
}
上一篇:多级反馈队列调度算法


下一篇:c++ STL queue:deque+优先队列