新闻详情

新闻详情

首页 / 资讯中心 / 详情

C++航班查询课设实战:结构体+链表基数排序+二分查找

发布时间:2026/9/27 1:37:10来源:尧图网络
C++航班查询课设实战:结构体+链表基数排序+二分查找
简介这份数据结构课程设计资料以「航班查询与检索」为主题面向正在完成数据结构课程设计或需要算法实践案例的计算机专业学生。内容围绕结构体、链表、顺序表、队列等基础数据结构以及基数排序、二分法查询等算法展开完整呈现了从航班信息建模到多条件查询的实现思路。压缩包内仅含1个doc文档大小约217KB集中收录了实验报告、核心代码、算法流程图与程序输出结果便于对照理解各模块的衔接关系。文档中给出了航班号、起飞站、终点站、班期、起降时间、机型与票价等字段定义并展示了按航班号、时间、地点、票价等不同路径的查询流程读者可据此掌握链表动态存储、队列辅助基数排序及二分查找的落地方式。目前已有104人学习适合作为课程设计参考或算法复习素材。1. 航班查询与检索课设拆包一份能跑通的 C 数据结构实战如果你正在做数据结构课程设计又恰好抽到航班查询与检索这个题目大概率会遇到两个尴尬一是网上能找到的代码要么跑不起来要么功能残缺二是自己从零写排序和查找的选型就够纠结半天。这份资源就是一份完整的课程设计报告包含 C 源码、流程图和输出结果核心用结构体存航班信息、链表做基数排序、顺序表做二分查找覆盖按航班号、时间、站点、票价四种查询方式。它适合两类人正在赶课设 deadline 的本科生以及想拿一个真实小项目练手链表、队列、排序算法的自学者。代码量不大但数据结构该有的东西基本都齐了拿来改改就能交也能顺着把基数排序和二分查找的边界条件吃透。2. 数据结构选型为什么是结构体 链表 顺序表 队列2.1 结构体 DataType 的字段设计航班信息本身是典型的多字段异构数据航班号是字符串、票价是整数、起降时间是定长字符串用结构体打包是最自然的选择。资源里定义的DataType包含八个字段flight_number、start_address、arrived_address、work_date、start_time、arrived_time、FlightType、fare。注意时间字段用的是char[6]而不是整型这是后面输入 16:40 只能存 1640那个坑的根源也是作者最后改数据类型才解决的问题。typedef struct flight { char flight_number[10]; // 航班号如 CA1544 char start_address[10]; // 起飞站 char arrived_address[10]; // 终点站 char work_date[10]; // 班期如 1245 表示周一/二/四/五 char start_time[6]; // 起飞时间如 10:55 char arrived_time[6]; // 到达时间 char FlightType[4]; // 机型如 733、M90 int fare; // 票价单位元 } DataType;字段长度不是随便定的。flight_number[10]够放 CA1544 加结束符start_time[6]刚好放 10:55 五个字符加\0。如果你要扩展成 10:55:00 这种带秒的格式这个长度就不够了得改成[9]。票价用int而不是float是因为查询时要做范围比较整数比较不会有浮点误差这也是课设里常见的省事做法。2.2 链表 队列实现基数排序排序这块是整份代码最值得看的部分。航班号是字符串直接比较字符串排序当然可以但作者选了基数排序Radix Sort用链表存节点、用队列数组当桶。基数排序对字符串这种按位可比的关键字特别合适时间复杂度是 O(d×(nr))d 是位数、r 是基数。代码里D7、Ra意思是按 7 位、以字符 a 的 ASCII 值为基数分桶。#define D 7 // 排序码最大位数 #define R a // 基数小于字母 a 的整型值 typedef struct Node { KeyType key[D]; // 关键字这里就是航班号 DataType info; // 挂载的完整航班数据 RadixNode *next; } RadixNode; Queue queue[R]; // 用队列数组表示桶 void radixSort(RadixList *plist, int d, int r) { int i, j, k; RadixNode *p, *head; head (*plist)-next; for (j d - 1; j 0; j--) { // 从最低位开始共 d 趟 p head; for (i 0; i r; i) { // 清空所有桶 queue[i].f NULL; queue[i].e NULL; } while (p ! NULL) { // 分配按第 j 位入桶 k p-key[j]; if (queue[k].f NULL) queue[k].f p; else (queue[k].e)-next p; queue[k].e p; p p-next; } i 0; while (queue[i].f NULL) i; // 找第一个非空桶 p queue[i].e; head queue[i].f; for (i; i r; i) // 收集串回链表 if (queue[i].f ! NULL) { p-next queue[i].f; p queue[i].e; } p-next NULL; } (*plist)-next head; }逻辑分三步先按最低位把节点分配到对应桶里再从低位桶到高位桶依次收集回链表重复 d 趟。queue[k].f和queue[k].e分别是桶的头尾指针保证入桶顺序稳定。这里有个容易翻车的点Ra意味着桶的数量是 97a 的 ASCII 值但实际用到的桶只有字符对应的那几个其余全是空桶收集时那个while (queue[i].f NULL) i就是在跳过空桶。如果你把R改小比如改成 10那遇到字母就会数组越界这是改参数时最容易踩的坑。2.3 顺序表承接排序结果做二分查找排完序的链表不能直接二分查找因为链表不支持随机访问。作者的解法是copy函数把链表节点逐个拷进flight Flight[N]这个顺序表之后所有查询都在顺序表上做。这个设计思路很清晰链表负责动态排序顺序表负责静态查找各取所长。void copy(flight F[], Node element[]) { RadixList p element; p p-next; int i; for (i 0; i N p ! NULL; i) { strcpy(F[i].flight_number, p-info.flight_number); strcpy(F[i].start_time, p-info.start_time); strcpy(F[i].arrived_time, p-info.arrived_time); strcpy(F[i].start_address, p-info.start_address); strcpy(F[i].arrived_address, p-info.arrived_address); strcpy(F[i].work_date, p-info.work_date); strcpy(F[i].FlightType, p-info.FlightType); F[i].fare p-info.fare; p p-next; } }strcpy逐个字段拷贝注意fare是int直接赋值其余字符串字段用strcpy。这里N6是航班数循环条件同时判断i N和p ! NULL防止链表长度和数组长度不一致时越界。拷完之后Flight数组就是按航班号升序排好的二分查找的前提就满足了。3. 查询功能落地四种查询的代码实现与参数说明3.1 按航班号二分查找这是唯一用到二分查找的查询因为只有航班号在排序后是有序的。其余三种查询都是线性遍历因为时间、站点、票价在排序后并不保证有序。void F_By_FN(flight F[]) { int low 0, high N, mid; char Num[10]; cout 请输入您要查询的航班号; cin Num; Cout_info1(); while (low high) { mid (low high) / 2; if (strcmp(Num, F[mid].flight_number) 0) { Cout_info2_2(F, mid); break; } else if (strcmp(Num, F[mid].flight_number) 0) high mid - 1; else low mid 1; } cout *************对不起没有您要查找的航班号********** endl; }low初始为 0high初始为N。注意这里highN而不是N-1因为数组下标是 0 到 N-1highN会让第一次mid落在N/2对于 N6 就是 3没问题但严格来说high应该初始化为N-1。这是课设代码里常见的小瑕疵不影响功能但值得知道。strcmp返回 0 表示相等小于 0 表示Num字典序更小往左半区找。找到后break跳出但后面的对不起提示还是会打印这是逻辑上的小 bug——应该用一个标志位控制找到就不打印失败提示。3.2 按起飞/到达时间查询时间查询用Time参数区分是查起飞还是到达1 查起飞、2 查到达。核心是strcmp比较时间字符串。void F_By_Time(flight F[], int Time) { int i; char T[6]; cout 请输入您要查询的航班的起飞/抵达时间:; cin T; Cout_info1(); for (i 0; i N; i) { if (Time 1) { if (strcmp(T, F[i].start_time) 0) Cout_info2_2(F, i); } if (Time 2) { if (strcmp(T, F[i].arrived_time) 0) Cout_info2_2(F, i); } } cout *******对不起该时间没有航班******* endl; }输入格式必须和存储格式完全一致存的是 10:55你就得输 10:55输 1055 或 1055中文冒号都匹配不上。这就是作者在报告里提到的输入 16:40 只能实现输入 1640那个问题的遗留——虽然改了数据类型但输入格式的约束还在。实际用的时候建议在输入后做一次格式校验把用户输入统一成HH:MM再比较。3.3 按站点查询与按票价范围查询站点查询和票价查询都是线性遍历逻辑直白。站点查询用AD参数区分起点站1和目的站2票价查询接收最低价和最高价两个参数。void F_By_Address(flight F[], int AD) { char str[10]; cout 请输入您要查询的航班的起飞/抵达地址:; cin str; Cout_info1(); for (int i 0; i N; i) { if (AD 1) { if (strcmp(str, F[i].start_address) 0) Cout_info2_2(F, i); } if (AD 2) { if (strcmp(str, F[i].arrived_address) 0) Cout_info2_2(F, i); } } cout ********对不起该站点不存在******** endl; } void F_By_fare(flight F[]) { int T1, T2, i; cout 请输入您要查询的航班的最低票价(单位元):; cin T1; cout 请输入您要查询的航班的最高票价(单位元):; cin T2; Cout_info1(); for (i 0; i N; i) { if (T1 F[i].fare T2 F[i].fare) Cout_info2_2(F, i); } cout *******对不起没有适合您的航班请修改您的票价范围******** endl; }票价查询的条件是T1 fare T2 fare闭区间。如果你输入 T1 T2循环一次都不会命中直接打印失败提示不会报错但结果为空。站点查询对中文站名用strcmp比较要求输入和存储完全一致北京和北京市会被当成两个站这是中文处理里最常见的坑。3.4 主菜单与主函数串联主函数负责初始化链表、调排序、拷数据、进菜单。初始化时把element数组的next指针串起来形成链表然后排序、输出、拷贝、进菜单。int main() { RadixList p element; for (int i 0; i N; i) element[i].next element[i 1]; element[10].next NULL; radixSort(p, D, R); // 基数排序 output_ALL_info1(element); // 输出排序后的有序序列 copy(Flight, element); // 另存储排序后的航班信息 mainmenu(); // 给出主菜单 return 0; }element数组大小是N1第 0 个是头节点后面 N 个是数据节点。element[10].next NULL这里写死了 10实际上应该是element[N].next NULL因为 N6 时最后一个数据节点是element[6]element[10]已经越界了。这是原代码的一个硬编码问题改成element[N].next NULL更稳妥。主菜单用while(1)循环加switch分发输入 0 重新显示菜单输入其他键退出。4. 避坑与排查课设代码里那些让人翻车的细节4.1 二分查找的 high 初始值与失败提示现象按航班号查询时输入存在的航班号能查到但后面还是会打印对不起没有您要查找的航班号。原因break只跳出了while循环没有跳过后面的cout失败提示。解决加一个bool found false标志位找到时置true最后根据标志位决定是否打印失败提示。另外high建议初始化为N-1避免mid越界访问F[N]。4.2 时间字符串的输入格式匹配现象输入 16:40 查不到任何航班但数据里明明有 16:40 这个到达时间。原因cin T遇到空格会截断而且中文冒号和英文冒号在strcmp里不相等。解决用cin.getline读整行读完后把中文冒号替换成英文冒号再统一格式。如果时间字段存的是 1640 这种无冒号格式输入时也要去冒号。4.3 基数排序的桶数组越界现象把R从a改成 10 之后程序崩溃或排序结果错乱。原因航班号里包含字母字母的 ASCII 值远大于 10queue[k]直接越界。解决要么保持R为字符集大小比如 128要么在分桶前把字符映射到 0-9 的数字。课设里用a当基数是一种取巧实际工程中应该用256或按实际字符集设定。4.4 链表初始化时的硬编码下标现象航班数 N 改成 8 之后程序输出乱码或崩溃。原因element[10].next NULL写死了 10N 变了之后链表尾没正确置空遍历时读到野指针。解决改成element[N].next NULL让尾指针跟着 N 走。所有和 N 相关的下标都要检查一遍避免类似硬编码。4.5 中文站名的 strcmp 比较现象输入北京查不到但数据里起飞站就是北京。原因输入时用了中文输入法可能带了不可见字符或者存储时strcpy拷贝的字符串没有正确结束。解决在strcmp前先打印两边的字符串长度和每个字符的 ASCII 值确认是否完全一致。更稳妥的做法是用std::string替代char[]避免手动管理结束符。5. 进阶玩法把课设代码改成能用的查询工具课设代码跑通只是第一步真正让它能用还得做几件事。第一是数据外置把element数组里的六条航班信息挪到flights.txt里程序启动时读文件初始化链表这样加航班不用改代码重编译。读文件的逻辑不复杂按行读、按逗号分割字段、逐个strcpy进节点就行但要注意文件编码用 UTF-8否则中文站名会乱码。第二是查询结果去重和排序。现在按票价查询是线性遍历结果按数组顺序输出票价不是有序的。可以在查询前对Flight数组按票价做一次快速排序或者查询后把结果收集到临时数组再排。我一般会写一个通用的sortByField函数用函数指针传比较逻辑这样按票价、按时间都能复用。第三是加一个简单的统计功能。比如按站点查询后顺便输出该站点的航班数量和平均票价。这个功能在课设里不要求但加上去之后整个工具就从能查变成能看答辩时也多点东西讲。// 按票价升序排序的示例快速排序版 void quickSortByFare(flight F[], int low, int high) { if (low high) return; int i low, j high; int pivot F[(low high) / 2].fare; while (i j) { while (F[i].fare pivot) i; while (F[j].fare pivot) j--; if (i j) { flight tmp F[i]; F[i] F[j]; F[j] tmp; i; j--; } } quickSortByFare(F, low, j); quickSortByFare(F, i, high); }这个快排和课设里的基数排序形成互补基数排序适合字符串按位比较快排适合整数按大小比较。实际用的时候航班号用基数排序票价用快排各取所长。最后说个血泪经验课设代码里的#includeiostream.h是老式写法现代编译器g 4.8 以后会报错得改成#includeiostream加using namespace std;。还有char*和string混用的问题如果编译器报strcpy不安全加#define _CRT_SECURE_NO_WARNINGS或者换strcpy_s。这些编译期的坑不解决代码再好也跑不起来。从那以后我每次拿到课设代码第一件事就是先编译一遍看报什么错再动逻辑。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

PADS Logic到OrCAD转换全流程:工具迁移、网表关联与高频问题排查 2026/9/27 2:33:56

PADS Logic到OrCAD转换全流程:工具迁移、网表关联与高频问题排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
国企干部民主评议场景,衡识人才测评等360评估系统适配 2026/9/27 2:33:56

国企干部民主评议场景,衡识人才测评等360评估系统适配

引文/摘要又到年终干部考核季。不少国企组织人事部门都在面对同一道题:民主评议怎么搞,才能既合规又高效,还能真正沉淀出有用的数据?传统纸票模式下,评议结果常常“评完就归档”,难以支撑干部选拔与梯队建设…

阅读更多 →
立创EDA安装全攻略:专业版与标准版选型及避坑指南 2026/9/27 2:33:56

立创EDA安装全攻略:专业版与标准版选型及避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Vue 全局事件总线详解 2026/9/27 2:33:56

Vue 全局事件总线详解

一、什么是事件总线 1.1 定义 事件总线(Event Bus)本质上就是一个居中转发消息的"邮局":发送方不直接找接收方,而是把消息丢给总线,总线再帮转给所有订阅了这个消息的人。 在 Vue 里,它用来解决任意两个组件之间通信的问题,不限于父子,不限于兄弟,只要挂在同一条总线…

阅读更多 →
AI正在悄悄淘汰律师职业,但会用它的人反而涨薪了 2026/9/27 2:33:43

AI正在悄悄淘汰律师职业,但会用它的人反而涨薪了

过去一年半,我眼看着 Codex 这类编程 Agent 把我们行业的”初级活”吃掉了一大块:写单测、改样板代码、查日志、搭数据管道,以前要带一个应届生干两周的事,现在一个中级工程师开几个并行任务,一下午收工。组里没人被裁…

阅读更多 →
六因子选股与双指标择时:量化策略回测实战拆解 2026/9/27 2:33:31

六因子选股与双指标择时:量化策略回测实战拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉