栈
上一篇讲的是队列,是一种先进先出的数据结构。还有一种后进先出的数据结构,称为栈。
栈限定为只能在一端进行插入和删除操作。比如往杯子里面放球,然后再往出拿,显然,最后放入的球可以最先拿出来。
判断回文
通过栈这个数据结构可以判断一个字符是否是回文。
- 读取字符串
char a[101];
int len;
gets(a);
len=strlen(a);
- 如果一个字符串是回文的话,那么它必须是中心对称,求中点
mid=len/2-1;
- 将mid之前的字符全部入栈,此处栈用来存储字符,所以此处用来实现栈的数组类型是字符数组,char s[101];,
- 初始化栈,top=0
- 入栈的操作top++;s[top]=x;(假设需要入栈的字符暂存在字符变量x中),简写成s[++top]=x;
- 代码实现mid之前字符全部入栈
for(i=0;i<=mid;i++)
{
s[++top]=a[i];
}
- 判断回文,将当前栈中的字符依次出栈,看是否能与mid之后的字符一一匹配,如果能匹配就是回文串,否则不是。
for(i=mid+1;i<=len-1;i++)
{
if(a[i]!=s[top])
{
break;
}
top--;
}
if(top==0)
printf("YES");
else
printf("NO");
当top=0时,说明栈内所有的字符都被一一匹配了,那么这个字符就是回文串。
下面附判断回文串完整代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//解密回文--栈
int main()
{
char a[101],s[101];
int i,len,mid,next,top;
gets(a);//读入字符串
len=strlen(a);//字符串长度
mid=len/2-1;//求字符串中点
top=0;//初始化栈
//将mid前的字符依次入栈
for(i=0;i<=mid;i++)
s[++top]=a[i];
//判断字符串长度是奇数还是偶数,并找出需要进行字符匹配的起始下标
if(len%2==0) //偶数
next=mid+1;
else //奇数
next=mid+2;
//开始匹配
for(i=next;i<=len-1;i++)
{
if(a[i]!=s[top])
break;
top--;
}
//当top=0时,说明栈内所有的字符都被一一匹配了
if(top==0)
printf("YES\n");
else
printf("NO\n");
return 0;
}
栈还可以用来进行验证括号的匹配。
纸牌游戏——小猫钓鱼
游戏规则:将一副扑克牌平均分成两份,每人拿1份,小哼先拿出第一张扑克牌放在桌上,然后小哈也拿出手中的第一张扑克牌,并放在小哼刚打出的扑克牌上面,两人交替出牌,出牌时,如果某人打出的牌和桌上某张牌牌面相同,即可将两张相同的牌,及夹在其中间的牌全部拿走,并依次放在自己手中牌的末尾,当任意一个人手中的牌全部出完时,游戏结束,对手获胜。
游戏开始时,小哼手中6张牌2,4,1,2,5,6。小哈手上也有6张牌3,1,3,5,6,4。牌面只有1~9。判断是谁赢。
分析
对于玩家而言有2种操作:赢牌和出牌
- 赢牌:入队
- 出牌:出队
对于桌子而言有2种操作:牌被放到桌上和牌被从桌上拿走
- 牌放到桌子上:入栈
- 牌被拿走:出栈
两个玩家,一张桌子,所以用两个队列,一个栈来模拟整个游戏。
完整代码
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
struct queue
{
int data[1000];
int head;
int tail;
};
struct stack
{
int data[10];
int top;
};
int main()
{
struct queue q1,q2;//小哼的扑克牌队列q1,小哈的扑克牌队列q2
struct stack s;//桌子上的扑克牌
int book[10];
int i,t;
//初始化队列,q1,q2为空,两人手中没有牌
q1.head=1;
q1.tail=1;
q2.head=1;
q2.tail=1;
//初始化栈,桌子上面没有牌
s.top=0;
//初始化用来标记的数组,用来标记哪些牌已经在桌子上
//book[10]={0};不可取
for(i=0;i<=9;i++)
{
book[i]=0;//初始化
}
//依次向队列中插入6个数
//小哼手上有6张牌
for(i=1;i<=6;i++)
{
scanf("%d",&q1.data[q1.tail]);//读入一个数到队尾q1.data[1],q1.data[2]...
q1.tail++;//队尾往后挪一位,q1.tail=2,3...
}
//小哈手上有6张牌
for(i=1;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];//小哼出一张牌,q1.data[1]
//判断小哼当前打出的牌是否能赢牌
if(book[t]==0)//如果桌面上没有为t的牌
{
//桌面上没有为t的牌,说明小哼此轮没有赢牌
q1.head++;//小哼打出一张牌,那么这张牌就出列
s.top++;//桌面上多出一张牌,s.top=1
s.data[s.top]=t;//s.data[1]=t,将小哼打出的一张牌放到桌上,入栈
book[t]=1;//标记桌面上此时已有牌面为t的牌
}
else
{
//小哼此轮可以赢0
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--;//栈中少了一张牌,所以栈顶减1
}
//收回桌面上牌面为t的牌
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(q2.head==q2.tail)
{
printf("小哼win\n");
printf("小哼当前手中的牌是");
for(i=q1.head;i<=q1.tail-1;i++)
printf(" %d",q1.data[i]);
if(s.top>0)
{
printf("\n桌上的牌是");
for(i=1;i<=s.top;i++)
printf(" %d",s.data[i]);
}
else
printf("\n桌上已经没有牌了");
}
else
{
printf("小哈win\n");
printf("小哈当前手中的牌是");
for(i=q2.head;i<=q2.tail-1;i++)
printf(" %d",q2.data[i]);
if(s.top>0)
{
printf("\n桌上的牌是");
for(i=1;i<=s.top;i++)
printf(" %d",s.data[i]);
}
else
printf("\n桌面上已经没有牌了");
}
getchar();getchar();
return 0;
}
。。。好长的难代码,自己一下子写也写不出来,这就是就是计算机模拟过程,之前涉足数模的时候,老师说要给一个模型就能用程序写出来,我说我不能。。一个软工的学生,多多少少得学点编程到时候还能混口饭的。。虽然数模是个水比赛,代码大部分也是copy,,,但是我发现了计算机模拟过程是我一点都不会的。。。
结束
分割线
=============================================================
判断每个人打出一张牌之后能否赢牌,可以通过枚举桌上的每一张牌来实现,用for循环来依次判断桌上的每一张牌是否与打出的牌相等。
上述代码通过用一个数组来记录桌上有哪些牌
因为牌面只有1~9,所以开一个大小为10的数组来记录当前桌上已经有哪些牌面。
book[10]
没有赢牌时和赢牌时代码区别:
未赢牌时:
if(book[t]==0)
{
q.head++;//打出一张牌,所以将打出的牌出列
s.top++;//桌面上多出一张牌
s.data[s.top]=t;//s.top是指向栈顶的变量
}
赢牌时:
//赢牌
else//book[t]==1
{
q.head++;//打出一张牌,将打出的牌出列
q.data[q.tail]=t;//已经确定能赢牌,所以就将这张牌直接放到队尾,即放到自己手中牌的末尾
q.tail++;
while(s.data[s.top]!=t)//桌上和自己打的牌不一样的牌
{
book[s.data[s.top]]=0;//因为牌要取走,所以就取消标记
q.data[q.tail]=s.data[s.top];//将桌上那些牌依次放入自己手中牌之后
q.tail++;
s.top--;//桌面上少了1张牌
}
//收回桌面上为t的牌
book[s.data[s.top]]=0;//取消标记
q.data[q.tail]=s.data[s.top];
q.tail++;
s.top--;
}
再次回看题目,程序模拟过程对应实际游戏过程
* 出牌——>出队列
*桌面上多一张牌——>栈顶+1
*桌上少一张牌——>栈顶-1
*赢牌时,先将打出的牌立即放到自己手中牌的最后,然后将桌面上牌和自己手中不一样的收回手中,依次放到自己手中末尾
*最后再将桌上的和自己手中一样的牌收了,放入手中牌最后
=============================================================
真的结束,有补充再说吧