牛客网解题-在线编程-2017网易有道_构造队列

来源:互联网 发布:java业务监控系统 编辑:程序博客网 时间:2024/05/18 18:17


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,以下已修正]

  • 输入描述
第一行一个整数TT100)表示数据组数,每组数据输入一个数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. 总结

  • 变量作为函数参数传递且需要进行修改

    • 像程序中的headtail变量

    • 因为QueueReconstruct执行完需要使用修改后的head和tail来输出数据,所以设置为指针形式

      • C语言中没有引用,所以这里不能使用引用,在C++中可以设置为QueueReconstruct(….,int &head, int &tail)的引用形式
  • 变量的作用域简单总结:C语言中的存储类型有externstaticautoregister四种类型

    • 全局变量

      • 一个在所有函数之外定义的变量
      • 作用域:整个源程序
      • 存储位置:全局存储区(静态区)或常量区

      • [1] 普通全局变量定义在主程序或头文件中可以在所有源程序中使用,定义在某个源程序中需要通过extern来进行声明使用

      • [2] 通过extern也可在其他源文件中使用

      • [3] 通过static只可以在本程序中使用

    • 局部变量

      • 只在特定函数或过程中可以访问的变量
      • 作用域:仅限于函数体内部
      • 存储位置:普通局部变量存储在栈区,static局部变量存储在静态区

      • [1] static修饰的局部变量,存储位置由栈区变为静态区

      • [2] static可以修饰函数和变量,修饰函数其作用域仅限当前源文件
  • 程序中headtail就是main函数中的局部变量,如果不以指针等形式传入QueueReconstruct函数内,由于在QueueReconstruct函数内的局部变量作用域仅为QueueReconstruct函数本身,则在main函数中head和tail的值没有改变。如int n传入函数后虽然进行n–操作,但QueueReconstruct函数执行完输出仍为原来的取值。



Acknowledgements:
http://m.blog.csdn.net/u010429424/article/details/76947514

2017.08.28

原创粉丝点击