C++ STL练习(1)

说明:题目节选自《算法竞赛入门经典》(第二版),仅为了练习使用,跟着书中手敲代码,并添加自己的理解,仅此记录,我始终相信,当你开始不懂许多东西的时候,跟着书中弄懂作者的写的代码的思路,照着敲出来,敲多了,明白许多原理了,还有你会为了看懂它,查很多资料,然后当自己面对新的问题,脑子就有的调用了

备注:1.个人更喜欢C++,对于作者书中的沿用了C语言的部分,我会改成C++实现,如果涉及到效率问题,请参考原书

           2.我会采用自己的命名习惯,以及添加注释,原书中的代码是针对竞赛的,我写代码是针对实际工程的,工程中变量最好能表明它的含义,以及必要的注释,方便其他人阅读,这也是习惯问题。

题目1:大理石在哪儿

思路:

1.接受用户多个输入,保存下来

2.对保存的数据排序

3.在已排序的数组中查找

代码实现:

#include <iostream>
#include <algorithm>
#include <array>
using namespace std;

const int arrSize = 10000;

int main()
{
	//变量最好在声明时进行初始化
	int marbleNum = 0;    //大理石数量,即非负整数的数量
	int questionNum = 0;  //问题数量
	int integerOfQuestion = 0;   //问题中所问的整数
	int ncase = 0;          //第n波输入

	//array对象会进行默认初始化吗?
	array<int,arrSize>   saveArray;   //保存非负整数的数组
	while((cin>>marbleNum>>questionNum) && marbleNum !=0)
		//对while循环中cin解释:
		//要保证有大理石,不然循环内的执行没有意义
	{
		cout<<"CASE# "<<++ncase<<endl;
		//输入n个"大理石非负整数“
		for(int i=0;i < marbleNum;i++)
			cin>>saveArray[i];

		//对输入的”大理石整数“进行排序
		//sort的用法总结,以及这里的迭代器解释见代码后解释
		sort(saveArray.begin(),saveArray.begin()+marbleNum);

		//回答Q个问题
		while(questionNum--)
		{
			//输入问题中要问的整数
			cin>>integerOfQuestion;
			//在数组中查找等于integerOfQuestion
			//为什么最后要减去saveArray.begin()?
			int intLocation = lower_bound(saveArray.begin(),saveArray.begin()+marbleNum,integerOfQuestion)-saveArray.begin();
			//此时我们需要判断是否找到的是等于integerOfQuestion的数,
			//因为lower_bound函数返回的是第一个大于或等于integerOfQuestion的位置,详细见下面解释
			if(saveArray[intLocation] == integerOfQuestion)
				cout<<integerOfQuestion<<" found at "<< intLocation+1<<endl;   //题目中要求返回的是从1开始的位置,所以+1
			else
				cout<<integerOfQuestion<<" not found"<<endl;
		}
	}
}

eclipse下运行截图:

扫描二维码关注公众号,回复: 4182173 查看本文章

知识点详细用法补充:待补充

1.while下的cin

2.sort()函数和对应迭代器的使用

3.low_bound()函数

题目2:木块问题

且原题假设输入中,0<n<25

思路:

实现四个操作即可

1.可以看到该四个操作有公共的部分,我们可以提取出来写成函数,达到复用的效果

        可以看到四个操作有重复的部分:归位木块,移动一个木块到另一个木块堆的顶部,移动一摞木块到另一个木块所在木块堆的顶部上,虽然归位本质也是移动,由于移动函数包括移动本身,而归位函数不包括移动本身,所以需要分开写

       (1)归位函数:把某个木块上方的木块全部归位,输入:要归位的

      (2)移动一个木块:输入:要移动的木块        输出:目标木块

      (3)移动一摞木块:输入:要移动的一摞木块的起始木块        输出:目标木块

2.封装四个操作

3.在主函数里获取用户输入,用case选择相应操作

4.最后打印每个位置的木块列表

代码实现:

#include <iostream>
#include <vector>
#include <string>

using namespace std;
//函数声明
void back_above(int numOfBlock);
void moveOneBlock(int numMoveBlock,int numTargetBlock);
int findPile(int numOfBlock);
void moveBlocks(int beginMoveBlock,int numTargetBlock);
void print();
void moveOnto(int moveBlock,int targetBlock);
void moveOver(int moveBlock,int targetBlock);
void pileOnto(int moveBlock,int targetBlock);
void pileOver(int moveBlock,int targetBlock);

//因为0<n<25,所以我们让位置数组的长度为25
const int arrSize=25;
//用户输入的木块堆的个数
int input;
//定义一个每个元素为vector的数组,使用数组来代表每个位置,即pile[i]代表每个木块堆
//然后每个位置为vector,用于保存木块序号,因为移动让该位置的保存数据的数据结构不断变化,所以我们选用vector来保存
vector<int> pile[arrSize];

//归位函数:把某个木块上方的木块全部归位,输入:要归位的木块编号
//查找用户输入的木块编号的时间复杂度为O(n)
void back_above(int numOfBlock)
{
	//循环遍历用户输入的n个木块堆
	for(int i=0;i < input;i++)
	{
		//遍历一个木块堆中的木块
		for(vector<int>::iterator it = pile[i].begin();it != pile[i].end();it++)
		{
			//如果找到了用户输入的木块
			if(*it == numOfBlock)
			{
				//从后遍历木块,将每个木块插入到编号为它的木块堆中,并将它从现在的木块堆中删除
				for(vector<int>::iterator iter = pile[i].end()-1;iter != it;iter--)
				{
					pile[*iter].push_back(*iter);
					pile[i].pop_back();
					//疑问:pop_back()会不会释放弹出元素原来所占的内存空间
				}
				break;
			}
		}
	}
}
//移动一个木块:输入:要移动的木块        输出:目标木块   且要移动的木块上面已没有任何木块
void moveOneBlock(int numMoveBlock,int numTargetBlock)
{
	//定义两个变量保存要移动木块和目标木块所在堆
	int moveAtPile=findPile(numMoveBlock);
	int targetAtPile=findPile(numTargetBlock);
	//移动木块
	pile[targetAtPile].push_back(numMoveBlock);
	pile[moveAtPile].pop_back();
}

//找木块编号对应的木块堆的函数
int findPile(int numOfBlock)
{
	//定义一个变量保存木块所在堆
	int atPile=0;
	//循环遍历木块堆找到要移动木块和目标木块所在堆
	for(int i=0;i < input;i++)
	{
		//遍历一个木块堆中的木块
		for(vector<int>::iterator it = pile[i].begin();it != pile[i].end();it++)
		{
			//如果找到了要移动的木块
			if(*it == numOfBlock)
			{
				atPile = i;
				return atPile;
			}
		}
	}
	return atPile;
}
//移动一摞木块:输入:要移动的一摞木块的起始木块        输出:目标木块
//      找到要移动木块和目标木块所在的堆
//      从要移动木块所在堆找要移动木块所在的位置
//      从要移动的木块开始移动到目标木块所在堆
void moveBlocks(int beginMoveBlock,int numTargetBlock)
{
	//找到要移动木块和目标木块所在的堆
	int moveAtPile=findPile(beginMoveBlock);
	int targetAtPile=findPile(numTargetBlock);
	for(vector<int>::iterator it = pile[moveAtPile].begin();it != pile[moveAtPile].end();it++)
	{
		if(*it == beginMoveBlock)
		{
			for(vector<int>::iterator iter = it;iter != pile[moveAtPile].end();it++)
			{
				pile[targetAtPile].push_back(*it);
			}

			for(vector<int>::iterator iter = it;iter != pile[moveAtPile].end();it++)
			{
				pile[moveAtPile].pop_back();
			}
		}
	}
}

//打印结果列表
void print()
{
	for(int i=0; i < input;i++)
	{
		cout<<i<<":";
		for(int j=0;j < pile[i].size();j++)
		{
			cout<<" "<<pile[i][j]<<endl;
		}
	}
}

//封装四个操作
void moveOnto(int moveBlock,int targetBlock)
{
	//将a和b上方的木块全部归位
	back_above(moveBlock);
	back_above(targetBlock);
	//把a摞到b上
	moveOneBlock(moveBlock,targetBlock);
}

void moveOver(int moveBlock,int targetBlock)
{
	//将a上方的木块全部归位
	back_above(moveBlock);
	//把a放在b所在木块堆的顶部
	moveOneBlock(moveBlock,targetBlock);
}

void pileOnto(int moveBlock,int targetBlock)
{
	//将b上方的木块全部归位
	back_above(targetBlock);
	//把a以及上面的木块整体摞在b上面
	moveBlocks(moveBlock,targetBlock);
}

void pileOver(int moveBlock,int targetBlock)
{
	//把a以及上面的木块整体摞在b所在木块堆的顶部
	moveBlocks(moveBlock,targetBlock);
}
int main()
{

	cout<<"请输入木块堆的数目:"<<endl;
	cin>>input;
}

elipse下运行结果:

未写完测试函数,待补充

经验总结:

题目3:安迪的第一个字典

思路:

找出不同的单词,并且进行排序,这就自然想到要用set

先获取到用户输入的文本串,再进行处理

将非法字符转化成空格,由于题目要忽略大小写,我们将所有字符都转化为小写

再插入set进行自动排序

将set中保存的单词打印出来即可

代码实现:

#include <iostream>
#include <string>
#include <set>
#include <sstream>
using namespace std;
//定义一个集合来保存每个单词
set<string> saveWord;
int main() {
	string inputText;//用户输入的文本串
	string wordBuffer;//用于sstream流分离单词时接受每个单词
	//获取用户的输入的文本,直到遇到文件结束符或非法输入为止
	while(cin >> inputText)
	{
		//遍历用户输入的文本字符串
		for(unsigned int i=0;i < inputText.length();i++)
		{
			//如果是字母,转换为小写
			if(isalpha(inputText[i]))
				inputText[i] = tolower(inputText[i]);
			else //不是字母,就是其他字符,转换成空格
				inputText[i] = ' ';  //刚开始输入的是“ ”,报错,因为inputText本身是字符串,对它使用[]运算符返回的是字符,所以只能用‘’
		}
		//用stringstream将文本串分割成单个单词
		//原理见补充部分
		stringstream word(inputText);
		while(word >> wordBuffer)
		{//将单个单词插入集合中
			saveWord.insert(wordBuffer);
		}
	}
	//打印set集合中顺序保存的字符串
	for(set<string>::iterator it=saveWord.begin();it != saveWord.end();it++)
		cout<<*it<<endl;
}

eclipse下运行效果图:

知识点详细用法补充:待补充

1.isalpha()

2.tolower()

3.stringstream()

猜你喜欢

转载自blog.csdn.net/qq_34805255/article/details/84098831