1. 题目
- 题目描述
小明同学把1到n这n个数字按照一定的顺序放入了一个队列Q中。现在他对队列Q执行了如下程序:
while(!Q.empty()) //队列不空,执行循环
{
int x=Q.front(); //取出当前队头的值x
Q.pop(); //弹出当前队头
Q.push(x); //把x放入队尾
x = Q.front(); //取出这时候队头的值
printf("%d\n",x); //输出x
Q.pop(); //弹出这时候的队头
}
做取出队头的值操作的时候,并不弹出当前队头。
小明同学发现,这段程序恰好按顺序输出了1,2,3,…,n。现在小明想让你构造出原始的队列,你能做到吗?
[注:原题样例第三行5有错,应该为3,以下已修正]
- 输入描述
第一行一个整数T(T ≤ 100)表示数据组数,每组数据输入一个数n(1 ≤ n ≤ 100000),输入的所有n之和不超过200000。
- 输出描述
对于每组数据,输出一行,表示原始的队列。数字之间用一个空格隔开,不要在行末输出多余的空格.
示例
输入:
4
1
2
3
10输出:
1
2 1
2 1 3
8 1 6 2 10 3 7 4 9 5
2. 解题思路
原题目的意思:队列中的元素按照“队首元素弹出并放入队尾 -> 队首元素取值输出 -> 队首元素弹出”的步骤进行得到了1,2,…,n的顺序序列。
现需构造原始队列达到此目的。
解题思路:逆向求解。
题目的操作按照如下步骤进行
- (1)原队列(由满到空)队首元素移到队尾
- (2)取出队首元素
- (3)循环n次,放入新队列(由空到满)队尾得到输出
所以可按照如下步骤得到原队列
- (1)循环取出新队列(由满到空)队尾元素n->n-1->n-2…
- (2)放入原队列(由空到满)队首
- (3)将原队列队尾元素移到队首
元素分布还呈现如下特点
- 第一遍:在1,3,5…位置放入1,2,3…等数
- 第二遍:去掉第一遍放入的数,依然每隔一个位置继续放入一个数
- 重复直至放满整个数组。
3. 代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//原始数组构造函数(类队列)
void QueueReconstruct(int n, int *queue, int *newQueue, int *head, int *tail)
{
int data, temp, i = n;
while (n > 0)
{
data = queue[n - 1];
//放入队列head
if (i == n)
{
newQueue[*tail] = data;
}
else
{
newQueue[*head] = data;
(*head)++;
//tail元素放到head
temp = newQueue[*tail];
newQueue[*tail] = newQueue[*head];
newQueue[*head] = temp;
}
//tail指针变化
if (i == n)
{
(*head)++;
n--;
continue;
}
else
{
(*head)++;
(*tail)++;
n--;
}
}
return;
}
int main()
{
int queue1[100000], queue2[300000];
memset(queue2, 0, sizeof(queue2));
int n, T;
//输入组数T
scanf("%d", &T);
while (T--)
{
//输入每行数n
scanf("%d",&n);
int i = 0, j = 0;
//每行对应的数组
for (; i < n; i++)
{
queue1[i] = i + 1;
}
//调用队列重建函数
int head = 0, tail = 0;
QueueReconstruct(n, queue1, queue2, &head, &tail);
//结果输出
for (j = head - 1; j >= tail; j--)
{
printf("%d%c",queue2[j],j == tail ? '\n' : ' ');
}
}
return 0;
}
运行时间:47ms
占用内存:2804K
4. 总结
变量作为函数参数传递且需要进行修改
像程序中的head和tail变量
因为QueueReconstruct执行完需要使用修改后的head和tail来输出数据,所以设置为指针形式
- C语言中没有引用,所以这里不能使用引用,在C++中可以设置为QueueReconstruct(….,int &head, int &tail)的引用形式
变量的作用域简单总结:C语言中的存储类型有extern,static,auto,register四种类型
全局变量
- 一个在所有函数之外定义的变量
- 作用域:整个源程序
存储位置:全局存储区(静态区)或常量区
[1] 普通全局变量定义在主程序或头文件中可以在所有源程序中使用,定义在某个源程序中需要通过extern来进行声明使用
[2] 通过extern也可在其他源文件中使用
[3] 通过static只可以在本程序中使用
局部变量
- 只在特定函数或过程中可以访问的变量
- 作用域:仅限于函数体内部
存储位置:普通局部变量存储在栈区,static局部变量存储在静态区
[1] static修饰的局部变量,存储位置由栈区变为静态区
- [2] static可以修饰函数和变量,修饰函数其作用域仅限当前源文件
程序中head和tail就是main函数中的局部变量,如果不以指针等形式传入QueueReconstruct函数内,由于在QueueReconstruct函数内的局部变量作用域仅为QueueReconstruct函数本身,则在main函数中head和tail的值没有改变。如int n传入函数后虽然进行n–操作,但QueueReconstruct函数执行完输出仍为原来的取值。
Acknowledgements:
http://m.blog.csdn.net/u010429424/article/details/76947514
2017.08.28