:用Dijkstra與BFS實現(xiàn)最短路徑與換乘查詢)
簡介全國交通出行咨詢模擬系統(tǒng)C語言實現(xiàn)源碼包是一份數(shù)據(jù)結(jié)構(gòu)課程設(shè)計項目面向高校計算機相關(guān)專業(yè)學(xué)生在課程設(shè)計、期末大作業(yè)中的直接參考與復(fù)用可作為完整方案下載即用。項目以全國城市間交通網(wǎng)絡(luò)為背景綜合運用圖存儲、最短路徑查詢、鄰接表等核心數(shù)據(jù)結(jié)構(gòu)知識涵蓋公路、鐵路、航班等多類交通方式并已獲導(dǎo)師指導(dǎo)、以97分高分通過驗收。壓縮包共10個文件核心為5個頭文件與1個C主程序分別承擔系統(tǒng)模塊接口與主邏輯另含3個文本數(shù)據(jù)文件用于城市、航班、火車信息初始化數(shù)據(jù)格式簡潔、便于按需修改同時附有1份README說明文檔整體約16KB目錄結(jié)構(gòu)清晰便于快速閱讀和二次開發(fā)。目前已有308人學(xué)習(xí)下載。下載解壓后即可編譯運行無需修改能幫助使用者快速完成一份結(jié)構(gòu)完整、可演示的課程設(shè)計也可作為理解交通咨詢模擬算法實現(xiàn)的參考資料代碼注釋與模塊劃分便于進一步擴展功能并適合在課程答辯中直接演示。1. 全國交通出行咨詢模擬系統(tǒng)一張帶權(quán)圖把“出行咨詢”變成一道最短路徑題數(shù)據(jù)結(jié)構(gòu)課程設(shè)計里“全國交通出行咨詢模擬系統(tǒng)”這類題目幾乎年年換皮出現(xiàn)。它聽上去要做成一個小型產(chǎn)品剝開來看骨架其實非常固定把城市抽象成頂點把交通線路抽象成帶權(quán)邊然后用最短路徑算法回答“從A市到B市怎么走最近、換乘最少”。真正讓初學(xué)者卡住的不是“全國”有多大而是C語言里怎么組織這張圖、怎么把文本數(shù)據(jù)可靠地加載進內(nèi)存、怎么讓算法結(jié)果以看得懂的方式輸出。這篇文章按我實際做課設(shè)時慣用的路線從建模、存儲、算法選型、交互菜單到排錯整體走一遍最后給出測試數(shù)據(jù)和答辯擴展方向。2. 建模與存儲把交通網(wǎng)變成C語言能讀懂的圖2.1 為什么是一張無向帶權(quán)圖城市、線路和權(quán)重怎么映射交通出行咨詢這件事核心信息只有兩類有哪些城市哪些城市之間有線路、線路代價是多少。城市就是圖的頂點線路就是連接兩個頂點的邊邊的權(quán)重可以表示距離、時間或票價。換乘信息不需要額外存它可以從路徑經(jīng)過的邊數(shù)推導(dǎo)出來。最常見的做法是把全國交通網(wǎng)建模成一張無向帶權(quán)圖。火車、長途汽車大多是雙向運行所以邊按無向處理存的時候?qū)ΨQ寫入鄰接矩陣。權(quán)重用什么口徑?jīng)Q定了系統(tǒng)的查詢標題。如果課程設(shè)計題目寫的是“最短路徑”權(quán)重用公里數(shù)如果寫的是“最少時間”權(quán)重就存分鐘數(shù)兩者都做就需要準備兩套邊權(quán)或者運行時動態(tài)替換。這一步先做結(jié)構(gòu)體定義。我用一個全局圖對象來裝城市表和鄰接矩陣后續(xù)所有函數(shù)都操作它省去在函數(shù)間反復(fù)傳指針的麻煩。課程設(shè)計規(guī)模下幾十個城市鄰接矩陣浪費的空間完全可以接受。#include stdio.h #include stdlib.h #include string.h #define MAX_CITY 256 #define INF 1000000000 // 1e9表示不可達 typedef struct { int id; // 城市編號直接當數(shù)組下標用 char name[64]; // 城市名 } City; typedef struct { int n; // 當前城市數(shù)量 City cities[MAX_CITY]; // 城市表 int edge[MAX_CITY][MAX_CITY]; // 鄰接矩陣 } TransportGraph; TransportGraph g_graph;City 結(jié)構(gòu)體把編號和名字綁在一起方便按數(shù)組下標訪問城市名。TransportGraph 里 n 表示有效頂點數(shù)量edge 是鄰接矩陣edge[i][j] 存放 i 到 j 的代價。這里的編號策略我建議直接讓文件的 id 等于數(shù)組下標從 0 開始后面所有算法都不用再做轉(zhuǎn)換少一類 bug。2.2 鄰接矩陣還是鄰接表課程設(shè)計規(guī)模下怎么選很多教材把鄰接表和鄰接矩陣放在一起講學(xué)生就容易糾結(jié)。其實選擇標準很簡單頂點少、邊比較密、要反復(fù)查詢?nèi)我鈨牲c關(guān)系用鄰接矩陣頂點多、邊稀疏、經(jīng)常只沿著某幾個鄰居遍歷用鄰接表。交通咨詢系統(tǒng)里查詢頻繁最短路徑算法每次都要掃描當前頂點的所有鄰居鄰接矩陣的隨機訪問是一步到位代碼也直觀。全國幾百個城市矩陣大小 500×500每個 int 占 4 字節(jié)總共約 1MB完全不是負擔。如果堅持鄰接表路徑回溯、判斷兩點是否直連、Floyd 預(yù)計算都會變得麻煩課設(shè)答辯時還要多解釋一套鏈式結(jié)構(gòu)。所以這個項目我一般直接上鄰接矩陣。只有當題目明確要求“城市數(shù)量超過 1000內(nèi)存受限”時才考慮鄰接表加 Dijkstra 堆優(yōu)化那是另一個故事。2.3 文件存儲與加載city.txt 和 route.txt 的約定數(shù)據(jù)不能寫死在代碼里這是課設(shè)評分的重要觀察點。用兩個文本文件分別存城市和線路將來替換數(shù)據(jù)就能模擬不同區(qū)域系統(tǒng)就不只是“全國”換成任意網(wǎng)絡(luò)都能跑。城市文件每行一個城市線路文件每行一條邊格式越簡單越好。我用兩個文件city.txt 存城市編號和名字route.txt 存邊的兩個端點和權(quán)重。下面這個表格是字段約定文件字段說明示例city.txtid 城市名城市編號從 0 開始城市名單詞間不要有空格0 A市route.txt起點 終點 權(quán)重權(quán)重表示距離或時間整數(shù)0 2 10加載函數(shù)分開寫先讀城市再讀線路。線路加載前必須把鄰接矩陣初始化成全 INF對角線初始化為 0否則程序會拿著內(nèi)存里的殘留值當距離算。int loadCities(const char* path) { FILE* fp fopen(path, r); if (!fp) { printf(無法打開城市文件: %s\n, path); return -1; } g_graph.n 0; while (fscanf(fp, %d %63s, g_graph.cities[g_graph.n].id, g_graph.cities[g_graph.n].name) 2) { g_graph.n; } fclose(fp); return g_graph.n; } void loadRoutes(const char* path) { for (int i 0; i MAX_CITY; i) { for (int j 0; j MAX_CITY; j) { g_graph.edge[i][j] (i j) ? 0 : INF; } } FILE* fp fopen(path, r); if (!fp) { printf(無法打開線路文件: %s\n, path); return; } int u, v, w; while (fscanf(fp, %d %d %d, u, v, w) 3) { if (u MAX_CITY || v MAX_CITY) continue; g_graph.edge[u][v] w; g_graph.edge[v][u] w; // 無向圖對稱寫入 } fclose(fp); }fscanf 的 %63s 限制了城市名長度避免一個超長名字把緩沖區(qū)寫穿。 2 和 3 的判斷很關(guān)鍵它表示“每行必須完整讀到對應(yīng)數(shù)量的字段才算一條有效數(shù)據(jù)”空行和壞行會被跳過而不是讓程序崩潰。加載線路前重置 n 和鄰接矩陣是重復(fù)加載數(shù)據(jù)的后悔藥程序支持重新載入文件時不會越界。2.4 初始化細節(jié)INF 的值為什么不能拍腦袋鄰接矩陣初始化時不可達邊用什么值看似小事實際是課設(shè)翻車重災(zāi)區(qū)。用 0 肯定不行0 會被當成一條零代價路徑Dijkstra 一跑全是 0。用 INT_MAX 也不行松弛比較 dist[u] w 時兩個大數(shù)相加直接溢出成負數(shù)結(jié)果比任何路徑都小算法全亂。我在代碼里統(tǒng)一用 1e9 作為 INF。城市數(shù) 256邊權(quán)就算到十萬dist[u] w 撐死幾千萬離 int 上限還遠。這個值既大得足夠表示“不可達”又小得不會溢出是面試和課設(shè)里最穩(wěn)的選擇。如果你手癢想用 2147483647那要么在松弛前判 w INF要么改成 long long否則遲早被溢出坑一次。3. 核心算法Dijkstra 與 Floyd 的選型、實現(xiàn)和參數(shù)3.1 選型判斷單點查詢用 Dijkstra全源預(yù)計算用 Floyd交通咨詢系統(tǒng)最常見的需求是“查 A 到 B 的最短路”。單次查詢用 Dijkstra時間復(fù)雜度 O(n2)簡單直接。如果系統(tǒng)需要頻繁查詢?nèi)我鈨沙鞘兄g的最短路每次跑 Dijkstra 就會重復(fù)計算這時候應(yīng)該上 Floyd一次性求出所有點對的最短路后續(xù)每次查詢 O(1) 取結(jié)果。課設(shè)里的選擇標準我總結(jié)成一句話菜單只有單次查詢Dijkstra 就夠了菜單有“任意兩地查詢”且城市數(shù)不超過 200Floyd 更省事代碼只有三層循環(huán)。有些同學(xué)兩個都寫了答辯時反而要解釋兩套代碼的行為差異沒必要。我一般用 Dijkstra 做單次查詢換乘查詢用 BFS各司其職。3.2 Dijkstra 模板鄰接矩陣版的最短路與路徑記錄Dijkstra 的教材實現(xiàn)到處都是但很多版本只返回距離不返回路徑。課設(shè)里如果沒有路徑查完只會輸出一個數(shù)字根本沒法演示。所以我寫的模板把路徑也記錄下來用 prev 數(shù)組存每個節(jié)點的前驅(qū)最后從終點回溯到起點。void dijkstra(int start, int dest, int* dist, int* prev, int* path, int* pathLen) { int visited[MAX_CITY] {0}; for (int i 0; i g_graph.n; i) { dist[i] g_graph.edge[start][i]; prev[i] (dist[i] ! INF i ! start) ? start : -1; } visited[start] 1; dist[start] 0; prev[start] -1; // 起點沒有前驅(qū)回溯到此停止 for (int step 1; step g_graph.n; step) { int u -1; int minDist INF; for (int i 0; i g_graph.n; i) { if (!visited[i] dist[i] minDist) { minDist dist[i]; u i; } } if (u -1) break; // 剩余節(jié)點不可達提前結(jié)束 visited[u] 1; for (int v 0; v g_graph.n; v) { if (!visited[v] g_graph.edge[u][v] ! INF dist[u] g_graph.edge[u][v] dist[v]) { dist[v] dist[u] g_graph.edge[u][v]; prev[v] u; } } } *pathLen 0; if (dist[dest] INF) return; for (int cur dest; cur ! -1; cur prev[cur]) { path[(*pathLen)] cur; if (cur start) break; } for (int i 0; i *pathLen / 2; i) { int tmp path[i]; path[i] path[*pathLen - 1 - i]; path[*pathLen - 1 - i] tmp; } }代碼第 7 行給所有點初始化了“通過起點直接能到的前驅(qū)”這個動作很多模板會漏。如果不初始化回溯路徑時 prev 是野值輕則路徑錯亂重則死循環(huán)。每輪選最小未訪問節(jié)點用線性掃描城市數(shù)量幾百時完全夠用。松弛的判斷條件是dist[u] edge[u][v] dist[v]這里要求 edge 不為 INF防止把“不可達”加成“可達”。3.3 最少換乘不是“權(quán)重小一點”是另一張圖上的 BFS最短距離和最少換乘經(jīng)常被混為一談。距離最短的路徑要經(jīng)過三個城市、換兩次車換乘最少的路徑可能是直連但繞遠路。兩個指標本質(zhì)不同不能用同一套權(quán)重。最少換乘問題的標準做法是把每條邊權(quán)重視為 1跑無權(quán)圖的最短路徑BFS 就是最優(yōu)解。換乘次數(shù)等于“經(jīng)過的邊數(shù) ? 1”直連線路是 1 條邊換乘 0 次。int minTransfers(int start, int dest) { int queue[MAX_CITY], head 0, tail 0; int step[MAX_CITY]; for (int i 0; i g_graph.n; i) step[i] -1; step[start] 0; queue[tail] start; while (head tail) { int u queue[head]; if (u dest) break; for (int v 0; v g_graph.n; v) { if (g_graph.edge[u][v] ! INF step[v] -1) { step[v] step[u] 1; queue[tail] v; } } } if (step[dest] -1) return -1; // 不可達 if (step[dest] 0) return 0; // 起點就是終點 return step[dest] - 1; // 邊數(shù)減一 }step 數(shù)組記錄從起點到每個點經(jīng)過的邊數(shù)同時兼作 visited 標記。這里必須用 BFS 而不是 DFS因為 BFS 第一次到達某個點時就是最短邊數(shù)DFS 會繞路。如果題目里所謂“換乘”指換乘交通工具類型比如高鐵轉(zhuǎn)飛機那要建“線路圖”而不是“城市圖”頂點變成車次兩個車次有共同城市才連邊那是進階版本課設(shè)一般用不到。3.4 參數(shù)與邊界不可達節(jié)點、起點終點相同、負權(quán)邊Dijkstra 的適用前提是邊權(quán)非負。交通網(wǎng)絡(luò)里的距離、時間、票價天然非負所以放心用。但如果自己擴展系統(tǒng)時允許“臨時優(yōu)惠”“反向里程”之類負數(shù)權(quán)重Dijkstra 會給出錯誤結(jié)果那就要換算法。課設(shè)文檔里寫一句“本系統(tǒng)交通場景均為非負權(quán)值故采用 Dijkstra”是很好的邊界說明。不可達的情況也要處理。dijkstra 結(jié)束后如果 dist[dest] 還是 INF不能給用戶輸出 0要提示“暫無可達路徑”。起點和終點相同的查詢直接返回 0 和只含一個頂點的路徑。這些細節(jié)在答辯演示時容易被老師專門問到提前擋住。4. 從算法到系統(tǒng)菜單交互、結(jié)果展示和一組可信的自測數(shù)據(jù)4.1 菜單狀態(tài)機用 while switch 把查詢串成一個系統(tǒng)算法寫好了還得有一個讓用戶操作的殼。課程設(shè)計系統(tǒng)不需要圖形界面命令行菜單就夠。一個死循環(huán)加用戶輸入通過 switch 分發(fā)到不同功能退出時用 break 跳出這個結(jié)構(gòu)既簡單又好解釋。void runMenu() { int choice -1; while (choice ! 0) { printf(\n 全國交通出行咨詢模擬系統(tǒng) \n); printf(1. 查詢兩地最短距離\n); printf(2. 查詢兩地最少換乘\n); printf(3. 查看所有城市列表\n); printf(0. 退出系統(tǒng)\n); printf(請選擇功能: ); if (scanf(%d, choice) ! 1) { printf(輸入無效請重新選擇\n); while (getchar() ! \n); // 清空輸入緩沖 choice -1; continue; } switch (choice) { case 1: queryShortestPath(); break; case 2: queryMinTransfer(); break; case 3: listAllCities(); break; case 0: printf(感謝使用再見\n); break; default: printf(沒有該選項\n); break; } } }輸入無效時用 getchar 把緩沖區(qū)的殘留字符讀完這是命令行程序的常規(guī)血淚處理。如果不做清理用戶隨便敲一個字母scanf 失敗后無限循環(huán)刷屏演示時相當尷尬。菜單層級也不要做得太深一兩層正好太深老師操作起來會覺得系統(tǒng)不好用。4.2 路徑回溯與格式化輸出把數(shù)組變成“A市 - C市 - D市 - B市”Dijkstra 算出的 path 數(shù)組存的是節(jié)點下標直接打印數(shù)字沒人能看懂。輸出前要映射回城市名并按順序拼接成一條完整路徑。路徑在回溯階段是從終點倒著存進數(shù)組的所以要先翻轉(zhuǎn)再逐段輸出。void printPath(int* path, int pathLen) { if (pathLen 0) { printf(暫無可達路徑\n); return; } for (int i 0; i pathLen; i) { if (i 0) printf( - ); printf(%s, g_graph.cities[path[i]].name); } printf(\n); } void queryShortestPath() { int from, to, dist[MAX_CITY], prev[MAX_CITY]; int path[MAX_CITY], pathLen; printf(請輸入起點城市編號: ); scanf(%d, from); printf(請輸入終點城市編號: ); scanf(%d, to); if (from 0 || from g_graph.n || to 0 || to g_graph.n) { printf(城市編號越界\n); return; } if (from to) { printf(起點和終點相同距離為 0\n); return; } dijkstra(from, to, dist, prev, path, pathLen); if (dist[to] INF) { printf(暫無可達路徑\n); return; } printf(最短距離: %d\n, dist[to]); printf(路徑方案: ); printPath(path, pathLen); }城市編號越界、起終點相同、不可達三種情況都在用戶輸入層攔截算法層不用重復(fù)操心。輸出格式保持一致先給距離再給路徑這是最直觀的展示順序。4.3 我用來驗證算法的 5 節(jié)點樣本數(shù)據(jù)寫完算法最怕自我感覺良好隨手填幾組數(shù)據(jù)全是直連算法再錯也看不出來。我習(xí)慣準備一個 5 節(jié)點的小樣本故意設(shè)計一條“距離最短但換乘多”的路徑和一條“直連但距離遠”的路徑用來同時驗證 Dijkstra 和換乘 BFS 是否各司其職。city.txt0 A市 1 B市 2 C市 3 D市 4 E市route.txt0 2 10 2 3 20 3 1 30 0 1 100 0 4 50 4 1 5這張圖里A 到 B 有直連路線代價 100經(jīng)過 C、D 繞行的代價是 60經(jīng)過 E 的路線代價 55距離最短。換乘方面直連只要乘坐 1 段換乘 0 次經(jīng)過 E 要乘坐 2 段換乘 1 次經(jīng)過 C、D 要乘坐 3 段換乘 2 次。三個方案的排名完全不同正好測試系統(tǒng)區(qū)分兩個查詢目標的能力。查詢預(yù)期結(jié)果最優(yōu)路徑A 到 B 最短距離55A市 - E市 - B市A 到 B 最少換乘0 次A市 - B市如果程序跑出來的最短距離是 60 或 100說明 Dijkstra 有 bug如果換乘查詢返回 1 次說明 BFS 把“經(jīng)過邊數(shù)”和“換乘次數(shù)”算混了。用這 5 條邊、6 條數(shù)據(jù)就能把兩套核心邏輯全部覆蓋比寫幾十個城市更有效率。5. 避坑指南從編譯通過到答案正確中間藏著這些坑5.1 數(shù)據(jù)讀入與初始化階段三個繞不開的問題**現(xiàn)象**路徑回溯時程序卡死或者打印出來的路徑在幾個城市之間來回循環(huán)最后棧溢出。 **原因**城市編號基準不統(tǒng)一。城市文件里編號從 1 開始數(shù)組下標從 0 開始Dijkstra 里一邊用數(shù)組下標一邊用文件編號prev 數(shù)組里存的是舊編號回溯時找不到起點甚至形成環(huán)。 **解決**統(tǒng)一用數(shù)組下標。文件里讀出 id 后存成 id-1或者要求文件編號從 0 開始我直接采用后者。只要代碼里出現(xiàn)“城市編號 ? 1”這種神秘代碼就說明基準又混了。**現(xiàn)象**城市名讀出來是亂碼或者最后一個字消失。 **原因**源碼文件、數(shù)據(jù)文件、控制臺三者的編碼不一致。Windows 下編譯器默認用 GBK 存源碼文本編輯器卻把 city.txt 存成了 UTF-8控制臺按 GBK 解碼自然亂碼。 **解決**把數(shù)據(jù)文件一律另存為與源碼相同的編碼。Windows 下統(tǒng)一 GBKLinux/macOS 下統(tǒng)一 UTF-8。寫文檔時附一句“數(shù)據(jù)文件需與源碼編碼保持一致”能省掉演示前最后一分鐘的手忙腳亂。**現(xiàn)象**大邊權(quán)時程序輸出負數(shù)距離路徑完全錯亂。 **原因**INF 初始化為 INT_MAX松弛比較時執(zhí)行 dist[u] edge[u][v]兩個值相加溢出為負每次更新都被當成更短路徑。 **解決**INF 用 1e9不要用 INT_MAX。或者把所有距離變量改成 long long但那樣打印格式又要調(diào)。最簡單就是固定 1e9省心。5.2 算法與輸出階段兩個容易被當成玄學(xué)的錯誤**現(xiàn)象**Floyd 三層循環(huán)寫完后部分點對結(jié)果正確部分錯誤而且錯誤還“看起來挺對”。 **原因**循環(huán)順序把 k 寫到了最內(nèi)層。Floyd 的中間節(jié)點 k 必須放在最外層才能保證每次用到的 dist[i][k] 和 dist[k][j] 已經(jīng)包含了前 k-1 個中間節(jié)點的更新結(jié)果。順序錯了松弛狀態(tài)會互相污染。 **解決**牢記標準順序k 在最外i 次之j 最內(nèi)。寫代碼時先寫循環(huán)框架再填決策不要邊寫邊調(diào)順序。**現(xiàn)象**Dijkstra 輸出的距離正確但路徑方向反了終點在前、起點在后。 **原因**回溯時從終點一路往 prev 找路徑自然是從終點倒著收集的。忘了翻轉(zhuǎn)數(shù)組直接打印就成了 A 市在前面。這一條不算復(fù)雜但幾乎每屆課設(shè)都有同學(xué)中招屬于典型的手滑問題。 **解決**回溯完成后對半翻轉(zhuǎn)數(shù)組或者在收集時從起點向終點遞歸。翻轉(zhuǎn)代碼只有三行寫在 dijkstra 函數(shù)末尾統(tǒng)一處理不要在 printPath 里翻避免查詢函數(shù)多得時候漏掉。**現(xiàn)象**第二次加載數(shù)據(jù)文件時程序崩潰城市數(shù)量翻倍增長。 **原因**loadCities 里 n 從上次的值開始繼續(xù)累加城市數(shù)組越界或者舊數(shù)據(jù)殘留干擾新數(shù)據(jù)。 **解決**每次加載前先把 g_graph.n 置 0鄰接矩陣在 loadRoutes 里重新初始化。重復(fù)加載本就是課設(shè)加分項但前提是狀態(tài)干凈。我習(xí)慣在文件讀取模塊提供 resetGraph 函數(shù)加載前統(tǒng)一調(diào)用。6. 答辯前還能做什么驗證習(xí)慣、擴展方向與怎么講清楚6.1 先跑通 5 節(jié)點最小樣例再上全國數(shù)據(jù)我自己的習(xí)慣是數(shù)據(jù)從小往大加。先用第 4 章的 5 節(jié)點數(shù)據(jù)把所有功能跑通確認輸出與手算一致再替換成幾十個城市的大文件。這樣做的好處是出錯時縮圈容易5 個節(jié)點都能手推答案算法對沒對一眼就知道直接上大數(shù)據(jù)錯了根本不知道正確答案是什么。6.2 三個低成本高分擴展時間權(quán)重、換乘限制、線路維護第一個擴展是給系統(tǒng)加第二套邊權(quán)距離和時間各存一個矩陣查詢時讓用戶選擇“按距離”還是“按時間”Dijkstra 函數(shù)提取對應(yīng)矩陣邏輯不用改。第二個擴展是限定“最多換乘 N 次”BFS 里加一層深度判斷超過 N 就剪掉。第三個擴展是“新增/刪除一條線路”提供菜單入口修改鄰接矩陣并重新持久化到 route.txt這能讓系統(tǒng)從“只讀查詢”變成“可維護系統(tǒng)”。6.3 答辯怎么講把圖論價值講清楚答辯時不要上來就講代碼行數(shù)老師想聽的是建模思想。我一般這樣講把全國交通網(wǎng)抽象成無向帶權(quán)圖城市是頂點線路是帶權(quán)邊最短距離用 Dijkstra核心是貪心加松弛最少換乘把權(quán)重置為 1用 BFS 求最少的邊數(shù)。把這三句話說清楚比背十段代碼都管用。另外一定要現(xiàn)場演示一次不可達查詢讓系統(tǒng)輸出友好提示這個場景比正常查詢更能體現(xiàn)邊界處理意識。這套方案做完我最大的教訓(xùn)就是數(shù)據(jù)初始化和編號基準比算法本身更容易翻車。算法只需要理解數(shù)據(jù)問題需要排查而且排查起來毫無成就感。所以現(xiàn)在每寫一個查詢模塊我都先用小樣本跑通再擴數(shù)據(jù)這個習(xí)慣讓我少熬了很多夜。希望幫到你。本文還有配套的精品資源點擊獲取