C語言實現飛機訂票系統
問題描述與題目要求
問題描述: 假定某民航有M個航次的班機,每個航次都只到達一個地方。試為該機場售票處設計一個自動訂票和退票系統,要求系統具有以下功能:
(1)訂票:若該航次餘票大於等於乘客訂票數,則在該航次的乘客表中,插入訂票乘客的資訊項,並修改該航次有關資料,否則給出相應資訊。
(2)退票:若該航次當前退票數小於等於乘客原訂票數,則在相應的乘客表中找到該乘客項,修改該航次及乘客表中有關資料;當某乘客由於退票使訂票數為零時,則從乘客表中撤消該資料項。
要求:
(1)描述對航次表和乘客表選用的資料結構。
(2)程式設計實現飛機票訂票和退票系統。
模型假設
1.假設所有輸入均為整數且在int型別的表示範圍內
3.假設每個乘客 ID 均唯一
資料結構的選用
聯想到圖中的鄰接連結串列,採用相似的資料結構描述該問題
航次表: 用一個數組flight_info_list儲存每個航次的乘客表,該陣列下標即為航班航次,對應元素即為該航次相關資訊(乘客表,航班編號及航班餘票數)
乘客表: 用雙向連結串列儲存每個航次的乘客表passenger_info_list,每個結點儲存乘客的 ID,訂票數以及指向前、後結點的指標
程式設計實現(C語言實現)
/* * @Description: 模擬航班的訂票系統 * 模型假設: * 1. 飛機最大載客量為300人 * 2. 共10個航次 * 用雙向連結串列儲存乘客資訊 * 用array儲存航班資訊 * @Author: Fishermanykx * @Date: 2019-09-29 10:32:56 * @LastEditors: Fishermanykx * @LastEditTime: 2019-09-30 12:29:16 */ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #define MAX_CAPACITY 300 // 假定飛機最大載客量為300 #define TOTAL_AIRLINE 10 // 假定不同航線最大數目為10 #define BOOK_TICKET 1 #define REFUND -1 #define EXIT_SYSTEM 0 #define PRINT_INFO 11 #define ROOT 123456 // 某航次航班 struct SingleFlight { int flight_id; // 航班編號,從1開始,到TOTAL_AIRLINE為止 int remain_tickets; // 該航班餘票數 struct SinglePassenger* passenger_info_list; // 該航班乘客表 }; // 某航次航班的某個乘客的資訊 struct PassengerInfo { int passenger_id; // 乘客id int ticket_number; // 該乘客購買票數 }; // 乘客表中的一個結點 struct SinglePassenger { struct PassengerInfo passenger_info; // 乘客資訊 struct SinglePassenger* prev_passenger; // 指向前一個乘客的指標 struct SinglePassenger* next_passenger; // 指向後一個乘客的指標 }; typedef struct SingleFlight SingleFlight; typedef struct SinglePassenger SinglePassenger; // 訂票操作 SingleFlight* BookTicket(SingleFlight flight_info_list[]); SinglePassenger* GetNewPassenger(const int new_passenger_id,const int book_ticket_number); SinglePassenger* AddNewPassenger(SinglePassenger* head,const int new_passenger_id,const int book_ticket_number); // 退票操作 SingleFlight* Refund(SingleFlight flight_info_list[]); SinglePassenger* RemovePassenger(SinglePassenger* head,const int passenger_id); // 判斷操作 bool IsPassengerExist(SinglePassenger* head,const int passenger_id); // 列印操作 void PrintCurrentAirlineInfo(SingleFlight flight_info_list[]); void PrintPassengerList(SinglePassenger* head,SingleFlight* flight_info_list,int airline_id); int main(void) { int order,exit_loop = 1; // 初始化航班資訊 SingleFlight* flight_info_list; flight_info_list = (SingleFlight*)malloc(TOTAL_AIRLINE * sizeof(SingleFlight)); for (int i = 0; i < TOTAL_AIRLINE; ++i) { flight_info_list[i].flight_id = i + 1; flight_info_list[i].remain_tickets = MAX_CAPACITY; flight_info_list[i].passenger_info_list = NULL; } /* 登入介面 */ printf("您好,歡迎使用此係統!\n\n"); printf("使用說明:\n"); printf("1. 本程式所有輸入均為整數\n"); printf("2. 可供選擇的航次編號為1-%d,每架次最大載客量為%d\n",TOTAL_AIRLINE,MAX_CAPACITY); printf( "3. 若訂票,請輸入1;若退票,請輸入-1;若退出系統,請輸入0; " "若要以root使用者登入,請輸入root密碼\n"); printf("使用說明到此結束,祝您使用愉快!\n"); // 判斷是否以root登入 int log_in_as_root,root_key; bool is_root = false; printf("-------------------------------------------------------------\n\n"); printf("是否以root使用者登入?若是,請輸入1,否則請輸入0:"); scanf("%d",&log_in_as_root); if (log_in_as_root) printf("請輸入root密碼(按0退出root登入程式):"); while (log_in_as_root) { scanf("%d",&root_key); if (!root_key) { break; } else if (root_key != ROOT) { printf("輸入密碼錯誤!請重新輸入或按0退出root登入程式:"); } else { is_root = true; break; } } // 歡迎介面 if (is_root) printf("歡迎,root使用者!輸入11可檢視當前航次表\n"); else printf("歡迎,普通使用者!\n"); printf("-------------------------------------------------------------\n"); // 主迴圈 while (true) { if (is_root) printf("請輸入1,-1或11中的一個數字: "); else printf("請輸入1,-1中的一個數字: "); scanf("%d",&order); switch (order) { case BOOK_TICKET: flight_info_list = BookTicket(flight_info_list); break; case REFUND: flight_info_list = Refund(flight_info_list); break; case EXIT_SYSTEM: exit_loop = 0; break; case PRINT_INFO: printf( "-------------------------------------------------------------\n"); PrintCurrentAirlineInfo(flight_info_list); break; default: printf("非法輸入!\n"); break; } if (!exit_loop) break; } return 0; } /** * @description: 一次訂票操作的模擬 * @param {type} * flight_info_list {SingleFlight *}: 航班資訊表(航次表) * @return: */ SingleFlight* BookTicket(SingleFlight flight_info_list[]) { /* 獲取乘客預定航次 */ int target_airline; printf("可供選擇的航次對應的編號為: 1 - %d\n",TOTAL_AIRLINE); printf("請輸入您想預定的航次(輸入0時退出訂票程式): "); // 判斷輸入合法性 while (true) { scanf("%d",&target_airline); if (target_airline < 0 || target_airline > TOTAL_AIRLINE) { printf("您要預定的航次不存在!\n"); printf("請重新輸入一個正確的航次,或按0退出訂票程式:"); } else if (target_airline == 0) { printf("-------------------------------------------------------------\n"); return flight_info_list; } else break; } /* 獲取乘客id */ int passenger_id; int modify_tickets; printf("若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: "); // 判斷輸入合法性 while (true) { scanf("%d",&modify_tickets); if (modify_tickets != 1 && modify_tickets != 0) { printf("您輸入的是非法命令,請重新輸入0(原先未訂票)或1(原先已經訂票):"); } else break; } printf("請輸入您的ID: "); // 若原先未訂票 while (!modify_tickets) { scanf("%d",&passenger_id); if (IsPassengerExist( flight_info_list[target_airline - 1].passenger_info_list,passenger_id)) { printf("該ID已存在,請輸入一個新的ID: "); } else break; } // 若原先已經訂票 if (modify_tickets) { scanf("%d",&passenger_id); if (!IsPassengerExist( flight_info_list[target_airline - 1].passenger_info_list,passenger_id)) { printf("您原先並未預訂該航次的票!\n"); printf("-------------------------------------------------------------\n"); return flight_info_list; } } /* 獲取乘客預定票數 */ // 獲取當前航次餘票數 int remain_tickets; remain_tickets = flight_info_list[target_airline - 1].remain_tickets; printf("當前航次餘票數為: %d\n",remain_tickets); // 若該乘客想修改票數,顯示此乘客此前預訂的票數 if (modify_tickets) { SinglePassenger* head = flight_info_list[target_airline - 1].passenger_info_list; while (head->passenger_info.passenger_id != passenger_id) { head = head->next_passenger; } printf("您此前預訂的票數為%d張\n",head->passenger_info.ticket_number); } // 獲取乘客想預定的票數 int target_ticket_num; printf("請輸入您想預定(或增訂)的票數: "); // 判斷輸入合法性 while (true) { scanf("%d",&target_ticket_num); if (target_ticket_num > remain_tickets) { printf("您想預定的票數為%d,但當前航次餘票數僅為%d,餘票不足!\n",target_ticket_num,remain_tickets); printf("請輸入您想預定的票數,或按0退出訂票程式: "); } else if (target_ticket_num == 0) { printf("-------------------------------------------------------------\n"); return flight_info_list; } else { break; } } /* 修改航次餘票數 */ flight_info_list[target_airline - 1].remain_tickets -= target_ticket_num; /* 修改乘客表中對應的項 */ // 判斷該乘客原先是否存在 if (modify_tickets) { // 若存在,找到該乘客並修改他的訂票項 SinglePassenger* tmp = flight_info_list[target_airline - 1].passenger_info_list; while (tmp->passenger_info.passenger_id != passenger_id) { tmp = tmp->next_passenger; } tmp->passenger_info.ticket_number += target_ticket_num; printf("增訂成功!您現在共預訂%d張航次%d的票\n",tmp->passenger_info.ticket_number,target_airline); } else { // 若不存在,則在該航次的乘客列表中增加該乘客及其對應資訊 flight_info_list[target_airline - 1].passenger_info_list = AddNewPassenger( flight_info_list[target_airline - 1].passenger_info_list,passenger_id,target_ticket_num); printf("預訂成功!您現在共預訂%d張航次%d的票\n",target_airline); } printf("-------------------------------------------------------------\n"); return flight_info_list; } /** * @description: 查詢乘客表(雙向連結串列)中某乘客是否存在 * @param {type} * head {SinglePassenger*}: 雙向連結串列頭結點 * passenger_id {const int}: 待查詢的鍵值 * @return: 若存在,返回true;否則返回false */ bool IsPassengerExist(SinglePassenger* head,const int passenger_id) { SinglePassenger* tmp = head; bool exist = false; if (!head) { return false; } while (tmp) { if (tmp->passenger_info.passenger_id == passenger_id) { exist = true; break; } tmp = tmp->next_passenger; } return exist; } /** * @description: 初始化一個新結點 * @param {type} * new_passenger_id {const int}: 新增加的乘客的id * book_ticket_number {const int}: 新增加乘客的訂票數 * @return: 初始化後的結點(前驅,後繼均為空指標) */ SinglePassenger* GetNewPassenger(const int new_passenger_id,const int book_ticket_number) { SinglePassenger* new_passenger = (SinglePassenger*)malloc(sizeof(SinglePassenger)); new_passenger->passenger_info.passenger_id = new_passenger_id; new_passenger->passenger_info.ticket_number = book_ticket_number; new_passenger->next_passenger = NULL; new_passenger->prev_passenger = NULL; return new_passenger; } SinglePassenger* AddNewPassenger(SinglePassenger* head,const int book_ticket_number) { SinglePassenger* new_passenger = GetNewPassenger(new_passenger_id,book_ticket_number); if (!head) { head = new_passenger; } else { // 直接從頭部插入 new_passenger->next_passenger = head->next_passenger; if (head->next_passenger) { head->next_passenger->prev_passenger = new_passenger; } new_passenger->prev_passenger = head; head->next_passenger = new_passenger; } return head; } /** * @description: 一次退票操作的模擬 * @param {type} * flight_info_list {SingleFlight *}: 航次表 * @return: 修改後的航次表 */ SingleFlight* Refund(SingleFlight flight_info_list[]) { /* 獲取乘客預定航次 */ int target_airline; printf("可供選擇的航次對應的編號為: 1 - %d\n",TOTAL_AIRLINE); printf("請輸入您想退訂的航次(輸入0時退出訂票程式): "); // 判斷輸入合法性 while (true) { scanf("%d",&target_airline); if (target_airline < 0 || target_airline > TOTAL_AIRLINE) { printf("您要退訂的航次不存在!\n"); printf("請重新輸入一個正確的航次,或按0退出退票程式:"); } else if (target_airline == 0) { printf("-------------------------------------------------------------\n"); return flight_info_list; } else break; } /* 獲取乘客ID並判斷其合法性 */ int passenger_id; printf("請輸入您的ID: "); scanf("%d",&passenger_id); SinglePassenger* head = flight_info_list[target_airline - 1].passenger_info_list; if (!IsPassengerExist(head,passenger_id)) { printf("您並未預訂此次航班!\n"); printf("-------------------------------------------------------------\n"); return flight_info_list; } /* 獲取乘客退票數 */ // 列印此乘客的預訂票數 SinglePassenger* tmp = head; while (tmp->passenger_info.passenger_id != passenger_id) { tmp = tmp->next_passenger; } printf("您當前預訂的票數為: %d張\n",tmp->passenger_info.ticket_number); // 讀入退票數 int refund_ticket_num; printf("請輸入您的退票數(輸入0退出退票程式): "); scanf("%d",&refund_ticket_num); // 輸入合法性檢查 int cur_ticket = tmp->passenger_info.ticket_number; // 當前該乘客預訂的票數 while (cur_ticket < refund_ticket_num) { if (!refund_ticket_num) { printf("-------------------------------------------------------------\n"); return flight_info_list; } printf("您輸入的退票數大於您當前預訂的票數!"); printf("請重新輸入退票數(輸入0退出退票程式): "); scanf("%d",&refund_ticket_num); } /* 退票 */ // 更新航次表 flight_info_list[target_airline - 1].remain_tickets += refund_ticket_num; // 更新乘客表 if (cur_ticket > refund_ticket_num) { tmp->passenger_info.ticket_number -= refund_ticket_num; printf("您已成功退票,現在您%d航次的餘票為%d張\n",target_airline,tmp->passenger_info.ticket_number); } else { flight_info_list[target_airline - 1].passenger_info_list = RemovePassenger(head,passenger_id); printf("您已成功退票,現在您%d航次的餘票為%d張\n",0); } printf("-------------------------------------------------------------\n"); return flight_info_list; } /** * @description: 從乘客表中刪除某個結點 * @param {type} * head {SinglePassenger *}: 乘客表 * passenger_id {const int}: 待刪除乘客的id * @return: 修改後的航次表 */ SinglePassenger* RemovePassenger(SinglePassenger* head,const int passenger_id) { SinglePassenger* tmp = head; while (tmp->passenger_info.passenger_id != passenger_id) { tmp = tmp->next_passenger; } // 若為頭結點 if (!tmp->prev_passenger) { head = head->next_passenger; } // 若為尾結點 else if (!tmp->next_passenger) { tmp->prev_passenger->next_passenger = NULL; } // 若為中間某個結點 else { tmp->prev_passenger->next_passenger = tmp->next_passenger; tmp->next_passenger->prev_passenger = tmp->prev_passenger; } return head; } /** * @description: 輸出當前航次表 * @param {type} * flight_info_list {SingleFlight *}: 航班資訊表(航次表) * @return: void */ void PrintCurrentAirlineInfo(SingleFlight flight_info_list[]) { for (int current_airline_index = 1; current_airline_index <= TOTAL_AIRLINE; ++current_airline_index) { int remain_ticket_num = flight_info_list[current_airline_index - 1].remain_tickets; SinglePassenger* head = flight_info_list[current_airline_index - 1].passenger_info_list; // 輸出 PrintPassengerList(head,flight_info_list,current_airline_index); printf("-------------------------------------------------------------\n"); } } /** * @description: 列印某航次的乘客表 * @param {type} * head {SinglePassenger*}: 乘客表的頭結點 * flight_info_list {SingleFlight *}: 航次表 * @return: */ void PrintPassengerList(SinglePassenger* head,int airline_id) { if (!head) { printf("%d航次無乘客訂票!\n",airline_id); } else { printf("%d航次餘票數為: %d,其中:\n",airline_id,flight_info_list[airline_id - 1].remain_tickets); } while (head) { printf("ID為%d的乘客訂票數為%d張\n",head->passenger_info.passenger_id,head->passenger_info.ticket_number); head = head->next_passenger; } printf("\n"); }
實現亮點
1.每一步操作均有對非法輸入的處理,最大限度上確保了程式執行的穩定性
2.區分root使用者和普通使用者,且只有root使用者能夠檢視所有人的訂票情況,從而保護了客戶的隱私
3.使用雙向連結串列儲存乘客資訊,一方面便於存取乘客的資訊(定長陣列分配的是棧記憶體,而棧記憶體小於堆記憶體,所以用連結串列進行儲存更不容易造成記憶體溢位),另一方面降低了程式設計難度(既不需要實現對陣列進行動態記憶體分配的一系列操作,又最大限度地降低了刪除結點操作的複雜度)
實現缺點
1.只考慮了數字輸入的情況,沒有考慮字元及其他資料型別的輸入
2.用連結串列儲存導致不能隨機訪問,使查詢操作複雜度始終為O(n) O(n)O(n)
執行結果
您好,歡迎使用此係統! 使用說明: 1. 本程式所有輸入均為整數 2. 可供選擇的航次編號為1-10,每架次最大載客量為300 3. 若訂票,請輸入1;若退票,請輸入-1;若退出系統,請輸入0; 若要以root使用者登入,請輸入root密碼 使用說明到此結束,祝您使用愉快! ------------------------------------------------------------- 是否以root使用者登入?若是,請輸入1,否則請輸入0:1 請輸入root密碼(按0退出root登入程式):123456 歡迎,root使用者!輸入11可檢視當前航次表 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 1 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 0 請輸入您的ID: 1 當前航次餘票數為: 300 請輸入您想預定(或增訂)的票數: 12 預訂成功!您現在共預訂12張航次1的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 1 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 0 請輸入您的ID: 2 當前航次餘票數為: 288 請輸入您想預定(或增訂)的票數: 21 預訂成功!您現在共預訂21張航次1的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 1 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 0 請輸入您的ID: 3 當前航次餘票數為: 267 請輸入您想預定(或增訂)的票數: 32 預訂成功!您現在共預訂32張航次1的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 2 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 0 請輸入您的ID: 32 當前航次餘票數為: 300 請輸入您想預定(或增訂)的票數: 2 預訂成功!您現在共預訂2張航次2的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 10 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 0 請輸入您的ID: 212 當前航次餘票數為: 300 請輸入您想預定(或增訂)的票數: 123 預訂成功!您現在共預訂123張航次10的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 1 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 1 請輸入您的ID: 1 當前航次餘票數為: 235 您此前預訂的票數為12張 請輸入您想預定(或增訂)的票數: -1 增訂成功!您現在共預訂11張航次1的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: -1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想退訂的航次(輸入0時退出訂票程式): 1 請輸入您的ID: 2 您當前預訂的票數為: 21張 請輸入您的退票數(輸入0退出退票程式): 222 您輸入的退票數大於您當前預訂的票數!請重新輸入退票數(輸入0退出退票程式): 2 您已成功退票,現在您1航次的餘票為19張 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想預定的航次(輸入0時退出訂票程式): 10 若您原先已經訂票,且想增加您的訂票數,請輸入1,否則請輸入0: 32 您輸入的是非法命令,請重新輸入0(原先未訂票)或1(原先已經訂票):0 請輸入您的ID: 322 當前航次餘票數為: 177 請輸入您想預定(或增訂)的票數: 12 預訂成功!您現在共預訂12張航次10的票 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: -1 可供選擇的航次對應的編號為: 1 - 10 請輸入您想退訂的航次(輸入0時退出訂票程式): 10 請輸入您的ID: 212 您當前預訂的票數為: 123張 請輸入您的退票數(輸入0退出退票程式): 123 您已成功退票,現在您10航次的餘票為0張 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 11 ------------------------------------------------------------- 1航次餘票數為: 238,其中: ID為1的乘客訂票數為11張 ID為3的乘客訂票數為32張 ID為2的乘客訂票數為19張 ------------------------------------------------------------- 2航次餘票數為: 298,其中: ID為32的乘客訂票數為2張 ------------------------------------------------------------- 3航次無乘客訂票! ------------------------------------------------------------- 4航次無乘客訂票! ------------------------------------------------------------- 5航次無乘客訂票! ------------------------------------------------------------- 6航次無乘客訂票! ------------------------------------------------------------- 7航次無乘客訂票! ------------------------------------------------------------- 8航次無乘客訂票! ------------------------------------------------------------- 9航次無乘客訂票! ------------------------------------------------------------- 10航次餘票數為: 288,其中: ID為322的乘客訂票數為12張 ------------------------------------------------------------- 請輸入1,-1或11中的一個數字: 0
注:普通使用者不能執行檢視所有乘客資訊的操作,只能檢視自己的購票資訊
更多學習資料請關注專題《管理系統開發》。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。