桌上有叠牌,从第一张牌(即位于顶面的牌)开始从上往下依次编号为1~n。当至少还剩两张牌时进行以下操作:把第一张牌扔掉,然后把新的第一张放一整叠牌的最后。输入n,输出每次扔掉的牌,以及最后剩下的牌。
样例输入:7
样例输出:1 3 5 74 2 6
【分析】
本题中牌像在排队。每次从排头拿到两个,其中第二个再次排到尾部。这种数据结构称为队列。在数据结构称为FIFO(First in First out,先进先出)表。
用一个数组queue来实现这个队列,可设两个指针front和rear。
完整的程序如下:
#include<stdio.h> constint MAXN = 50; int queue[MAXN]; intmain() { int n,front, rear; scanf("%d", &n); for(int i = 0; i < n; i++) queue[i] = i+1; //初始化队列 front = 0; //队首元素的位置 rear = n; //队尾元素的后一个位置 while(front< rear) { //当队列非空 printf("%d ", queue[front++]); //输出并抛弃队首元素 queue[rear++]= queue[front++]; //队首元素转移到队尾 } return 0; }
注意:上面的程序有bug。如果在最后把rear的值打印出来,rear比n大。即在程序运行的后期,queue[rear++]=queue[front++]读写了非法内存。也可以采取将数组空间开大些,或采取一种称为循环队列的技术,重用已出队元素占用的空间。
C++提供了一种更加简单的处理方式——STL队列。下面是代码:
#include<cstdio> #include <queue> usingnamespace std; queue<int> q; intmain() { int n, front, rear; scanf("%d", &n); for(int i = 0; i < n; i++) q.push(i+1); //初始化队列 while(!q.empty()){ //当队列非空 printf("%d ", q.front()); //打印队首元素 q.pop(); //抛弃队首元素 q.push(q.front()); //把队首元素加入队尾 q.pop(); //抛弃队首元素 } return 0; }
上面的程序的可读性大大增强了,体现在“queue”、“front”见名知义的命名,使用了C++ STL。除此之外,上面的代码还有两个附加的好处。首先,不需要事先知道n的大小;其次,可以少用两个变量front和rear。减少魔术数(magicnumber)和变量个数都是提高代码可读性、减少错误可能性的重要手段。
说明:(1)在ACM竞赛中,需要用到数组、字符串、队列、堆栈、链表、平衡二叉检索树等数据结构和排序、搜索等算法,以提高程序的时间、空间运行效率,这些数据结构,如果需要手工来编写,那是相当麻烦的事情。
(2)ANSI C++中包含了一个C++ STL(Standard Template Library),即C++标准模板库,又称为C++泛型库,它在std命名空间中定义了常用的数据结构和算法,使用起来十分方便。
(3)C++ STL组件
STL组件三种类型的组件:容器、迭代器和算法,它们都支持泛型程序设计标准。
容器主要有两类:顺序容器和关联容器。顺序容器(vector、list、queue、string等)一系列元素的有序集合。关联容器(set、multiset、map和mulimap)包含查找元素的键值。
迭代器的作用是遍历容器。
STL算法库包含四类算法:排序算法、不可变序算法、变序性算法和数值算法。
(4)queue队列容器
queue队列容器是一个先进先出(First In First Out,FIFO)线性存储表,元素的插入只能在队尾、元素的删除只能在队首。
使用queue需要声明头文件包含语句“#include <queue>”,queue文件在C:Program
FilesMicrosoft Visual StudioVC98Include文件夹里。
queue队列的操作有入队push()(即插入元素)、出队pop()(即删除元素)、读取队首元素front()、读取队尾元素back()、判断队列是否为空empty()和队列当前元素的数目size()。
下面给出一个程序来说明queue队列的使用方法。
#include<iostream> #include<queue> usingnamespace std; intmain() { //定义队列,元素类型是整型 queue<int>q; //入队,即插入元素 q.push(1); q.push(2); q.push(3); q.push(9); //返回队列元素数量 cout<<q.size()<<endl; //队列是否为空,是空,则返回逻辑真,否则返回逻辑假 cout<<q.empty()<<endl; //读取队首元素 cout<<q.front()<<endl; //读取队尾元素 cout<<q.back()<<endl; //所有元素出列(删除所有元素) while(q.empty()!=true){ cout<<q.front()<<""; //队首元素出队(删除队首元素) q.pop(); } //回车换行 cout<<endl; return 0; }
运行结果:
4
0
1
9
1 2 3 9