桌上有一叠牌,从第一张牌(即位于顶面的牌)开始从上往下依次编号为1~n;当至少还剩两张牌时进行以下操作:把第一张牌扔掉,然后把新的第一张放到整叠牌的最后。输入n,输出每次扔掉的牌。
样例输入:
7
样例输出:
1 3 5 7 4 2 6
1 #include <stdio.h> 2 int queue[500]; 3 int main() 4 { 5 int i, n, front, rear; //n<=strlen(queue)/2 6 scanf("%d", &n); 7 for(i = 0; i < n; i++) 8 queue[i] = i+1; //初始化队列 9 front = 0; //队首元素的位置 10 rear = n; //队尾元素的后一个位置 11 while(front < rear) //当队列非空 12 { 13 printf("%d ", queue[front++]); //输出并抛弃队首元素 14 queue[rear++] = queue[front++]; //队首元素转移到队尾 15 } 16 return 0; 17 }
分析:
1.队列:每次从排头拿到两个,其中第二个再排到尾部;这种数据结构称为队列(queue),或FIFO表。其中FIFO表示先进先出(First In,First Out),符合日常生活中的排队。
2.用一个数组queue来实现这个队列,再设两个指针front和rear。尽管运行结果没错,但如果在最后把rear的值打印出来,rear会比n大(恰好是2n)。换言之,在程序运行的后期,queue[rear++]=queue[front++]读写了非法内存(读写非法内存不一定导致程序崩溃)!因此要么把数组空间开大些;要么采用一种称为循环队列的技术,重用已出队元素占用的空间。
C++提供了一种更加简单的处理方式—STL队列:
1 #include <cstdio> 2 #include <queue> 3 using namespace std; 4 queue<int> q; 5 int main() 6 { 7 int i, n; 8 scanf("%d", &n); 9 for(i = 0; i < n; i++) 10 q.push(i+1); //初始化队列 11 while(!q.empty()) //当队列非空 12 { 13 printf("%d ", q.front()); //打印队首元素 14 q.pop(); //抛弃队首元素 15 q.push(q.front()); //把新的队首元素加入队列 16 q.pop(); //抛弃队首元素 17 } 18 return 0; 19 }
分析:
1.该程序代码并没有简洁很多,但可读性大大增强:一方面体现在“queue”、“rear”这些望文知义的命名,另一方面体现在STL库的标准性(它是C++不可分割的组成部分)。
2.减少魔术数(majic number),即不需要事先知道n的大小;减少变量个数(少用了两个变量front和rear)都是提高代码可读性,减少错误可能性的重要手段。