这篇先写前三节,下一篇在把这一张剩下的写完
第2章 栈、队列、链表
第一节 解密QQ号——队列
这一节通过解密一个QQ号来引入队列,解密这个QQ号的方法是首先将第1个数删除,紧接着将第2个数放到这串数的末尾,再将第3个数删除并将第4个数放到这串数的末尾,再将第5个数删除……知道剩下最后一个数,将最后一个属也删除。按照刚才删除的顺序,把这些删除的数连在一起就是小哈的QQ。
队列有两个变量,两个整型变量head和tail。head记录队列的队首(即第一位),tail用来记录队列的队尾(即最后一位)的下一个位置。
注意:head指向的是第一位,但tail指向的却不是最后一位,而是最后一位的下一位,因为当队列只剩下一个元素时,head和tail会重合,会带来麻烦。
队首和队尾重合时,队列为空。
删除一个数:head++
增加一个属:q[tail]=num;tail++;
书中将数组的0号元素赋值为0,即将0号元素去除,从1号开始,方便计数,且将数组定义为102个,这里我将代码稍稍改动。
#include <stdio.h>
int main()
{
int q[20]={6,3,1,7,5,8,9,2,4},head,tail;
int i;
//初始化队列
head=0;
tail=9; //队列中已经有9个元素了,tail指向队尾的后一个位置
while(head<tail) //当队列不为空的时候执行循环
{
//打印队首并将队首出队
printf("%d ",q[head]);
head++;
//先将新队首的数添加到队尾
q[tail]=q[head];
tail++;
//再将队首出队
head++;
}
getchar();getchar();
return 0;
}
队列时一种特殊的线性结构,只允许在队列的首部(head)进行删除操作,称为“出队”;而在队列的尾部(tail)进行插入操作,称为“入队”。当队列中没有元素时(head==tail),称为空队列。
队列,先进先出(First In First Out,FIFO)
将队列的三个基本元素(一个数组,两个变量)封装为一个结构体类型,代码如下:
struct queue
{
int data[100];//队列的主体,用来存储内容
int head;//队首
int tail;//队尾
};
//定义结构体类型,通常将其放在main函数的外面
//注意结构体的定义末尾有个;
//
定义结构体变量:
struct queue q;
//struct queque 是一个整体,不能直接写queque q;
//使用成员运算符(点号运算符)来访问结构体变量的成员
下面是完整的使用结构体来实现的队列操作。
#include <stdio.h>
struct queue
{
int data[100];//队列的主体,用来存储内容
int head;//队首
int tail;//队尾
};
int main()
{
struct queue q;
int i;
//初始化队列
q.head=0;
q.tail=0;
for(i=1;i<=9;i++)
{
//依次向队列插入9个数
scanf("%d",&q.data[q.tail]);
q.tail++;
}
while(q.head<q.tail) //当队列不为空的时候执行循环
{
//打印队首并将队首出队
printf("%d ",q.data[q.head]);
q.head++;
//先将新队首的数添加到队尾
q.data[q.tail]=q.data[q.head];
q.tail++;
//再将队首出队
q.head++;
}
getchar();getchar();
return 0;
}
第二节 解密回文——栈
本节通过判断是否是回文来引入栈的概念,判断回文的方法,先将要判断的字符前一半如栈,然后当前栈的字符依次出栈,看能否与后一半字符依次匹配,匹配即回文。
栈:后进后出,只能在一端进行插入和删除操作。
栈只需要一个一维数组和一个指向顶栈的变量top,通过top来对栈进行插入和删除操作。
因为top指向的是当前栈顶的变量,所以进栈的代码是:
s[++top]=a[i];
//先将top指向下一个位置,然后赋值
下面是书中判断是否回文的代码:
#include <stdio.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");
else
printf("NO");
getchar();getchar();
return 0;
}
堆栈最早由 Alan M. Turing(艾伦·图灵)于 1946 年提出,当时是为了解决子程序的调用和返回。艾伦·图灵这个大帅哥可是个大牛人,图灵奖就是以他的名字命名的。如果你对他感兴趣不妨去读一读《艾伦·图灵传:如谜的解谜者》和《图灵的秘密》。
第三节 纸牌游戏——小猫钓鱼
本节是由我们小时候玩的游戏,小猫钓鱼引入,这个游戏大概就是两个人一人一摞纸牌,按照一定顺序,往上放牌,如果与之前放过的牌一致,就可以把这两张牌之间的牌拿走(包括这两张牌本身)放到自己手中牌的后面,最后手里没有牌的一方为输。
这个游戏相信大家小时候都玩过,但是用代码来模拟这个游戏怎么实现呢,让我们来看一下吧:
#include <stdio.h>
struct queue
{
int data[1000];
int head;
int tail;
};
struct stack
{
int data[10];
int top;
};
int main()
{
struct queue q1,q2;
struct stack s;
int book[10];
int i,t;
//初始化队列
q1.head=1; q1.tail=1;
q2.head=1; q2.tail=1;
//初始化栈
s.top=0;
//初始化用来标记的数组,用来标记哪些牌已经在桌上
for(i=1;i<=9;i++)
book[i]=0;
//依次向队列插入6个数
//小哼手上的6张牌
for(i=1;i<=6;i++)
{
scanf("%d",&q1.data[q1.tail]);
q1.tail++;
}
//小哈手上的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];//小哼出一张牌
//判断小哼当前打出的牌是否能赢牌
if(book[t]==0) //表明桌上没有牌面为t的牌
{
//小哼此轮没有赢牌
q1.head++; //小哼已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
book[t]=1; //标记桌上现在已经有牌面为t的牌
}
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--; //栈中少了一张牌,所以栈顶要减1
}
}
t=q2.data[q2.head]; //小哈出一张牌
//判断小哈当前打出的牌是否能赢牌
if(book[t]==0) //表明桌上没有牌面为t的牌
{
//小哈此轮没有赢牌
q2.head++; //小哈已经打出一张牌,所以要把打出的牌出队
s.top++;
s.data[s.top]=t; //再把打出的牌放到桌上,即入栈
book[t]=1; //标记桌上现在已经有牌面为t的牌
}
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--;
}
}
}
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;
}
最后来个个人小总结吧:
1.队列:先进先出(后进后出),需要三个变量,一个数组(用来存放数据),一个head变量(记录队列的队首),一个tail变量(记录队列的队尾的下一个位置)
2.栈:后进先出(先进后出),需要两个变量,一个数组(用来存放数据),一个top变量(指向栈顶)
谢谢你的坚持阅读ovo哟,让我们一起加油吖