《啊哈!算法》笔记_Day02

这篇先写前三节,下一篇在把这一张剩下的写完

第一节 解密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哟,让我们一起加油吖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朋友叫我小马

不需要打赏哟!谢谢阅读!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值