前言
师弟: “经过几轮优化之后,我的学生成绩管理系统,感觉已经非常不错了,是我学习以来做的最好的系统了。没想到,还是被嘲笑了。”
我:“怎么被嘲笑了?”
师弟:“程夏她说: 你在录入学生的时候,id是增序录入的,在查询的时候,就不能高效一点查询,不去遍历整个数据?”
我:“确定这个女生不是我们计算机系的?”
师弟:“的确不是我们计算机系的呢。”
我:“那人家学习的速度和你相比,像是龟兔赛跑呀。”
看师弟有点难受,我:“干嘛这么惆怅,谁笑的开心还不一定呢。在讲二分查找之前,讲个故事吧。”
龟兔赛跑
乌龟小龟情不自禁的喜欢上了兔子小兔,然后就展开自己快速的步伐,去追小兔,可是小兔的速度太快了,小龟怎么也追不上,小龟爬啊爬,爬啊爬,历经了千山万水,日升日落,春去秋来,小兔的影子都没有看到。
这一天黄昏时分,小龟累了,停留了一下脚步。这个时候,金黄的阳光照射过来,绚丽而灿烂,小龟沉醉在其中,忘记了心中所想,感觉身上满满的都是幸福,闭上了眼睛,尽情的享受着这份快乐。
“你放弃吧。”小龟被一声话语惊醒,本来很生气的小龟,瞬间变得不生气了,替换的更多的是内心的喜悦。因为说话的是小兔,自己满心喜欢和期待的小兔啊。
小龟倔强的回道:“不,我绝不放弃。”但是坚定的说完了以后,小龟内心产生了一个疑问。“真的是决不放弃吗?我能够追的上吗?”疑问很快就被小龟否定了。
“那好吧,你那么笨,既然想追,你就追吧,只要你能够追上我的步伐,那我就可以考虑和你在一起。”说完以后,还没等小龟反应,就已经绝尘而去。
看着小兔远去的背影,夹杂着激起的灰尘,小龟喜中也参含着忧。高兴的是自己有机会,不开心的是自己似乎又没有机会。
小龟重新整理了一下背上的行囊,上路了。目标很明确:追上小兔。
这一年在风吹雨打中过去了。
小龟犹豫了。“我真的能够追上小兔吗?就我这种速度,就我这么笨拙。或许我根本就不适合。或许我该重新认识一下现实,接受现实。”
就在小龟自我否定的时候,不知不觉来到了一个寺庙的门口。门口坐着两个和尚。一个和尚胖胖的,满脸的赘肉,看似很富裕的样子。另一个和尚,有点沧桑,略显消瘦,但是精神饱满。胖和尚惊讶的听着瘦和尚讲述着他去南海的经历。
原来一年前,瘦和尚说道:自己想去南海看看。胖和尚就笑话他,说自己多年前就开始攒钱,常常想着买船,顺江而下,去南海游历一番,可是没有实现,你这么穷,凭什么啊。没想到的是,这个瘦和尚竟然从南海游历回来了。胖和尚没有成功,瘦和尚竟然成功了。
小龟看着瘦和尚的面庞,不知道为什么感觉大受鼓舞,向他拜了拜。“天下事有难易乎?为之则难者亦易矣,不为则易者亦难矣。”小龟轻快的唱着歌就又重新出发了,扫去了之前的不快。
又是一年,伴随着风雨度过。
看着北归的大雁,小龟不知不觉中牵动了归家的情思,眼泪不自觉的流落了下来。
“枯藤老树昏鸦,小桥流水人家,古道西风瘦马,夕阳西下,断肠人在天涯。”一阵悲怆的诗歌从远处被风吹了过来。小龟沿着声音传来的方向看过去,只见一个身形消瘦的长衫游客,牵着一匹瘦瘦的马。不知道为什么小龟内心中很是凄凉。竟然不自觉的在这里放声大哭起来,很是想念在堂的老龟父母。
父母在,不远游。
“归去来兮!”小龟擦干了眼泪,看着夕阳西下,转过了身,朝家的方向爬去。
归家的路好长啊!小龟没有想到这些年竟然走了这么多的路。
终于,到了一条水边,一条熟悉的水边,小的时候曾经来过的地方。站在水边的高处,可以遥遥望见家乡的方向。
不知道为什么,前段时间日夜紧赶,就是想早点回家,这会快要到家了,反而有些羞涩。难道这是“近乡情更怯”。想想自己当年为爱而行,何尝不是在家乡闹得沸沸扬扬。
小龟长舒了一口气,收回了视线,又踏上了回家的路程。
归家途中经过一片农田,在田边不远处有一个老农,手中攥着一个东西,在焦急的等待,眼神紧紧的盯着田边的一棵树桩。
小龟好奇的走过去,问道:“大伯,你这是在等什么吗?”看清了大伯手中的护手后,小龟心头不禁一震。因为这是小龟在几年前送给小兔的生日礼物,这个护手上面有小兔的名字,他一眼就能够认出。为什么小兔的东西会在这儿呢?还没等大伯回答,小龟继续问道:“大伯,你这手中的手环是哪买的啊?好漂亮啊,我也想买一个。”
大伯晃了晃手中的手环,回道:“你说这个啊,不是我买的,是几天前的那个兔子的。”
小龟心头一紧,“前几天的兔子?她怎么了吗?”
大伯笑道:“她跑的太快,一下子撞死在了这棵树桩上了。瞧,血迹还在这儿呢。我在这儿继续等待,看看还有没有兔子过来,那样的话,我也就不用种庄稼了。”
小龟不知道为什么有点眩晕,终于抑制不住伤心,放声大哭了起来。伤心不止,眼泪顺着眼角就流了出来。
大伯看着大哭的乌龟,感觉默名其妙,转身就走了,嘀咕道:“今天,看样子是没有什么收获了,还是回去吧。”
大伯离开以后,小龟哭的更加伤心了,泪眼模糊中似乎看见了小兔的影子,他不顾一切的冲了上去,一把抱住了她,哭喊着说道:“小兔,你为什么,为什么,为什么这么早就离开了。”
“小龟,你这是干什么?”小兔说道,心中说不出的开心。
小龟听到了这话还没有反应过来,擦了擦眼泪。看了看眼前的小兔,不敢相信自己的眼睛。
“你还活着?”小龟兴奋的叫道。
“我当然还活着了,不然你以为呢!”小兔说道。“那滩血迹,是偷我护手的兔子的。走吧,我们回家。回去给你讲这个故事。”
“回家?”小龟疑惑地说道。
“不是说了嘛,只要你追上我,我就和你在一起。你怎么还是这么笨!”小兔说道。
小龟和小兔幸福的回家了。
二分查找
二分查找是一种在有序数组中查找特定元素的算法,其基本思想是将待查找区间分为两部分,每一步比较待查找元素与区间中间元素的大小,从而将搜索范围缩小到一半,又被称为折半查找。
/**
* @arr: 有序数组
* @l: 待查找区间左端点
* @r: 待查找区间右端点
* @x: 需要查找的元素
*/
int binary_search(int *arr, int l, int r, int x) {
while (l <= r) {
// 计算中间位置
int m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出
// 检查x是否存在于中间位置
if (arr[m] == x)
return m;
// 若x大,则忽略左半部分
if (arr[m] < x) {
l = m + 1;
} else {
// 若x小,则忽略右半部分
r = m - 1;
}
// 若未找到元素,返回-1
return -1;
}
完整代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for access() function
#define MAX_STUDENTS 100
#define MAX_NAME_LEN 50
#define STUDENT_SYSTEM "student_system"
#define TRUE 1
#define FALSE 0
typedef struct {
int id; // 学号
char name[MAX_NAME_LEN]; // 姓名
float score; // 成绩
} Student;
int student_count = 0; // 学生数量
Student *students; // 学生数组指针
int g_max_student = MAX_STUDENTS;
Student *stu_sys_init(int num)
{
Student *stu_sys;
stu_sys = malloc(num * sizeof(Student));
if (stu_sys == NULL) {
printf("student system malloc failed!\n");
}
return stu_sys;
}
int write_student_info(Student *s)
{
FILE *fp = fopen(STUDENT_SYSTEM, "a");
if (fp == NULL) {
printf("fopen student_system failed!\n");
return 1;
}
fprintf(fp, "%-4d %-10s %-.2f\n", s->id, s->name, s->score);
fclose(fp);
return 0;
}
int check_if_student_exsit(int id)
{
int i;
for(i = 0; i < student_count; i++) {
if(students[i].id == id) {
return 1;
}
}
return 0;
}
void update_student_info(Student s, int need_write)
{
Student *stu_reinit;
int old_max_student;
int i;
if(student_count >= g_max_student) {
old_max_student = g_max_student;
g_max_student = g_max_student << 1;
stu_reinit = stu_sys_init(g_max_student);
if (stu_reinit == NULL) {
printf("Database is full!\n");
return;
}
memcpy(stu_reinit, students, old_max_student * sizeof(Student));
free(students);
students = stu_reinit;
}
if (!check_if_student_exsit(s.id)) {
students[student_count++] = s;
if (need_write) {
printf("Student added successfully, all student: %d!\n", student_count);
write_student_info(&s);
}
} else {
printf("student has in db, do nothing!\n");
}
}
void add_student()
{
Student s;
printf("Enter student ID: ");
scanf("%d", &s.id);
printf("Enter student name: ");
scanf("%s", s.name);
s.score = 0.0; // 初始成绩设置为0
update_student_info(s, TRUE);
}
void print_title()
{
printf("%-4s %-10s %-5s\n", "ID", "Name", "Score");
}
void display_all_students()
{
int i;
printf("-------- All students info --------\n");
if (student_count == 0) {
printf("No students!\n");
} else {
print_title();
for(i = 0; i < student_count; i++) {
printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);
}
}
printf("-------- End -----------\n");
}
/**
* * @arr: 有序数组
* * @l: 待查找区间左端点
* * @r: 待查找区间右端点
* * @x: 需要查找的元素
* */
int binary_search(Student *s, int l, int r, int target)
{
int m;
while (l <= r) {
// 计算中间位置
m = l + (r - l) / 2; // 防止(l+r)直接相加导致的溢出
// 检查x是否存在于中间位置
if (s[m].id == target)
return m;
// 若x大,则忽略左半部分
if (s[m].id < target) {
l = m + 1;
} else {
// 若x小,则忽略右半部分
r = m - 1;
}
}
// 若未找到元素,返回-1
return -1;
}
void find_student_by_id()
{
int id, i, ret;
printf("Enter student ID to search: ");
scanf("%d", &id);
ret = binary_search(students, 0, student_count, id);
if (ret != -1) {
print_title();
printf("%-4d %-10s %-.2f\n", students[ret].id, students[ret].name, students[ret].score);
return;
}
printf("Student with ID %d not found!\n", id);
}
void find_student_by_name()
{
int i, is_find = 0;
char name[MAX_NAME_LEN];
printf("Enter student name to search: ");
scanf("%s", name);
for(i = 0; i < student_count; i++) {
if(strcmp(students[i].name, name) == 0) {
print_title();
printf("%-4d %-10s %-.2f\n", students[i].id, students[i].name, students[i].score);
is_find = 1;
}
}
if (is_find == 0) {
printf("Student with name %s not found!\n", name);
}
}
void add_score()
{
int id, i;
float score;
printf("Enter student ID: ");
scanf("%d", &id);
printf("Enter student score: ");
scanf("%f", &score);
for(i = 0; i < student_count; i++) {
if(students[i].id == id) {
students[i].score = score;
printf("Score added successfully!\n");
return;
}
}
printf("Student with ID %d not found!\n", id);
}
void display_average_score()
{
float total = 0.0;
int i;
for(i = 0; i < student_count; i++) {
total += students[i].score;
}
printf("Average score of all students: %.2f\n", total / student_count);
}
int init_student_info()
{
if(access(STUDENT_SYSTEM, F_OK) != 0) { // 文件不存在
return 0;
}
FILE *fp = fopen(STUDENT_SYSTEM, "r");
if (fp == NULL) {
printf("fopen student_system failed!\n");
return 1;
}
#define BUF_SIZE 1024
char buf[BUF_SIZE];
int i = 0;
Student s;
while(fgets(buf, BUF_SIZE - 1, fp) != NULL) {
sscanf(buf, "%d %s %f\n", &s.id, s.name, &s.score);
update_student_info(s, FALSE);
}
fclose(fp);
return 0;
}
void swap(Student *a, Student *b)
{
Student tmp = *a;
*a = *b;
*b = tmp;
}
void bubble_sort_by_score(Student *s, int n)
{
int i, j;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) { // 最后 i 个已经排序好了, 遍历未排序的部分
if (s[j].score < s[j+1].score) {
// 如果当前元素大于后面的元素,交换它们
swap(&s[j], &s[j+1]);
}
}
}
}
int main()
{
int choice;
int ret;
students = stu_sys_init(MAX_STUDENTS);
if (students == NULL) {
printf("student system init failed, exit!\n");
return -1;
}
ret = init_student_info();
if (ret) {
printf("init_student_info failed!\n");
return 1;
}
display_all_students();
do {
printf("\nStudent Score Management System\n");
printf("0. Exit\n");
printf("1. Add Student\n");
printf("2. Display All Students\n");
printf("3. Find Student by ID\n");
printf("4. Find Student by Name\n");
printf("5. Add Score\n");
printf("6. Display Average Score\n");
printf("7. Display by Score sort\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch(choice) {
case 0:
printf("Exiting...\n");
break;
case 1:
add_student();
break;
case 2:
display_all_students();
break;
case 3:
find_student_by_id();
break;
case 4:
find_student_by_name();
break;
case 5:
add_score();
break;
case 6:
display_average_score();
break;
case 7:
bubble_sort_by_score(students, student_count);
display_all_students();
break;
default:
printf("Invalid choice!\n");
}
} while(choice != 0);
return 0;
}