查找学生信息 - 九度教程第18题

查找学生信息 - 九度教程第18题

题目

时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
输入N个学生的信息,然后进行查询。
输入:
输入的第一行为N,即学生的个数(N<=1000)
接下来的N行包括N个学生的信息,信息格式如下:
01 李江 男 21
02 刘唐 男 23
03 张军 男 19
04 王娜 女 19
然后输入一个M(M<=10000),接下来会有M行,代表M次查询,每行输入一个学号,格式如下:
02
03
01
04
输出:
输出M行,每行包括一个对应于查询的学生的信息。
如果没有对应的学生信息,则输出“No Answer!”
样例输入:
4
01 李江 男 21
02 刘唐 男 23
03 张军 男 19
04 王娜 女 19
5
02
03
01
04
03
样例输出:
02 刘唐 男 23
03 张军 男 19
01 李江 男 21
04 王娜 女 19
03 张军 男 19
来源:
2003年清华大学计算机研究生机试真题

若依旧采用每次询问时线性遍历数组来查找是否存在我们需要查找的元素,那么,该算法的时间复杂度达到了O(n * m)(查找次数 * 每次查找所需比较的个数),而这已经达到了千万数量级。

#include 
#include 

struct Student{
    char num[10];
    char name[10];
    char sex[10];
    int age;
};

int main()
{
    int n,m;
    while(scanf("%d",&n)!=EOF){
        Student student[n];
        for(int i=0;i

用二分查找查找长度为L的有序数组,时间复杂度可由原本线性查找的O(L)降低到O(logL)。为了符合查找空间单调有序的要求,首先要对所有数组元素按照学号关键字升序排列。当数组内各元素已经升序有序时,就可以在每次询问某个特定学号的学生是否存在时,使用二分查找来查找该学生。

#include 
#include 
#include 

using namespace std;

struct Student{ //用于表示学生个体的结构体
    char no[100]; //学号
    char name[100]; //姓名
    int age; //年龄
    char sex[5]; //性别
    bool operator < (const Student & A) const { //重载小于运算符使其能使用sort函数排序
        return strcmp(no,A.no) < 0;
    }
}buf[1000];

int main () {
    int n;
    while (scanf ("%d",&n) != EOF) {
        for (int i = 0;i < n;i ++) {
            scanf ("%s%s%s%d",buf[i].no,buf[i].name,buf[i].sex,&buf[i].age);
        } //输入
        sort(buf,buf + n); //对数组排序使其按照学号升序排列
        int t;
        scanf ("%d",&t); //有t组询问
        while (t -- != 0) { //while循环保证查询次数为t
            int ans = -1; //目标元素下标,初始化为-1
            char x[30];
            scanf ("%s",x); //待查找学号
            int top = n - 1,base = 0; //初始时,开始下标0,结束下标n-1,查找子集为整个数组
            while(top >= base) { //当查找子集不为空集时重复二分查找
                int mid = (top + base) / 2; //计算中间点下标
                int tmp = strcmp(buf[mid].no,x); //比较中间点学号与目标学号
                if (tmp == 0) {
                    ans = mid;
                    break; //若相等,则查找完成跳出二分查找
                }
                else if (tmp > 0) top = mid - 1; // 若大于,则结束下标变为中间点前一个点下标
                else base = mid + 1; //若小于,则开始点下标变为中间点后一个点坐标
            }
            if (ans == -1) { //若查找失败
                printf("No Answer!\n");
            }
            else printf("%s %s %s %d\n",buf[ans].no,buf[ans].name,buf[ans].sex,buf[ans].age); //若查找成功
        }
    }
    return 0;
}

利用二分查找,原本O(n * m)的时间复杂度被优化到O(nlogn(排序) + m * logn),而该复杂度是符合要求。

补充

在一个升序有序的数组中,确定一个下标点,使在这个下标点之前(包括该下标点)的数字均小于等于目标数字(该目标数字一定大于等于数组中最小的数字),而数组的其余部分均大于目标数字,如何编写程序。

//存在一个升序有序的数组buf,其大小为size,目标数字为target
int base = 0 , top = size; //初始情况与二分查找一致
while (base <= top) { //二分循环条件与二分查找一致
	int mid = (base + top) / 2;
	if (buf[mid] <= target) base = mid + 1; //符合前一部分数字规定
	else top = mid - 1; //否则
}
int ans = top; //最后,top即为要求的数字数组下标,buf[top]为该数字本身

你可能感兴趣的:(九度OJ)