diff --git a/PracticalTrain/DataStructure/.gitignore b/PracticalTrain/DataStructure/.gitignore new file mode 100644 index 0000000..c21da1c --- /dev/null +++ b/PracticalTrain/DataStructure/.gitignore @@ -0,0 +1,3 @@ +main.cpp +bin +obj \ No newline at end of file diff --git a/PracticalTrain/DataStructure/Makefile b/PracticalTrain/DataStructure/Makefile new file mode 100644 index 0000000..25c2c3f --- /dev/null +++ b/PracticalTrain/DataStructure/Makefile @@ -0,0 +1,52 @@ +# Makefile for Bus Route Management System + +CC = gcc +CFLAGS = -Wall -Wextra -g -I./include +LDFLAGS = -lm + +# 目录 +SRC_DIR = src +INC_DIR = include +OBJ_DIR = obj +BIN_DIR = bin +DATA_DIR = data + +# 源文件和目标文件 +SOURCES = $(wildcard $(SRC_DIR)/*.c) +OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) +TARGET = $(BIN_DIR)/bus_system + +# 默认目标 +all: directories $(TARGET) + +# 创建必要的目录 +directories: + @mkdir -p $(OBJ_DIR) + @mkdir -p $(BIN_DIR) + @mkdir -p $(DATA_DIR) + +# 链接目标文件生成可执行文件 +$(TARGET): $(OBJECTS) + $(CC) $(OBJECTS) -o $(TARGET) $(LDFLAGS) + @cp -r $(DATA_DIR) $(BIN_DIR) + @echo "build successful: $(TARGET)" + +# 编译源文件为目标文件 +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c + $(CC) $(CFLAGS) -c $< -o $@ + +# 清理编译文件 +clean: + rm -rf $(OBJ_DIR) $(BIN_DIR) + @echo "clean over" + +# 运行程序 +run: $(TARGET) + @cp -r $(DATA_DIR) $(BIN_DIR) + @cd $(BIN_DIR) && ./bus_system + +# 安装数据文件(如果需要) +install-data: + @echo "请确保 data/ 目录包含 stations.csv 和 routes.csv" + +.PHONY: all clean run directories install-data \ No newline at end of file diff --git a/PracticalTrain/DataStructure/README.md b/PracticalTrain/DataStructure/README.md new file mode 100644 index 0000000..f89d306 --- /dev/null +++ b/PracticalTrain/DataStructure/README.md @@ -0,0 +1,33 @@ +## 课题二十六: 校园巴士实时查询系统 + +### 一、设计目的 + +1. 掌握数据结构知识,强化C语言编程实现与算法设计的结合; +2. 提升对数据结构的逻辑设计与存储结构的理解。 + + +### 二、设计任务与要求 + +**设计一个校园巴士线路查询系统,模拟巴士运行状态,提供实时到站预测和最优乘车方案。** + +- 功能要求 + + 1. 支持定义多条巴士线路,每条线路有固定站点序列,每个站点包含名称、位置坐标、停靠时间,线路信息可从配置文件加载; + 2. 为每辆巴士维护当前位置、行驶方向、速度,模拟巴士在站点停靠(固定时间),实时更新所有巴士位置(每虚拟分钟更新一次); + 3. 输入站点名,显示即将到达的巴士信息(线路号、预计到达时间),显示当前正在该站点停靠的巴士,显示该站点下一班各线路巴士的预计等待时间; + 4. 输入起点和终点站点,推荐换乘方案,显示总行程时间、换乘次数、步行距离(简化),提供最快方案和最简方案(最少换乘)。 + +- 技术点要求 + + 1. 使用邻接表存储巴士站点网络。 + 2. 实现Dijkstra算法计算最优路径。 + 3. 使用文本文件读写数据。 + 4. 程序结构清晰,功能模块划分合理。 + +### 三、设计步骤 + +1. 根据课题,查阅相关资料,确定结构体设计。 +2. 明确相关功能,对功能部分进行设计及代码编写。 +3. 对所写代码进行测试。 +4. 撰写课程设计报告:字数约5000字(不包括程序清单)。 +5. 答辩。 diff --git a/PracticalTrain/DataStructure/data/routes.csv b/PracticalTrain/DataStructure/data/routes.csv new file mode 100644 index 0000000..b9c1845 --- /dev/null +++ b/PracticalTrain/DataStructure/data/routes.csv @@ -0,0 +1,13 @@ +id,routeName,stationCount +0,1,4 +0,1,2,3 +5.0,6.0,7.0 +1,2,5 +0,4,5,7,9 +8.0,6.0,10.0,5.0 +2,3,4 +1,6,4,2 +4.0,5.0,6.0 +3,4,3 +8,1,3 +7.0,12.0 diff --git a/PracticalTrain/DataStructure/data/stations.csv b/PracticalTrain/DataStructure/data/stations.csv new file mode 100644 index 0000000..6041d08 --- /dev/null +++ b/PracticalTrain/DataStructure/data/stations.csv @@ -0,0 +1,11 @@ +id,name,latitude,longitude,stopTime +0,վ,39.9042,116.4074,60 +1,,39.9100,116.4100,45 +2,ѧ,39.9200,116.4200,45 +3,Ƽ԰,39.9300,116.4300,45 +4,ҵ,39.9150,116.4250,60 +5,,39.9250,116.4350,45 +6,԰,39.9180,116.4180,30 +7,,39.9400,116.4400,90 +8,ҽԺ,39.9050,116.4150,50 +9,ͼ,39.9280,116.4280,40 diff --git a/PracticalTrain/DataStructure/include/graph.h b/PracticalTrain/DataStructure/include/graph.h new file mode 100644 index 0000000..70af584 --- /dev/null +++ b/PracticalTrain/DataStructure/include/graph.h @@ -0,0 +1,49 @@ +// include/graph.h +#ifndef GRAPH_H +#define GRAPH_H + +#include +#include "station.h" +#include "route.h" + +// ڽӱڵ +typedef struct AdjNode { + int stationId; + int routeId; + double travelTime; // ʻʱ() + struct AdjNode* next; +} AdjNode; + +// ڽӱ +typedef struct AdjList { + AdjNode* head; +} AdjList; + +// ͼṹ +typedef struct Graph { + AdjList adjLists[MAX_STATIONS]; + int vertexCount; +} Graph; + +// ·ڵ +typedef struct PathNode { + int stationId; + int routeId; + double time; + struct PathNode* next; +} PathNode; + +// ͼ +Graph* createGraph(int vertexCount); +void destroyGraph(Graph* graph); +void addEdge(Graph* graph, int from, int to, int routeId, double travelTime); +void buildGraphFromRoutes(Graph* graph, const BusRoute routes[], int routeCount, + const Station stations[], int stationCount); + +// ·ѯ +PathNode* dijkstra(Graph* graph, int start, int end, double* totalTime); +void freePath(PathNode* path); +void displayPath(PathNode* path, const Station stations[], int stationCount, + const BusRoute routes[], int routeCount); + +#endif \ No newline at end of file diff --git a/PracticalTrain/DataStructure/include/route.h b/PracticalTrain/DataStructure/include/route.h new file mode 100644 index 0000000..c93f2f4 --- /dev/null +++ b/PracticalTrain/DataStructure/include/route.h @@ -0,0 +1,22 @@ +// include/route.h +#ifndef ROUTE_H +#define ROUTE_H + +#include "station.h" + +#define MAX_STATIONS_PER_ROUTE 50 + +typedef struct BusRoute { + int id; + char routeName[50]; + int stationCount; + int stations[MAX_STATIONS_PER_ROUTE]; // վID + double segmentTimes[MAX_STATIONS_PER_ROUTE]; // ÿʻʱ() +} BusRoute; + +// · +int loadRoutes(const char* filename, BusRoute routes[], int maxRoutes); +void displayRoute(const BusRoute* route, const Station stations[], int stationCount); +void displayAllRoutes(const BusRoute routes[], int routeCount, const Station stations[], int stationCount); + +#endif \ No newline at end of file diff --git a/PracticalTrain/DataStructure/include/station.h b/PracticalTrain/DataStructure/include/station.h new file mode 100644 index 0000000..43fb942 --- /dev/null +++ b/PracticalTrain/DataStructure/include/station.h @@ -0,0 +1,23 @@ +// include/station.h +#ifndef STATION_H +#define STATION_H + +#define MAX_NAME 50 +#define MAX_STATIONS 100 + +typedef struct Station { + int id; + char name[MAX_NAME]; + double latitude; + double longitude; + int stopTime; // ͣʱ() +} Station; + +// վ +int loadStations(const char* filename, Station stations[], int maxStations); +int findStationByName(const Station stations[], int count, const char* name); +int findStationById(const Station stations[], int count, int id); +void displayStation(const Station* station); +void displayAllStations(const Station stations[], int count); + +#endif \ No newline at end of file diff --git a/PracticalTrain/DataStructure/src/graph.c b/PracticalTrain/DataStructure/src/graph.c new file mode 100644 index 0000000..a14ef01 --- /dev/null +++ b/PracticalTrain/DataStructure/src/graph.c @@ -0,0 +1,169 @@ +// src/graph.c +#include +#include +#include +#include "../include/graph.h" + +// ͼ +Graph* createGraph(int vertexCount) { + Graph* graph = (Graph*)malloc(sizeof(Graph)); + graph->vertexCount = vertexCount; + for (int i = 0; i < MAX_STATIONS; i++) { + graph->adjLists[i].head = NULL; + } + return graph; +} + +// ͼ +void destroyGraph(Graph* graph) { + if (!graph) return; + + for (int i = 0; i < MAX_STATIONS; i++) { + AdjNode* curr = graph->adjLists[i].head; + while (curr) { + AdjNode* temp = curr; + curr = curr->next; + free(temp); + } + } + free(graph); +} + +// ӱ +void addEdge(Graph* graph, int from, int to, int routeId, double travelTime) { + AdjNode* newNode = (AdjNode*)malloc(sizeof(AdjNode)); + newNode->stationId = to; + newNode->routeId = routeId; + newNode->travelTime = travelTime; + newNode->next = graph->adjLists[from].head; + graph->adjLists[from].head = newNode; +} + +// ·ͼ˫ +void buildGraphFromRoutes(Graph* graph, const BusRoute routes[], int routeCount, + const Station stations[], int stationCount) { + for (int r = 0; r < routeCount; r++) { + for (int i = 0; i < routes[r].stationCount - 1; i++) { + int from = routes[r].stations[i]; + int to = routes[r].stations[i + 1]; + double segmentTime = routes[r].segmentTimes[i]; + + // ȡվͣʱ + int fromIdx = findStationById(stations, stationCount, from); + int toIdx = findStationById(stations, stationCount, to); + + if (fromIdx == -1 || toIdx == -1) continue; + + double fromStopTime = stations[fromIdx].stopTime / 60.0; + double toStopTime = stations[toIdx].stopTime / 60.0; + + // : from -> to + addEdge(graph, from, to, r, segmentTime + fromStopTime); + + // : to -> fromַ֧̣ + addEdge(graph, to, from, r, segmentTime + toStopTime); + } + } + printf("ͼɣ֧˫·ߣ\n"); +} + +// Dijkstra㷨 +PathNode* dijkstra(Graph* graph, int start, int end, double* totalTime) { + double dist[MAX_STATIONS]; + int prev[MAX_STATIONS]; + int prevRoute[MAX_STATIONS]; + bool visited[MAX_STATIONS] = {false}; + + // ʼ + for (int i = 0; i < MAX_STATIONS; i++) { + dist[i] = DBL_MAX; + prev[i] = -1; + prevRoute[i] = -1; + } + dist[start] = 0; + + // Dijkstraѭ + for (int count = 0; count < graph->vertexCount; count++) { + double minDist = DBL_MAX; + int u = -1; + + // ҵδʵСڵ + for (int i = 0; i < MAX_STATIONS; i++) { + if (!visited[i] && dist[i] < minDist) { + minDist = dist[i]; + u = i; + } + } + + if (u == -1 || u == end) break; + visited[u] = true; + + // ڽڵ + AdjNode* node = graph->adjLists[u].head; + while (node != NULL) { + int v = node->stationId; + double weight = node->travelTime; + + if (!visited[v] && dist[u] + weight < dist[v]) { + dist[v] = dist[u] + weight; + prev[v] = u; + prevRoute[v] = node->routeId; + } + node = node->next; + } + } + + // Ƿҵ· + if (dist[end] == DBL_MAX) { + *totalTime = -1; + return NULL; + } + + *totalTime = dist[end]; + + // ؽ· + PathNode* path = NULL; + for (int v = end; v != -1; v = prev[v]) { + PathNode* newNode = (PathNode*)malloc(sizeof(PathNode)); + newNode->stationId = v; + newNode->routeId = prevRoute[v]; + newNode->time = dist[v]; + newNode->next = path; + path = newNode; + } + + return path; +} + +// ͷ· +void freePath(PathNode* path) { + while (path) { + PathNode* temp = path; + path = path->next; + free(temp); + } +} + +// ʾ· +void displayPath(PathNode* path, const Station stations[], int stationCount, + const BusRoute routes[], int routeCount) { + (void)routeCount; // Ϊδʹ,⾯ + + if (!path) return; + + PathNode* curr = path; + while (curr) { + int stationIdx = findStationById(stations, stationCount, curr->stationId); + if (stationIdx != -1) { + printf(" %s", stations[stationIdx].name); + + if (curr->next && curr->next->routeId != -1) { + printf(" -[%s]-> ", routes[curr->next->routeId].routeName); + } else if (!curr->next) { + printf(" ()"); + } + printf("\n"); + } + curr = curr->next; + } +} \ No newline at end of file diff --git a/PracticalTrain/DataStructure/src/main.c b/PracticalTrain/DataStructure/src/main.c new file mode 100644 index 0000000..e431952 --- /dev/null +++ b/PracticalTrain/DataStructure/src/main.c @@ -0,0 +1,170 @@ +// src/main.c +#include +#include +#include +#include "../include/station.h" +#include "../include/route.h" +#include "../include/graph.h" + +#define MAX_ROUTES 20 + +// ȫֱ +Station stations[MAX_STATIONS]; +BusRoute routes[MAX_ROUTES]; +int stationCount = 0; +int routeCount = 0; +Graph* graph = NULL; + +// +void printMenu(); +void queryRoute(); +void saveQueryResult(const char* filename, const char* startName, const char* endName, + PathNode* path, double totalTime); + +// ӡ˵ +void printMenu() { + printf("\nXTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT[\n"); + printf("U ʿ·߹ϵͳ U\n"); + printf("dTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTg\n"); + printf("U 1. ѯ· U\n"); + printf("U 2. ʾվ U\n"); + printf("U 3. ʾ· U\n"); + printf("U 4. ˳ϵͳ U\n"); + printf("^TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTa\n"); + printf("ѡ (1-4): "); +} + +// ѯ· +void queryRoute() { + char startName[MAX_NAME], endName[MAX_NAME]; + + printf("\nվ: "); + scanf("%s", startName); + printf("յվ: "); + scanf("%s", endName); + + int startId = findStationByName(stations, stationCount, startName); + int endId = findStationByName(stations, stationCount, endName); + + if (startId == -1) { + printf(": Ҳվ '%s'\n", startName); + return; + } + if (endId == -1) { + printf(": Ҳվ '%s'\n", endName); + return; + } + + double totalTime; + PathNode* path = dijkstra(graph, startId, endId, &totalTime); + + if (!path || totalTime < 0) { + printf("\nûҵ %s %s ·\n", startName, endName); + return; + } + + printf("\n========== ·ѯ ==========\n"); + printf(": %s\n", startName); + printf("յ: %s\n", endName); + printf("ʱ: %.2f \n", totalTime); + printf("\nϸ·:\n"); + + displayPath(path, stations, stationCount, routes, routeCount); + + printf("=====================================\n\n"); + + // + saveQueryResult("data/query_results.txt", startName, endName, path, totalTime); + + freePath(path); +} + +// ѯ +void saveQueryResult(const char* filename, const char* startName, const char* endName, + PathNode* path, double totalTime) { + FILE* fp = fopen(filename, "a"); + if (!fp) { + printf(": ޷ѯļ\n"); + return; + } + + fprintf(fp, "================================\n"); + fprintf(fp, ": %s\n", startName); + fprintf(fp, "յ: %s\n", endName); + fprintf(fp, "ʱ: %.2f \n", totalTime); + fprintf(fp, "·: "); + + PathNode* curr = path; + while (curr) { + int stationIdx = findStationById(stations, stationCount, curr->stationId); + if (stationIdx != -1) { + fprintf(fp, "%s", stations[stationIdx].name); + if (curr->next) { + fprintf(fp, " -> "); + } + } + curr = curr->next; + } + fprintf(fp, "\n"); + + fclose(fp); +} + +// +int main() { + printf("========================================\n"); + printf(" ʿ·߹ϵͳ v1.0\n"); + printf("========================================\n\n"); + + // + printf("ڼϵͳ...\n"); + stationCount = loadStations("data/stations.csv", stations, MAX_STATIONS); + if (stationCount == 0) { + printf(": ޷վ\n"); + return 1; + } + + routeCount = loadRoutes("data/routes.csv", routes, MAX_ROUTES); + if (routeCount == 0) { + printf(": ޷·\n"); + return 1; + } + + // ͼ + graph = createGraph(stationCount); + buildGraphFromRoutes(graph, routes, routeCount, stations, stationCount); + + printf("\nϵͳʼ!\n"); + + // ѭ + int choice; + while (1) { + printMenu(); + + if (scanf("%d", &choice) != 1) { + while (getchar() != '\n'); + printf("Ч,1-4\n"); + continue; + } + + switch (choice) { + case 1: + queryRoute(); + break; + case 2: + displayAllStations(stations, stationCount); + break; + case 3: + displayAllRoutes(routes, routeCount, stations, stationCount); + break; + case 4: + printf("\nлʹðʿ·߹ϵͳ!\n"); + destroyGraph(graph); + return 0; + default: + printf("Чѡ,1-4\n"); + } + } + + return 0; +} \ No newline at end of file diff --git a/PracticalTrain/DataStructure/src/route.c b/PracticalTrain/DataStructure/src/route.c new file mode 100644 index 0000000..08539be --- /dev/null +++ b/PracticalTrain/DataStructure/src/route.c @@ -0,0 +1,83 @@ +// src/route.c +#include +#include +#include +#include "../include/route.h" + +// ļ·Ϣ +int loadRoutes(const char* filename, BusRoute routes[], int maxRoutes) { + FILE* fp = fopen(filename, "r"); + if (!fp) { + printf(": ޷ļ %s\n", filename); + return 0; + } + + int count = 0; + char line[512]; + + // + if (fgets(line, sizeof(line), fp) == NULL) { + fclose(fp); + return 0; + } + + while (count < maxRoutes) { + // ȡϢ: id,routeName,stationCount + if (fscanf(fp, "%d,%49[^,],%d\n", + &routes[count].id, + routes[count].routeName, + &routes[count].stationCount) != 3) { + break; + } + + // ȡվ + if (fgets(line, sizeof(line), fp) == NULL) break; + char* token = strtok(line, ",\n"); + int idx = 0; + while (token != NULL && idx < routes[count].stationCount) { + routes[count].stations[idx++] = atoi(token); + token = strtok(NULL, ",\n"); + } + + // ȡʻʱ + if (fgets(line, sizeof(line), fp) == NULL) break; + token = strtok(line, ",\n"); + idx = 0; + while (token != NULL && idx < routes[count].stationCount - 1) { + routes[count].segmentTimes[idx++] = atof(token); + token = strtok(NULL, ",\n"); + } + + count++; + } + + fclose(fp); + printf("ɹ %d ·\n", count); + return count; +} + +// ʾ· +void displayRoute(const BusRoute* route, const Station stations[], int stationCount) { + printf("%s: ", route->routeName); + for (int i = 0; i < route->stationCount; i++) { + int stationIdx = findStationById(stations, stationCount, route->stations[i]); + if (stationIdx != -1) { + printf("%s", stations[stationIdx].name); + if (i < route->stationCount - 1) { + printf(" -> "); + } + } + } + printf("\n"); +} + +// ʾ· +void displayAllRoutes(const BusRoute routes[], int routeCount, + const Station stations[], int stationCount) { + printf("\n========== ·Ϣ ==========\n"); + for (int i = 0; i < routeCount; i++) { + displayRoute(&routes[i], stations, stationCount); + } + printf("ܼ: %d ·\n", routeCount); + printf("==================================\n"); +} \ No newline at end of file diff --git a/PracticalTrain/DataStructure/src/station.c b/PracticalTrain/DataStructure/src/station.c new file mode 100644 index 0000000..971ff5f --- /dev/null +++ b/PracticalTrain/DataStructure/src/station.c @@ -0,0 +1,75 @@ +// src/station.c +#include +#include +#include "../include/station.h" + +// ļվϢ +int loadStations(const char* filename, Station stations[], int maxStations) { + FILE* fp = fopen(filename, "r"); + if (!fp) { + printf(": ޷ļ %s\n", filename); + return 0; + } + + int count = 0; + char line[256]; + + // + if (fgets(line, sizeof(line), fp) == NULL) { + fclose(fp); + return 0; + } + + while (count < maxStations && + fscanf(fp, "%d,%49[^,],%lf,%lf,%d\n", + &stations[count].id, + stations[count].name, + &stations[count].latitude, + &stations[count].longitude, + &stations[count].stopTime) == 5) { + count++; + } + + fclose(fp); + printf("ɹ %d վ\n", count); + return count; +} + +// Ʋվ +int findStationByName(const Station stations[], int count, const char* name) { + for (int i = 0; i < count; i++) { + if (strcmp(stations[i].name, name) == 0) { + return stations[i].id; + } + } + return -1; +} + +// IDվ +int findStationById(const Station stations[], int count, int id) { + for (int i = 0; i < count; i++) { + if (stations[i].id == id) { + return i; + } + } + return -1; +} + +// ʾվϢ +void displayStation(const Station* station) { + printf(" ID: %d\n", station->id); + printf(" : %s\n", station->name); + printf(" γ: (%.4f, %.4f)\n", station->latitude, station->longitude); + printf(" ͣʱ: %d\n", station->stopTime); +} + +// ʾվ +void displayAllStations(const Station stations[], int count) { + printf("\n========== վϢ ==========\n"); + for (int i = 0; i < count; i++) { + printf("%d. %s (ͣʱ: %d)\n", + stations[i].id, stations[i].name, stations[i].stopTime); + } + printf("ܼ: %d վ\n", count); + printf("==================================\n"); +} \ No newline at end of file diff --git a/PracticalTrain/README.md b/PracticalTrain/README.md new file mode 100644 index 0000000..85b7fcc --- /dev/null +++ b/PracticalTrain/README.md @@ -0,0 +1,15 @@ + + +## 实训 + +### 文件介绍 + +```sh +. +└── DataStructure # 数据结构课程设计 +``` diff --git a/README.md b/README.md index 11f91b0..462f928 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ ```sh . ├── DataStructure # 数据结构 + ├── PracticalTrain # 实训 ├── Server # Node.js 从基础到项目实践 ├── Spider # Python 网络爬虫基础教程 └── Web # Web 前端开发技术 @@ -21,6 +22,7 @@ - [`Node.js` 从基础到项目实践](Server/README.md) - [`Python` 网络爬虫基础教程](Spider/README.md) - [`Web` 前端开发技术](Web/README.md) +- [实训](PracticalTrain/README.md) ## 📜 License