├── .clang-format ├── .clang-tidy ├── CMakeLists.txt ├── README.md ├── code ├── PrioritizedWaitingList │ ├── DateTime.cpp │ ├── DateTime.h │ ├── List.h │ ├── PrioritizedWaitingList.cpp │ ├── PrioritizedWaitingList.h │ ├── PrioritizedWaitingListTest.cpp │ ├── PurchaseInfo.h │ ├── Queue.h │ └── Utils.h ├── RailwayGraph │ ├── DisjointSet.h │ ├── Graph.h │ ├── List.h │ ├── Queue.h │ ├── RailwayGraph.cpp │ ├── RailwayGraph.h │ ├── RailwayGraphTest.cpp │ ├── RouteSectionInfo.cpp │ └── RouteSectionInfo.h ├── TicketManager │ ├── BPlusTree.h │ ├── DateTime.cpp │ ├── DateTime.h │ ├── List.h │ ├── Pair.h │ ├── SearchTable.h │ ├── TicketInfo.h │ ├── TicketManager.cpp │ ├── TicketManager.h │ ├── TicketManagerTest.cpp │ ├── TrainScheduler.cpp │ ├── TrainScheduler.h │ └── Utils.h ├── TrainScheduler │ ├── List.h │ ├── TrainScheduler.cpp │ ├── TrainScheduler.h │ ├── TrainSchedulerTest.cpp │ └── Utils.h ├── TripManager │ ├── BPlusTree.h │ ├── DateTime.cpp │ ├── DateTime.h │ ├── List.h │ ├── Pair.h │ ├── SearchTable.h │ ├── TripInfo.h │ ├── TripManager.cpp │ ├── TripManager.h │ ├── TripManagerTest.cpp │ └── Utils.h ├── UserManager │ ├── DynamicSearchTable.h │ ├── RedBlackTree.h │ ├── UserManager.h │ └── UserManagerTest.cpp └── WaitingList │ ├── DateTime.cpp │ ├── DateTime.h │ ├── PurchaseInfo.h │ ├── Queue.h │ ├── Utils.h │ ├── WaitingList.cpp │ ├── WaitingList.h │ └── WaitingListTest.cpp ├── init_database.sh ├── input.in ├── station.txt ├── textcode ├── chapter1 │ ├── max1max2Test.cpp │ ├── maxSubsequenceSum1.cpp │ ├── maxSubsequenceSum2.cpp │ ├── maxSubsequenceSum3.cpp │ └── maxSubsequenceSum4.cpp ├── chapter10 │ ├── CMakeLists.txt │ ├── adjListGraph.h │ ├── adjMatrixGraph.h │ ├── dijkstraTest.cpp │ ├── floydTest.cpp │ ├── kruskalPrimTest.cpp │ └── unweightedShortDistanceTest.cpp ├── chapter11 │ ├── CMakeLists.txt │ ├── climbStairs.cpp │ ├── isPrime.cpp │ ├── knapsack.cpp │ ├── nearestPointPair2D.cpp │ └── queenAll.cpp ├── chapter2 │ ├── CMakeLists.txt │ ├── LongLongInt.h │ ├── LongLongIntTest.cpp │ ├── list.h │ ├── multinomial.h │ ├── multinomialTest.cpp │ ├── sLinkList.h │ ├── sLinkListTest.cpp │ ├── seqList.h │ └── seqListTest.cpp ├── chapter3 │ ├── CMakeLists.txt │ ├── bracketMatcher.cpp │ ├── linkQueue.h │ ├── linkQueueTest.cpp │ ├── linkStack.h │ ├── linkStackTest.cpp │ ├── queue.h │ ├── seqQueue.h │ ├── seqQueueTest.cpp │ ├── seqStack.h │ ├── seqStackTest.cpp │ ├── stack.h │ └── washer.cpp ├── chapter4 │ ├── CMakeLists.txt │ ├── binaryTree.h │ ├── binaryTreeTest.cpp │ ├── btree.h │ ├── hfTree.h │ ├── hfTreeTest.cpp │ ├── priorityQueue.h │ ├── priorityQueueTest.cpp │ └── tree.h ├── chapter5 │ ├── CMakeLists.txt │ ├── binarySearchTest.cpp │ ├── disjointSet.h │ ├── disjointSetTest.cpp │ ├── orderedSeqSearchTest.cpp │ ├── seqSearchTest.cpp │ └── set.h ├── chapter6 │ ├── AVLTree.h │ ├── AVLTreeTest.cpp │ ├── CMakeLists.txt │ ├── binarySearchTree.h │ ├── binarySearchTreeTest.cpp │ ├── closeHashTable.h │ ├── closeHashTableTest.cpp │ ├── dynamicSearchTable.h │ ├── openHashTable.h │ ├── openHashTableTest.cpp │ ├── redBlackTree.h │ └── redBlackTreeTest.cpp ├── chapter7 │ ├── CMakeLists.txt │ ├── bubbleSortTest.cpp │ ├── bucketSortTest.cpp │ ├── heapSortTest.cpp │ ├── mergeSortTest.cpp │ ├── quickSortTest.cpp │ ├── shellSortTest.cpp │ ├── simpleInsertSortTest.cpp │ └── simpleSelectSortTest.cpp ├── chapter8 │ ├── BPlusTree.h │ ├── BPlusTreeTest.cpp │ ├── CMakeLists.txt │ ├── List.h │ ├── Pair.h │ └── StorageSearchTable.h └── chapter9 │ ├── CMakeLists.txt │ ├── EulerCircuitTest.cpp │ ├── adjListGraph.h │ ├── adjListGraphTest.cpp │ ├── adjMatrixGraph.h │ ├── adjMatrixGraphTest.cpp │ ├── criticalPathTest.cpp │ ├── graph.h │ └── topSortTest.cpp ├── trainsys ├── CommandParser.cpp ├── CommandParser.h ├── DataStructure │ ├── BPlusTree.h │ ├── BinarySearchTable.h │ ├── CachedBPlusTree.h │ ├── DisjointSet.h │ ├── Graph.h │ ├── List.h │ ├── Pair.h │ ├── Queue.h │ ├── RedBlackTree.h │ └── SearchTable.h ├── DateTime.cpp ├── DateTime.h ├── PurchaseInfo.h ├── RailwayGraph.cpp ├── RailwayGraph.h ├── RouteSectionInfo.cpp ├── RouteSectionInfo.h ├── SchedulerManager.cpp ├── SchedulerManager.h ├── StationManager.cpp ├── StationManager.h ├── TicketInfo.h ├── TicketManager.cpp ├── TicketManager.h ├── TrainScheduler.cpp ├── TrainScheduler.h ├── TrainSystem.cpp ├── TrainSystem.h ├── TripInfo.h ├── TripManager.cpp ├── TripManager.h ├── UserInfo.cpp ├── UserInfo.h ├── UserManager.cpp ├── UserManager.h ├── Utils.h ├── WaitingList.cpp ├── WaitingList.h └── main.cpp └── 习题答案.docx /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 2 3 | --- 4 | Language: Cpp 5 | DerivePointerAlignment: false 6 | PointerAlignment: Right 7 | ColumnLimit: 80 8 | AlignAfterOpenBracket: DontAlign 9 | AllowAllArgumentsOnNextLine: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: true 12 | AllowShortCaseLabelsOnASingleLine: true 13 | --- 14 | # Enable Customized Space Insertion If Clang-Format Version >= 14 15 | # SpaceBeforeParens: Custom 16 | # SpaceBeforeParensOptions: 17 | # AfterControlStatements: true 18 | # AfterFunctionDefinitionName: false 19 | # AfterOverloadedOperator: true 20 | # BeforeNonEmptyParentheses: false 21 | --- 22 | 23 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.16) 2 | PROJECT(TrainSystem) 3 | 4 | SET(CMAKE_CXX_STANDARD 14) 5 | SET(CMAKE_CXX_FLAGS "-O2") 6 | 7 | AUX_SOURCE_DIRECTORY(./trainsys SRC) 8 | 9 | ADD_EXECUTABLE(main ${SRC}) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 动手学数据结构与算法 电子资料仓库 2 | ### 仓库各目录中的内容 3 | - textcode 目录包含本书代码清单中的所有代码,按照章节进行排列,通常类名即为文件名,类名 + Test.cpp 即为该类的测试程序。例如,textcode/chapter2/seqList.h 及对应的 .cpp 文件包含代码清单 2-2 ~ 代码清单 2-5 顺序表的完整定义与实现。此外,本书介绍的数据结构简单应用也包含在内,例如,textcode/chapter2/multinomial.h 及 multinomialTest.cpp 是代码清单 2-14 所示的多项式类的实现与测试程序。 4 | 5 | - code 目录包含本书除第 1 章、第 7 章和第 11 章以外,每章的大型应用实现中各个应用模块的代码。由于涉及文件较多,将它们与 textcode 目录分开。通常,类名即为子目录名,例如,code/TrainScheduler 目录包含 2.5 节中列车运行计划管理类的完整实现与测试代码。 6 | 7 | - trainsys 目录包含整个大型应用——火车票管理系统的代码。 8 | 9 | - DataStructure 子目录是大型应用中使用的数据结构实现。注意,作为一个完整应用,其实现可能和textcode目录与code 目录中的代码有所差异。例如,余票管理类和行程管理类均使用了一对多B+树进行存储而非8.4节介绍的一对一B+树,这些差异已在每章介绍大型应用实现时阐明,读者可以亲自动手运行代码,比对这些差异,体会从简单的数据结构到复杂的大型应用实现的变化。 10 | - main.cpp 文件是火车票管理系统的主入口,与火车票管理系统的交互方式为命令行。 11 | - CommandParser.h 和 CommandParser.cpp 文件是火车票管理系统的命令解析类,它负责解析用户输入的指令,调用对应管理类的系统功能。 12 | - 其余 .h 文件和对应的 .cpp 文件是大型应用各个类的定义与具体实现。 13 | - input.in 文件(位于根目录)是火车票管理系统测试样例输入。 14 | - station.txt 文件(位于根目录)是火车票管理系统测试样例的站点列表。 15 | - init_database.sh 文件(位于根目录)用于清除火车票管理系统在磁盘上保存的数据文件。 16 | - ``习题答案.docx`` 包含每章最后一节习题中客观题的答案和部分主观题的解题思路。 17 | 18 | 19 | ### 本地环境搭建和仓库代码运行 20 | 火车票管理系统这一大型应用由许多文件构成,读者下载代码仓库后需要在本地搭建C++编译与测试环境后方可动手学习,具体环境搭建方法参见本书附录 B.3。 21 | 22 | 本书的所有代码在 GNU/Linux 环境下测试编译通过,因此推荐读者采用 g++ 9.4 或更新版本的 GNU C++ 编译器,并选用 ``-lm、-Wall、-Wextra、-O1、-std=c++14`` 等编译参数。例如,读者可以在命令行中执行 ``g++ max1max2Test.cpp -o max1max2Test -lm -Wall -Wextra -O1 -std=c++14`` ,将代码清单1-1 函数 max1 与 max2 的实现及其测试程序的源文件max1max2Test.cpp 编译为可执行文件 max1max2Test。 -------------------------------------------------------------------------------- /code/PrioritizedWaitingList/List.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | template 9 | class list { 10 | public: 11 | virtual void clear() = 0; 12 | virtual int length() const = 0; 13 | virtual void insert(int i, const elemType &x) = 0; 14 | virtual void remove(int i) = 0; 15 | virtual elemType visit(int i) const = 0; 16 | virtual ~list() {}; 17 | }; 18 | 19 | template 20 | class seqList : public list { 21 | protected: 22 | elemType *data; 23 | int currentLength; 24 | int maxSize; 25 | void doubleSpace(); 26 | 27 | public: 28 | seqList(int initSize = 10); 29 | ~seqList() { delete[] data; } 30 | void clear() { currentLength = 0; } 31 | int length() const { return currentLength; } 32 | bool empty() const { return currentLength == 0; } 33 | void insert(int i, const elemType &x); 34 | void remove(int i); 35 | elemType visit(int i) const { return data[i]; } 36 | 37 | // 新增三个成员函数对顺序表尾部进行操作 38 | void pushBack(const elemType &x) { insert(length(), x); } 39 | void popBack() { remove(length() - 1); } 40 | elemType back() const { return visit(length() - 1); } 41 | }; 42 | 43 | template 44 | seqList::seqList(int initSize) { 45 | data = new elemType[initSize]; 46 | maxSize = initSize; 47 | currentLength = 0; 48 | } 49 | 50 | // 自动扩容函数doubleSpace() 51 | template 52 | void seqList::doubleSpace() { 53 | elemType *tmp = data; 54 | maxSize *= 2; 55 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 56 | for (int i = 0; i < currentLength; ++i) 57 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 58 | delete[] tmp; // 回收旧空间 59 | } 60 | 61 | // 在第i个位置插入元素x 62 | template 63 | void seqList::insert(int i, const elemType &x) { 64 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 65 | if (currentLength == maxSize) doubleSpace(); 66 | 67 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 68 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 69 | data[i] = x; 70 | ++currentLength; 71 | } 72 | 73 | // 删除第i个位置的元素 74 | template 75 | void seqList::remove(int i) { 76 | // 将第i+1个元素到最后一个元素全部前移一个位置 77 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 78 | --currentLength; 79 | } 80 | 81 | } // namespace trainsys 82 | 83 | #endif -------------------------------------------------------------------------------- /code/PrioritizedWaitingList/PrioritizedWaitingList.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单4-20 PrioritizedWaitingList 类的实现 2 | #include "PrioritizedWaitingList.h" 3 | #include 4 | #include 5 | #include "DateTime.h" 6 | 7 | namespace trainsys { 8 | 9 | PrioritizedWaitingList::PrioritizedWaitingList() {} 10 | 11 | PrioritizedWaitingList::~PrioritizedWaitingList() {} 12 | 13 | void PrioritizedWaitingList::addToPrioritizedWaitingList( 14 | const PurchaseInfo &purchaseInfo) { 15 | purchaseQueue.enQueue(purchaseInfo); 16 | } 17 | 18 | void PrioritizedWaitingList::removeHeadFromPrioritizedWaitingList() { 19 | purchaseQueue.deQueue(); 20 | } 21 | 22 | const PurchaseInfo PrioritizedWaitingList::getFrontPurchaseInfo() const { 23 | return purchaseQueue.getHead(); 24 | } 25 | 26 | bool PrioritizedWaitingList::isEmpty() const { 27 | return purchaseQueue.isEmpty(); 28 | } 29 | 30 | }; // namespace trainsys 31 | -------------------------------------------------------------------------------- /code/PrioritizedWaitingList/PrioritizedWaitingList.h: -------------------------------------------------------------------------------- 1 | // 代码清单4-20 PrioritizedWaitingList 类的定义 2 | #ifndef WAITINGLIST_H 3 | #define WAITINGLIST_H 4 | 5 | #include "Utils.h" 6 | #include "PurchaseInfo.h" 7 | #include "Queue.h" 8 | #include "DateTime.h" 9 | 10 | namespace trainsys { 11 | 12 | class PrioritizedWaitingList { // 带优先级的排队交易类 13 | private: 14 | priorityQueue purchaseQueue; 15 | 16 | public: 17 | PrioritizedWaitingList(); 18 | ~PrioritizedWaitingList(); 19 | // 将订单按照优先级插入队列的合适位置 20 | void addToPrioritizedWaitingList(const PurchaseInfo &purchaseInfo); 21 | // 将队头的订单移出队列 22 | void removeHeadFromPrioritizedWaitingList(); 23 | // 获取队头的订单 24 | const PurchaseInfo getFrontPurchaseInfo() const; 25 | // 判断队列是否为空 26 | bool isEmpty() const; 27 | }; 28 | 29 | } // namespace trainsys 30 | 31 | #endif // PRORITIZEDWAITINGLIST_H -------------------------------------------------------------------------------- /code/PrioritizedWaitingList/PrioritizedWaitingListTest.cpp: -------------------------------------------------------------------------------- 1 | // PrioritizedWaitingList 类的测试程序 2 | // 编译命令:g++ PrioritizedWaitingList.cpp PrioritizedWaitingListTest.cpp DateTime.cpp -o code.out 3 | // 样例输出: 4 | // User: User2 with priviledge: 6 5 | // Date: 02-02 6 | // DepartureStation: 470 7 | // Type: Ordering 8 | 9 | // User: User3 with priviledge: 4 10 | // Date: 03-03 11 | // DepartureStation: 626 12 | // Type: Ordering 13 | 14 | // User: User4 with priviledge: 2 15 | // Date: 04-04 16 | // DepartureStation: 1318 17 | // Type: Ordering 18 | 19 | // User: User4 with priviledge: 2 20 | // Date: 05-04 21 | // DepartureStation: 1318 22 | // Type: Ordering 23 | 24 | // User: User4 with priviledge: 2 25 | // Date: 05-04 26 | // DepartureStation: 1318 27 | // Type: Refunding 28 | 29 | // User: User1 with priviledge: 0 30 | // Date: 01-01 31 | // DepartureStation: 295 32 | // Type: Ordering 33 | 34 | #include "PrioritizedWaitingList.h" 35 | 36 | int main() { 37 | trainsys::PrioritizedWaitingList wl; 38 | wl.addToPrioritizedWaitingList( 39 | trainsys::PurchaseInfo(trainsys::User("User1", "Psd1", "Mail1", 0), 40 | trainsys::TrainID("1462"), trainsys::Date(1, 1), 295, 1)); 41 | wl.addToPrioritizedWaitingList( 42 | trainsys::PurchaseInfo(trainsys::User("User2", "Psd2", "Mail2", 6), 43 | trainsys::TrainID("G8"), trainsys::Date(2, 2), 470, 1)); 44 | wl.addToPrioritizedWaitingList( 45 | trainsys::PurchaseInfo(trainsys::User("User3", "Psd3", "Mail3", 4), 46 | trainsys::TrainID("T110"), trainsys::Date(3, 3), 626, 1)); 47 | wl.addToPrioritizedWaitingList( 48 | trainsys::PurchaseInfo(trainsys::User("User4", "Psd4", "Mail4", 2), 49 | trainsys::TrainID("G18"), trainsys::Date(5, 4), 1318, 1)); 50 | wl.addToPrioritizedWaitingList( 51 | trainsys::PurchaseInfo(trainsys::User("User4", "Psd4", "Mail4", 2), 52 | trainsys::TrainID("G18"), trainsys::Date(5, 4), 1318, -1)); 53 | wl.addToPrioritizedWaitingList( 54 | trainsys::PurchaseInfo(trainsys::User("User4", "Psd4", "Mail4", 2), 55 | trainsys::TrainID("G18"), trainsys::Date(4, 4), 1318, 1)); 56 | while (!wl.isEmpty()) { 57 | std::cout << "User: " << wl.getFrontPurchaseInfo().getUser().getName() 58 | << " with priviledge: " << wl.getFrontPurchaseInfo().getUser().getPrivilege() 59 | << std::endl; 60 | std::cout << "Date: " << wl.getFrontPurchaseInfo().getDate() << std::endl; 61 | std::cout << "DepartureStation: " << wl.getFrontPurchaseInfo().getDepartureStation() 62 | << std::endl; 63 | std::cout << "Type: " << (wl.getFrontPurchaseInfo().isOrdering() ? "Ordering" : "Refunding") 64 | << std::endl << std::endl; 65 | wl.removeHeadFromPrioritizedWaitingList(); 66 | } 67 | return 0; 68 | } -------------------------------------------------------------------------------- /code/PrioritizedWaitingList/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace trainsys { 8 | 9 | const int MAX_TRAINID_LEN = 20; 10 | const int MAX_USERNAME_LEN = 20; 11 | const int MAX_PASSWORD_LEN = 30; 12 | 13 | const int MAX_PASSING_STATION_NUMBER = 30; 14 | 15 | const int MAX_STATIONID = 1000; 16 | const int MAX_STATIONNAME_LEN = 30; 17 | 18 | const int ADMIN_PRIVILEGE = 10; 19 | 20 | const int BUSY_STATE_TRESHOLD = 1; 21 | 22 | struct String; 23 | 24 | using UserID = long long; 25 | using StationID = int; 26 | using TrainID = String; 27 | using StationName = String; 28 | 29 | const int MAX_STRING_LENGTH = 50; 30 | 31 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 32 | struct String { 33 | char index[MAX_STRING_LENGTH]; 34 | 35 | String() = default; 36 | 37 | explicit String(const char *str) { strcpy(index, str); } 38 | 39 | String(const String &other) { 40 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 41 | index[i] = other.index[i]; 42 | } 43 | } 44 | 45 | String &operator=(const String &other) { 46 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 47 | index[i] = other.index[i]; 48 | } 49 | return *this; 50 | } 51 | 52 | friend bool operator>(const String &lhs, const String &rhs) { 53 | return std::string(lhs.index) > std::string(rhs.index); 54 | } 55 | 56 | friend bool operator>=(const String &lhs, const String &rhs) { 57 | return std::string(lhs.index) >= std::string(rhs.index); 58 | } 59 | 60 | friend bool operator<(const String &lhs, const String &rhs) { 61 | return std::string(lhs.index) < std::string(rhs.index); 62 | } 63 | 64 | friend bool operator<=(const String &lhs, const String &rhs) { 65 | return std::string(lhs.index) <= std::string(rhs.index); 66 | } 67 | 68 | friend bool operator==(const String &lhs, const String &rhs) { 69 | return std::string(lhs.index) == std::string(rhs.index); 70 | } 71 | 72 | friend bool operator!=(const String &lhs, const String &rhs) { 73 | return std::string(lhs.index) != std::string(rhs.index); 74 | } 75 | 76 | friend std::ostream &operator<<( 77 | std::ostream &os, const String &obj) { 78 | os << obj.index; 79 | return os; 80 | } 81 | }; 82 | 83 | } // namespace trainsys 84 | 85 | #endif -------------------------------------------------------------------------------- /code/RailwayGraph/DisjointSet.h: -------------------------------------------------------------------------------- 1 | #ifndef DISJOINTSET_H_ 2 | #define DISJOINTSET_H_ 3 | 4 | namespace trainsys { 5 | 6 | class DisjointSet { 7 | private: 8 | int size; 9 | int *parent; 10 | 11 | public: 12 | DisjointSet(int n) { 13 | size = n; 14 | parent = new int[size]; 15 | for (int i = 0; i < size; ++i) parent[i] = -1; 16 | } 17 | 18 | ~DisjointSet() { delete[] parent; } 19 | 20 | void join(int root1, int root2) { 21 | if (root1 == root2) return; 22 | if (parent[root1] > parent[root2]) { 23 | parent[root2] += parent[root1]; 24 | parent[root1] = root2; 25 | } else { 26 | parent[root1] += parent[root2]; 27 | parent[root2] = root1; 28 | } 29 | } 30 | 31 | int find(int x) { 32 | if (parent[x] < 0) return x; 33 | return parent[x] = find(parent[x]); 34 | } 35 | }; 36 | 37 | } // namespace trainsys 38 | 39 | #endif -------------------------------------------------------------------------------- /code/RailwayGraph/Graph.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPH_H_ 2 | #define GRAPH_H_ 3 | 4 | namespace trainsys { 5 | 6 | // 对于简化版的图存储,ver 直接使用 StationID (int) 7 | // edge 的类型是 edgeType 8 | // 相较代码清单9-1 减少了一个模板参数 9 | template 10 | class graph { 11 | public: 12 | virtual void insert(int x, int y, edgeType &w) = 0; 13 | virtual void remove(int x, int y) = 0; 14 | virtual bool exist(int x, int y) const = 0; 15 | virtual ~graph() {} 16 | int numOfVer() const { return Vers; } 17 | int numOfEdges() const { return Edges; } 18 | 19 | protected: 20 | int Vers; 21 | int Edges; 22 | }; 23 | 24 | // 代码清单9-14 简化版adjListGraph类的定义 25 | template 26 | class adjListGraph : public graph { 27 | public: 28 | adjListGraph(int vers); 29 | void insert(int u, int v, edgeType &w); 30 | void remove(int u, int v); 31 | bool exist(int u, int v) const; 32 | ~adjListGraph(); 33 | 34 | struct edgeNode { 35 | int end; 36 | edgeType weight; 37 | edgeNode *next; 38 | 39 | edgeNode(int e, const edgeType &w, edgeNode *n = nullptr) 40 | : end(e), weight(w), next(n) {} 41 | }; 42 | 43 | edgeNode **verList; 44 | }; 45 | 46 | template 47 | adjListGraph::adjListGraph(int vers) { 48 | this->Vers = vers; 49 | this->Edges = 0; 50 | verList = new edgeNode *[vers]; 51 | for (int i = 0; i < this->Vers; ++i) verList[i] = nullptr; 52 | } 53 | 54 | template 55 | adjListGraph::~adjListGraph() { 56 | for (int i = 0; i < this->Vers; ++i) { 57 | for (edgeNode *p = verList[i]; p != nullptr; p = verList[i]) { 58 | verList[i] = p->next; 59 | delete p; 60 | } 61 | } 62 | delete[] verList; 63 | } 64 | 65 | template 66 | void adjListGraph::insert(int u, int v, edgeType &w) { 67 | verList[u] = new edgeNode(v, w, verList[u]); 68 | this->Edges++; 69 | } 70 | 71 | template 72 | void adjListGraph::remove(int u, int v) { 73 | edgeNode *p = verList[u], *q; 74 | 75 | if (p != nullptr) return; 76 | if (p->end == v) { 77 | verList[u] = p->next; 78 | delete p; 79 | this->Edges--; 80 | return; 81 | } 82 | while (p->next != nullptr && p->next->end != v) p = p->next; 83 | if (p->next != nullptr) { 84 | q = p->next; 85 | p->next = q->next; 86 | delete q; 87 | this->Edges--; 88 | } 89 | } 90 | 91 | template 92 | bool adjListGraph::exist(int u, int v) const { 93 | edgeNode *p = verList[u]; 94 | while (p != nullptr && p->end != v) p = p->next; 95 | return p != nullptr; 96 | } 97 | 98 | } // namespace trainsys 99 | 100 | #endif // GRAPH_H_ -------------------------------------------------------------------------------- /code/RailwayGraph/List.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | template 9 | class list { 10 | public: 11 | virtual void clear() = 0; 12 | virtual int length() const = 0; 13 | virtual void insert(int i, const elemType &x) = 0; 14 | virtual void remove(int i) = 0; 15 | virtual elemType visit(int i) const = 0; 16 | virtual ~list() {}; 17 | }; 18 | 19 | template 20 | class seqList : public list { 21 | protected: 22 | elemType *data; 23 | int currentLength; 24 | int maxSize; 25 | void doubleSpace(); 26 | 27 | public: 28 | seqList(int initSize = 10); 29 | ~seqList() { delete[] data; } 30 | void clear() { currentLength = 0; } 31 | int length() const { return currentLength; } 32 | bool empty() const { return currentLength == 0; } 33 | void insert(int i, const elemType &x); 34 | void remove(int i); 35 | elemType visit(int i) const { return data[i]; } 36 | 37 | // 新增三个成员函数对顺序表尾部进行操作 38 | void pushBack(const elemType &x) { insert(length(), x); } 39 | void popBack() { remove(length() - 1); } 40 | elemType back() const { return visit(length() - 1); } 41 | }; 42 | 43 | template 44 | seqList::seqList(int initSize) { 45 | data = new elemType[initSize]; 46 | maxSize = initSize; 47 | currentLength = 0; 48 | } 49 | 50 | // 自动扩容函数doubleSpace() 51 | template 52 | void seqList::doubleSpace() { 53 | elemType *tmp = data; 54 | maxSize *= 2; 55 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 56 | for (int i = 0; i < currentLength; ++i) 57 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 58 | delete[] tmp; // 回收旧空间 59 | } 60 | 61 | // 在第i个位置插入元素x 62 | template 63 | void seqList::insert(int i, const elemType &x) { 64 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 65 | if (currentLength == maxSize) doubleSpace(); 66 | 67 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 68 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 69 | data[i] = x; 70 | ++currentLength; 71 | } 72 | 73 | // 删除第i个位置的元素 74 | template 75 | void seqList::remove(int i) { 76 | // 将第i+1个元素到最后一个元素全部前移一个位置 77 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 78 | --currentLength; 79 | } 80 | 81 | } // namespace trainsys 82 | 83 | #endif -------------------------------------------------------------------------------- /code/RailwayGraph/RailwayGraph.h: -------------------------------------------------------------------------------- 1 | // RailwayGraph 类的定义 2 | // 包括:代码清单5-9与9-16 3 | #ifndef RAILWAY_GRAPH_H_ 4 | #define RAILWAY_GRAPH_H_ 5 | 6 | #include "DisjointSet.h" 7 | #include "Graph.h" 8 | #include "List.h" 9 | #include "RouteSectionInfo.h" 10 | 11 | namespace trainsys { 12 | 13 | class RailwayGraph { 14 | private: 15 | using GraphType = adjListGraph; 16 | GraphType routeGraph; 17 | DisjointSet stationSet; 18 | 19 | public: 20 | RailwayGraph(); 21 | ~RailwayGraph(); 22 | // 把两个站点所属的并查集子集合并 23 | void connectStation( 24 | StationID departureStationID, StationID arrivalStationID); 25 | 26 | // 查询两站点之间是否可达 27 | bool checkStationAccessibility( 28 | StationID departureStationID, StationID arrivalStationID); 29 | 30 | // 向列车运行图添加一条边 31 | void addRoute(StationID departureStationID, 32 | StationID arrivalStationID, int duration, int price, 33 | TrainID trainID); 34 | 35 | void displayRoute( 36 | StationID departureStationID, StationID arrivalStationID); 37 | 38 | void shortestPath(StationID departureStationID, 39 | StationID arrivalStationID, int type); 40 | 41 | private: 42 | void routeDfs(int curIdx, int arrivalIdx, 43 | seqList &prevStations, bool *visited); 44 | }; 45 | 46 | } // namespace trainsys 47 | 48 | #endif -------------------------------------------------------------------------------- /code/RailwayGraph/RailwayGraphTest.cpp: -------------------------------------------------------------------------------- 1 | // RailwayGraph 类的测试程序 2 | // 编译命令:g++ RailwayGraph.cpp RailwayGraphTest.cpp RouteSectionInfo.cpp -o code.out 3 | // 样例输出: 4 | // 1 -> 7 is accessible 5 | // 3 -> 7 is not accessible 6 | // route found: 1 2 4 5 7 7 | // shortest path: 2 4 5 7 8 | // shortest path: 2 4 5 7 9 | // 1 -> 7 is accessible 10 | // 3 -> 7 is accessible 11 | // shortest path: 3 4 5 7 12 | // shortest path: 2 4 6 7 13 | 14 | #include "RailwayGraph.h" 15 | 16 | namespace trainsys { 17 | 18 | RailwayGraph *railwayGraph; 19 | 20 | void addRoute1(RailwayGraph *graph) { 21 | graph->addRoute(1, 2, 10, 20, (String) "G1"); 22 | graph->addRoute(2, 4, 10, 20, (String) "G1"); 23 | graph->addRoute(4, 5, 20, 10, (String) "G1"); 24 | graph->addRoute(5, 7, 20, 10, (String) "G1"); 25 | } 26 | 27 | void addRoute2(RailwayGraph *graph) { 28 | graph->addRoute(1, 3, 20, 10, (String) "G2"); 29 | graph->addRoute(3, 4, 20, 10, (String) "G2"); 30 | graph->addRoute(4, 6, 10, 20, (String) "G2"); 31 | graph->addRoute(6, 7, 10, 20, (String) "G2"); 32 | } 33 | 34 | void railwayGraphTest() { 35 | railwayGraph = new RailwayGraph(); 36 | addRoute1(railwayGraph); 37 | if (railwayGraph->checkStationAccessibility(1, 7)) { 38 | std::cout << "1 -> 7 is accessible" << std::endl; 39 | } else { 40 | std::cout << "1 -> 7 is not accessible" << std::endl; 41 | } 42 | if (railwayGraph->checkStationAccessibility(3, 7)) { 43 | std::cout << "3 -> 7 is accessible" << std::endl; 44 | } else { 45 | std::cout << "3 -> 7 is not accessible" << std::endl; 46 | } 47 | railwayGraph->displayRoute(1, 7); 48 | railwayGraph->shortestPath(1, 7, 0); 49 | railwayGraph->shortestPath(1, 7, 1); 50 | 51 | addRoute2(railwayGraph); 52 | if (railwayGraph->checkStationAccessibility(1, 7)) { 53 | std::cout << "1 -> 7 is accessible" << std::endl; 54 | } else { 55 | std::cout << "1 -> 7 is not accessible" << std::endl; 56 | } 57 | if (railwayGraph->checkStationAccessibility(3, 7)) { 58 | std::cout << "3 -> 7 is accessible" << std::endl; 59 | } else { 60 | std::cout << "3 -> 7 is not accessible" << std::endl; 61 | } 62 | railwayGraph->shortestPath(1, 7, 0); 63 | railwayGraph->shortestPath(1, 7, 1); 64 | delete railwayGraph; 65 | } 66 | } // namespace trainsys 67 | 68 | int main() { 69 | trainsys::railwayGraphTest(); 70 | return 0; 71 | } -------------------------------------------------------------------------------- /code/RailwayGraph/RouteSectionInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "RouteSectionInfo.h" 2 | 3 | namespace trainsys { 4 | 5 | RouteSectionInfo::RouteSectionInfo(TrainID trainID, 6 | StationID arrivalStation, int price, int duration) { 7 | this->trainID = trainID; 8 | this->arrivalStation = arrivalStation; 9 | this->price = price; 10 | this->duration = duration; 11 | } 12 | 13 | RouteSectionInfo::RouteSectionInfo(const RouteSectionInfo &rhs) { 14 | this->trainID = rhs.trainID; 15 | this->arrivalStation = rhs.arrivalStation; 16 | this->price = rhs.price; 17 | this->duration = rhs.duration; 18 | } 19 | 20 | } // namespace trainsys -------------------------------------------------------------------------------- /code/RailwayGraph/RouteSectionInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef ROUTE_SECTION_INFO_H_ 2 | #define ROUTE_SECTION_INFO_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | const int MAX_STRING_LENGTH = 50; 9 | 10 | struct String { 11 | char index[MAX_STRING_LENGTH]; 12 | 13 | String() = default; 14 | 15 | explicit String(const char *str) { strcpy(index, str); } 16 | 17 | String(const String &other) { 18 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 19 | index[i] = other.index[i]; 20 | } 21 | } 22 | 23 | String &operator=(const String &other) { 24 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 25 | index[i] = other.index[i]; 26 | } 27 | return *this; 28 | } 29 | }; 30 | 31 | using StationID = int; 32 | using TrainID = String; 33 | using StationName = String; 34 | 35 | // 代码清单9-15 RouteSectionInfo 结构体的定义 36 | struct RouteSectionInfo { 37 | TrainID trainID; 38 | StationID arrivalStation; 39 | int price; 40 | int duration; 41 | 42 | RouteSectionInfo() = default; 43 | RouteSectionInfo(TrainID trainID, StationID arrivalStation, 44 | int price, int duration); 45 | RouteSectionInfo(const RouteSectionInfo &rhs); 46 | ~RouteSectionInfo() = default; 47 | }; 48 | 49 | } // namespace trainsys 50 | 51 | #endif // ROUTE_SECTION_INFO -------------------------------------------------------------------------------- /code/TicketManager/List.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | template 9 | class list { 10 | public: 11 | virtual void clear() = 0; 12 | virtual int length() const = 0; 13 | virtual void insert(int i, const elemType &x) = 0; 14 | virtual void remove(int i) = 0; 15 | virtual elemType visit(int i) const = 0; 16 | virtual ~list() {}; 17 | }; 18 | 19 | template 20 | class seqList : public list { 21 | protected: 22 | elemType *data; 23 | int currentLength; 24 | int maxSize; 25 | void doubleSpace(); 26 | 27 | public: 28 | seqList(int initSize = 10); 29 | ~seqList() { delete[] data; } 30 | void clear() { currentLength = 0; } 31 | int length() const { return currentLength; } 32 | bool empty() const { return currentLength == 0; } 33 | void insert(int i, const elemType &x); 34 | void remove(int i); 35 | elemType visit(int i) const { return data[i]; } 36 | 37 | // 新增三个成员函数对顺序表尾部进行操作 38 | void pushBack(const elemType &x) { insert(length(), x); } 39 | void popBack() { remove(length() - 1); } 40 | elemType back() const { return visit(length() - 1); } 41 | }; 42 | 43 | template 44 | seqList::seqList(int initSize) { 45 | data = new elemType[initSize]; 46 | maxSize = initSize; 47 | currentLength = 0; 48 | } 49 | 50 | // 自动扩容函数doubleSpace() 51 | template 52 | void seqList::doubleSpace() { 53 | elemType *tmp = data; 54 | maxSize *= 2; 55 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 56 | for (int i = 0; i < currentLength; ++i) 57 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 58 | delete[] tmp; // 回收旧空间 59 | } 60 | 61 | // 在第i个位置插入元素x 62 | template 63 | void seqList::insert(int i, const elemType &x) { 64 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 65 | if (currentLength == maxSize) doubleSpace(); 66 | 67 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 68 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 69 | data[i] = x; 70 | ++currentLength; 71 | } 72 | 73 | // 删除第i个位置的元素 74 | template 75 | void seqList::remove(int i) { 76 | // 将第i+1个元素到最后一个元素全部前移一个位置 77 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 78 | --currentLength; 79 | } 80 | 81 | } // namespace trainsys 82 | 83 | #endif -------------------------------------------------------------------------------- /code/TicketManager/Pair.h: -------------------------------------------------------------------------------- 1 | #ifndef PAIR_H 2 | #define PAIR_H 3 | 4 | namespace trainsys { 5 | 6 | template 7 | struct Pair { 8 | FirstType first; 9 | SecondType second; 10 | 11 | Pair() {} 12 | Pair(const FirstType &first, const SecondType &second) 13 | : first(first), second(second) {} 14 | }; 15 | 16 | template 17 | bool checkPairLess(const Pair &lhs, 18 | const Pair &rhs) { 19 | if (lhs.first != rhs.first) { 20 | return lhs.first < rhs.first; 21 | } else { 22 | return lhs.second < rhs.second; 23 | } 24 | } 25 | 26 | template 27 | bool checkPairEqual(const Pair &lhs, 28 | const Pair &rhs) { 29 | return lhs.first == rhs.first && lhs.second == rhs.second; 30 | } 31 | 32 | } // namespace trainsys 33 | 34 | #endif -------------------------------------------------------------------------------- /code/TicketManager/SearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef SEARCH_TABLE_H_ 2 | #define SEARCH_TABLE_H_ 3 | 4 | namespace trainsys { 5 | 6 | template 7 | class StorageSearchTable { 8 | public: 9 | virtual seqList find(const KeyType &key) = 0; 10 | virtual void insert(const KeyType &key, const ValueType &val) = 0; 11 | virtual void remove(const KeyType &key, const ValueType &val) = 0; 12 | virtual ~StorageSearchTable() {}; 13 | }; 14 | 15 | } // namespace trainsys 16 | 17 | #endif -------------------------------------------------------------------------------- /code/TicketManager/TicketInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef TICKETINFO_H_ 2 | #define TICKETINFO_H_ 3 | 4 | #include "Utils.h" 5 | 6 | namespace trainsys { 7 | 8 | struct TicketInfo { 9 | TrainID trainID; 10 | StationID departureStation; 11 | StationID arrivalStation; 12 | int seatNum; 13 | int price; 14 | int duration; 15 | Date date; 16 | 17 | bool operator==(const TicketInfo &rhs) const { 18 | return trainID == rhs.trainID && departureStation == rhs.departureStation && 19 | arrivalStation == rhs.arrivalStation && seatNum == rhs.seatNum && 20 | price == rhs.price && duration == rhs.duration && date == rhs.date; 21 | } 22 | 23 | bool operator!=(const TicketInfo &rhs) const { return !(*this == rhs); } 24 | 25 | bool operator<(const TicketInfo &rhs) const { 26 | if (trainID != rhs.trainID) { 27 | return trainID < rhs.trainID; 28 | } else if (departureStation != rhs.departureStation) { 29 | return departureStation < rhs.departureStation; 30 | } else if (arrivalStation != rhs.arrivalStation) { 31 | return arrivalStation < rhs.arrivalStation; 32 | } else if (date != rhs.date) { 33 | return date < rhs.date; 34 | } else if (seatNum != rhs.seatNum) { 35 | return seatNum < rhs.seatNum; 36 | } else if (price != rhs.price) { 37 | return price < rhs.price; 38 | } else { 39 | return duration < rhs.duration; 40 | } 41 | } 42 | 43 | friend std::ostream &operator<<( 44 | std::ostream &os, const TicketInfo &ticketInfo) { 45 | os << "TrainID: " << ticketInfo.trainID << std::endl; 46 | os << "Departure Station: " << ticketInfo.departureStation << std::endl; 47 | os << "Arrival Station: " << ticketInfo.arrivalStation << std::endl; 48 | os << "Seat Number: " << ticketInfo.seatNum << std::endl; 49 | os << "Price: " << ticketInfo.price << std::endl; 50 | os << "Duration: " << ticketInfo.duration << std::endl; 51 | os << "Date: " << ticketInfo.date << std::endl; 52 | return os; 53 | } 54 | }; 55 | 56 | } // namespace trainsys 57 | 58 | #endif -------------------------------------------------------------------------------- /code/TicketManager/TicketManager.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单8-10到8-12 TicketManager类的实现 2 | #include "TicketManager.h" 3 | 4 | #include "List.h" 5 | #include "TrainScheduler.h" 6 | 7 | namespace trainsys { 8 | 9 | TicketManager::TicketManager(const std::string &filename) 10 | : ticketInfo(filename) {} 11 | 12 | TicketManager::~TicketManager() {} 13 | 14 | int TicketManager::querySeat( 15 | const TrainID &trainID, const Date &date, const StationID &stationID) { 16 | seqList relatedInfo = ticketInfo.find(trainID); 17 | for (int i = 0; i < relatedInfo.length(); ++i) { 18 | if (relatedInfo.visit(i).date == date && 19 | relatedInfo.visit(i).departureStation == stationID) { 20 | return relatedInfo.visit(i).seatNum; 21 | } 22 | } 23 | return -1; // 出错,没有找到符合条件的车票 24 | } 25 | 26 | int TicketManager::updateSeat(const TrainID &trainID, const Date &date, 27 | const StationID &stationID, int delta) { 28 | seqList relatedInfo = ticketInfo.find(trainID); 29 | for (int i = 0; i < relatedInfo.length(); ++i) { 30 | if (relatedInfo.visit(i).date == date && 31 | relatedInfo.visit(i).departureStation == stationID) { 32 | TicketInfo updatedInfo = relatedInfo.visit(i); 33 | updatedInfo.seatNum += delta; 34 | ticketInfo.modify(trainID, relatedInfo.visit(i), updatedInfo); 35 | return relatedInfo.visit(i).price; 36 | } 37 | } 38 | return -1; // 出错,未找到符合条件的余票信息 39 | } 40 | 41 | void TicketManager::releaseTicket( 42 | const TrainScheduler &scheduler, const Date &date) { 43 | int passingStationNum = scheduler.getPassingStationNum(); 44 | for (int i = 0; i + 1 < passingStationNum; ++i) { 45 | TicketInfo newTicket; 46 | newTicket.trainID = scheduler.getTrainID(); 47 | newTicket.departureStation = scheduler.getStation(i); 48 | newTicket.arrivalStation = scheduler.getStation(i + 1); 49 | newTicket.seatNum = scheduler.getSeatNum(); 50 | newTicket.price = scheduler.getPrice(i); 51 | newTicket.duration = scheduler.getDuration(i); 52 | newTicket.date = date; 53 | ticketInfo.insert(newTicket.trainID, newTicket); 54 | } 55 | } 56 | 57 | void TicketManager::expireTicket(const TrainID &trainID, const Date &date) { 58 | seqList relatedInfo = ticketInfo.find(trainID); 59 | for (int i = 0; i < relatedInfo.length(); ++i) { 60 | if (relatedInfo.visit(i).date == date) { 61 | ticketInfo.remove(trainID, relatedInfo.visit(i)); 62 | } 63 | } 64 | } 65 | 66 | } // namespace trainsys -------------------------------------------------------------------------------- /code/TicketManager/TicketManager.h: -------------------------------------------------------------------------------- 1 | // 代码清单8-9 TicketManager类的定义 2 | #ifndef TICKET_MANAGER_H_ 3 | #define TICKET_MANAGER_H_ 4 | 5 | #include "TicketInfo.h" 6 | #include "TrainScheduler.h" 7 | #include "Utils.h" 8 | #include "BPlusTree.h" 9 | 10 | namespace trainsys { 11 | 12 | class TicketManager { 13 | public: 14 | // 从 trainID 到 [一组 TicketInfo] 的 B+ 树索引 15 | BPlusTree ticketInfo; 16 | 17 | public: 18 | TicketManager(const std::string &filename); 19 | ~TicketManager(); 20 | // 余票查询 21 | int querySeat( 22 | const TrainID &trainID, const Date &date, const StationID &stationID); 23 | 24 | // 余票更新(购票、退票) 25 | // 给定车次号、乘车日期、始发站、购票或退票,修改余票数量 26 | // delta == 1,购票;delta == -1,退票 27 | // 返回:票价 28 | int updateSeat(const TrainID &trainID, const Date &date, 29 | const StationID &stationID, int delta); 30 | 31 | // 车票发售 32 | void releaseTicket(const TrainScheduler &scheduler, const Date &date); 33 | 34 | // 车票停售 35 | void expireTicket(const TrainID &trainID, const Date &date); 36 | }; 37 | 38 | } // namespace trainsys 39 | 40 | #endif // TICKET_MANAGER_H_ -------------------------------------------------------------------------------- /code/TicketManager/TrainScheduler.h: -------------------------------------------------------------------------------- 1 | // TrainScheduler类的数组实现(非seqList) 2 | #ifndef TRAIN_SCHEDULER_H_ 3 | #define TRAIN_SCHEDULER_H_ 4 | 5 | #include "Utils.h" 6 | #include "List.h" 7 | 8 | namespace trainsys { 9 | 10 | class TrainScheduler { 11 | private: 12 | TrainID trainID; // 车次号 13 | int seatNum; // 额定乘员 14 | int passingStationNum; // 途经站点数量 15 | StationID stations[MAX_PASSING_STATION_NUMBER]; // 途经站点的数组 16 | int duration[MAX_PASSING_STATION_NUMBER]; // 每一段历时的数组 17 | int price[MAX_PASSING_STATION_NUMBER]; // 每一段票价的数组 18 | 19 | public: 20 | TrainScheduler(); 21 | ~TrainScheduler(); 22 | 23 | void addStation(const StationID &station); 24 | void insertStation(int i, const StationID &station); 25 | void removeStation(int i); 26 | int findStation(const StationID &station); 27 | void traverseStation(); 28 | 29 | void setTrainID(const TrainID &id); 30 | void setPrice(const int price[]); 31 | void setDuration(const int duration[]); 32 | void setSeatNumber(int seatNum); 33 | 34 | TrainID getTrainID() const; 35 | int getSeatNum() const; 36 | int getPassingStationNum() const; 37 | 38 | void getStations(StationID *stations) const; 39 | void getDuration(int* duration) const; 40 | void getPrice(int* price) const; 41 | 42 | StationID getStation(int i) const; 43 | int getDuration(int i) const; 44 | int getPrice(int i) const; 45 | 46 | bool operator == (const TrainScheduler &rhs) const; 47 | 48 | bool operator != (const TrainScheduler &rhs) const; 49 | 50 | friend std::ostream &operator << (std::ostream &os, const TrainScheduler &trainScheduler); 51 | 52 | }; 53 | 54 | } 55 | 56 | #endif -------------------------------------------------------------------------------- /code/TicketManager/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | #include "DateTime.h" 6 | #include "List.h" 7 | 8 | namespace trainsys { 9 | 10 | const int MAX_TRAINID_LEN = 20; 11 | const int MAX_USERNAME_LEN = 20; 12 | const int MAX_PASSWORD_LEN = 30; 13 | 14 | const int MAX_PASSING_STATION_NUMBER = 30; 15 | 16 | const int MAX_STATIONID = 1000; 17 | const int MAX_STATIONNAME_LEN = 30; 18 | 19 | const int ADMIN_PRIVILEGE = 10; 20 | 21 | const int BUSY_STATE_TRESHOLD = 1; 22 | 23 | struct String; 24 | 25 | using UserID = long long; 26 | using StationID = int; 27 | using TrainID = String; 28 | using StationName = String; 29 | 30 | const int MAX_STRING_LENGTH = 50; 31 | 32 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 33 | struct String { 34 | char index[MAX_STRING_LENGTH]; 35 | 36 | String() = default; 37 | 38 | explicit String(const char * str) { 39 | strcpy(index, str); 40 | } 41 | 42 | String(const String &other) { 43 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 44 | index[i] = other.index[i]; 45 | } 46 | } 47 | 48 | String &operator=(const String &other) { 49 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 50 | index[i] = other.index[i]; 51 | } 52 | return *this; 53 | } 54 | 55 | friend bool operator>(const String &lhs, const String &rhs) { 56 | return std::string(lhs.index) > std::string(rhs.index); 57 | } 58 | 59 | friend bool operator>=(const String &lhs, const String &rhs) { 60 | return std::string(lhs.index) >= std::string(rhs.index); 61 | } 62 | 63 | friend bool operator<(const String &lhs, const String &rhs) { 64 | return std::string(lhs.index) < std::string(rhs.index); 65 | } 66 | 67 | friend bool operator<=(const String &lhs, const String &rhs) { 68 | return std::string(lhs.index) <= std::string(rhs.index); 69 | } 70 | 71 | friend bool operator==(const String &lhs, const String &rhs) { 72 | return std::string(lhs.index) == std::string(rhs.index); 73 | } 74 | 75 | friend bool operator!=(const String &lhs, const String &rhs) { 76 | return std::string(lhs.index) != std::string(rhs.index); 77 | } 78 | 79 | friend std::ostream &operator<<(std::ostream &os, const String &obj) { 80 | os << obj.index; 81 | return os; 82 | } 83 | }; 84 | 85 | template 86 | int binarySearch(const list &data, const elemType &x) { 87 | int low = 0, high = data.length() - 1, mid; 88 | while (low <= high) { //查找区间存在 89 | mid = (low + high) / 2; //计算中间位置 90 | if (x == data.visit(mid)) return mid; //查找完成 91 | else if (x < data.visit(mid)) high = mid - 1; 92 | else low = mid + 1; 93 | } 94 | return 0; 95 | } 96 | 97 | } 98 | 99 | #endif -------------------------------------------------------------------------------- /code/TrainScheduler/List.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include 5 | using namespace std; 6 | 7 | namespace trainsys { 8 | 9 | template 10 | class list { 11 | public: 12 | virtual void clear() = 0; 13 | virtual int length() const = 0; 14 | virtual void insert(int i, const elemType &x) = 0; 15 | virtual void remove(int i) = 0; 16 | virtual int search(const elemType &x) const = 0; 17 | virtual elemType visit(int i) const = 0; 18 | virtual void traverse() const = 0; 19 | virtual ~list() {}; 20 | }; 21 | 22 | template 23 | class seqList : public list { 24 | private: 25 | elemType *data; 26 | int currentLength; 27 | int maxSize; 28 | void doubleSpace(); 29 | 30 | public: 31 | seqList(int initSize = 10); 32 | ~seqList() { delete[] data; } // 释放动态数组的空间 33 | void clear() { currentLength = 0; } 34 | int length() const { return currentLength; } 35 | void insert(int i, const elemType &x); 36 | void remove(int i); 37 | int search(const elemType &x) const; 38 | elemType visit(int i) const { return data[i]; } 39 | void traverse() const; 40 | }; 41 | 42 | template 43 | seqList::seqList(int initSize) { 44 | data = new elemType[initSize]; 45 | maxSize = initSize; 46 | currentLength = 0; 47 | } 48 | 49 | template 50 | int seqList::search(const elemType &x) const { 51 | int i; 52 | // 使用for循环逐位搜索data[i]是否等于x 53 | for (i = 0; i < currentLength && data[i] != x; ++i); 54 | if (i == currentLength) 55 | return -1; 56 | else 57 | return i; 58 | } 59 | 60 | template 61 | void seqList::traverse() const { 62 | for (int i = 0; i < currentLength; ++i) cout << data[i] << ' '; 63 | cout << endl; 64 | } 65 | 66 | // 在第i个位置插入元素x 67 | template 68 | void seqList::insert(int i, const elemType &x) { 69 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 70 | if (currentLength == maxSize) doubleSpace(); 71 | 72 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 73 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 74 | data[i] = x; 75 | ++currentLength; 76 | } 77 | 78 | // 自动扩容函数doubleSpace() 79 | template 80 | void seqList::doubleSpace() { 81 | elemType *tmp = data; 82 | maxSize *= 2; 83 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 84 | for (int i = 0; i < currentLength; ++i) 85 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 86 | delete[] tmp; // 回收旧空间 87 | } 88 | 89 | // 删除第i个位置的元素 90 | template 91 | void seqList::remove(int i) { 92 | // 将第i+1个元素到最后一个元素全部前移一个位置 93 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 94 | --currentLength; 95 | } 96 | 97 | } // namespace trainsys 98 | 99 | #endif -------------------------------------------------------------------------------- /code/TrainScheduler/TrainScheduler.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单2-15 TrainScheduler 类的实现 2 | 3 | #include "TrainScheduler.h" 4 | 5 | namespace trainsys { 6 | TrainScheduler::TrainScheduler() {} 7 | 8 | TrainScheduler::~TrainScheduler() {} 9 | 10 | void TrainScheduler::addStation(const StationID &station) { 11 | stations.insert(stations.length(), station); 12 | } 13 | 14 | void TrainScheduler::insertStation(int i, const StationID &station) { 15 | stations.insert(i, station); 16 | } 17 | 18 | void TrainScheduler::removeStation(int i) { stations.remove(i); } 19 | 20 | int TrainScheduler::findStation(const StationID &station) { 21 | return stations.search(station); 22 | } 23 | 24 | void TrainScheduler::traverseStation() { 25 | for (int i = 0; i < stations.length(); i++) { 26 | std::cout << stations.visit(i) << " "; 27 | } 28 | std::cout << std::endl; 29 | } 30 | 31 | void TrainScheduler::setTrainID(const TrainID &id) { 32 | this->trainID = id; 33 | } 34 | 35 | void TrainScheduler::setSeatNumber(int seatNum) { 36 | this->seatNum = seatNum; 37 | } 38 | 39 | void TrainScheduler::setPrice(int price[]) { 40 | for (int i = 0; i + 1 < stations.length(); i++) { 41 | this->price.insert(i, price[i]); 42 | } 43 | } 44 | 45 | void TrainScheduler::setDuration(int duration[]) { 46 | for (int i = 0; i + 1 < stations.length(); i++) { 47 | this->duration.insert(i, duration[i]); 48 | } 49 | } 50 | 51 | TrainID TrainScheduler::getTrainID() const { return trainID; } 52 | 53 | int TrainScheduler::getSeatNum() const { return seatNum; } 54 | 55 | void TrainScheduler::getStations(seqList *stations) const { 56 | stations = new seqList(this->stations); 57 | } 58 | 59 | void TrainScheduler::getDuration(seqList *duration) const { 60 | duration = new seqList(this->duration); 61 | } 62 | 63 | void TrainScheduler::getPrice(seqList *price) const { 64 | price = new seqList(this->price); 65 | } 66 | 67 | } // namespace trainsys -------------------------------------------------------------------------------- /code/TrainScheduler/TrainScheduler.h: -------------------------------------------------------------------------------- 1 | // 代码清单2-15 TrainScheduler 类的定义 2 | 3 | #ifndef TRAIN_SCHEDULER_H_ 4 | #define TRAIN_SCHEDULER_H_ 5 | 6 | #include "List.h" 7 | #include "Utils.h" 8 | 9 | namespace trainsys { 10 | 11 | class TrainScheduler { // 列车运行计划管理类 12 | private: 13 | TrainID trainID; // 车次号 14 | int seatNum; // 额定乘员 15 | seqList stations; // 途经站点的线性表 16 | seqList duration; // 每一段历时的线性表 17 | seqList price; // 每一段票价的线性表 18 | 19 | public: 20 | TrainScheduler(); 21 | ~TrainScheduler(); 22 | void addStation(const StationID &station); 23 | void insertStation(int i, const StationID &station); 24 | void removeStation(int i); 25 | int findStation(const StationID &station); 26 | void traverseStation(); 27 | 28 | void setTrainID(const TrainID &id); 29 | void setSeatNumber(int seatNum); 30 | void setPrice(int price[]); 31 | void setDuration(int duration[]); 32 | 33 | TrainID getTrainID() const; 34 | int getSeatNum() const; 35 | 36 | void getStations(seqList *stations) const; 37 | void getDuration(seqList *duration) const; 38 | void getPrice(seqList *price) const; 39 | 40 | StationID getStation(int i) const; 41 | int getDuration(int i) const; 42 | int getPrice(int i) const; 43 | }; 44 | 45 | } // namespace trainsys 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /code/TrainScheduler/TrainSchedulerTest.cpp: -------------------------------------------------------------------------------- 1 | // TrainScheduler 类的测试程序 2 | // 编译命令:g++ TrainScheduler.cpp TrainSchedulerTest.cpp -o code.out 3 | // 样例输出: 4 | // 0 295 470 626 912 1318 5 | // 0 295 626 912 1318 6 | // 0 295 626 912 1196 1318 7 | // 4 8 | // -1 9 | 10 | #include 11 | #include 12 | 13 | #include "TrainScheduler.h" 14 | #include "Utils.h" 15 | 16 | int main() { 17 | trainsys::TrainScheduler scheduler; 18 | trainsys::StationID stationID[6] = {0, 295, 470, 626, 912, 1318}; 19 | for (int i = 0; i < 6; i++) { scheduler.addStation(stationID[i]); } 20 | scheduler.traverseStation(); 21 | 22 | scheduler.removeStation(2); 23 | scheduler.traverseStation(); 24 | 25 | trainsys::StationID newStation = 1196; 26 | scheduler.insertStation(4, newStation); 27 | scheduler.traverseStation(); 28 | 29 | std::cout << scheduler.findStation(1196) << std::endl; 30 | std::cout << scheduler.findStation(1462) << std::endl; 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /code/TrainScheduler/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | 6 | #include "List.h" 7 | 8 | namespace trainsys { 9 | 10 | const int MAX_TRAINID_LEN = 20; 11 | const int MAX_USERNAME_LEN = 20; 12 | const int MAX_PASSWORD_LEN = 30; 13 | 14 | const int MAX_PASSING_STATION_NUMBER = 30; 15 | 16 | const int MAX_STATIONID = 1000; 17 | const int MAX_STATIONNAME_LEN = 30; 18 | 19 | const int ADMIN_PRIVILEGE = 10; 20 | 21 | const int BUSY_STATE_TRESHOLD = 1; 22 | 23 | struct String; 24 | 25 | using UserID = long long; 26 | using StationID = int; 27 | using TrainID = String; 28 | using StationName = String; 29 | 30 | const int MAX_STRING_LENGTH = 50; 31 | 32 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 33 | struct String { 34 | char index[MAX_STRING_LENGTH]; 35 | 36 | String() = default; 37 | 38 | explicit String(const char *str) { strcpy(index, str); } 39 | 40 | String(const String &other) { 41 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 42 | index[i] = other.index[i]; 43 | } 44 | } 45 | 46 | String &operator=(const String &other) { 47 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 48 | index[i] = other.index[i]; 49 | } 50 | return *this; 51 | } 52 | 53 | friend bool operator>(const String &lhs, const String &rhs) { 54 | return std::string(lhs.index) > std::string(rhs.index); 55 | } 56 | 57 | friend bool operator>=(const String &lhs, const String &rhs) { 58 | return std::string(lhs.index) >= std::string(rhs.index); 59 | } 60 | 61 | friend bool operator<(const String &lhs, const String &rhs) { 62 | return std::string(lhs.index) < std::string(rhs.index); 63 | } 64 | 65 | friend bool operator<=(const String &lhs, const String &rhs) { 66 | return std::string(lhs.index) <= std::string(rhs.index); 67 | } 68 | 69 | friend bool operator==(const String &lhs, const String &rhs) { 70 | return std::string(lhs.index) == std::string(rhs.index); 71 | } 72 | 73 | friend bool operator!=(const String &lhs, const String &rhs) { 74 | return std::string(lhs.index) != std::string(rhs.index); 75 | } 76 | 77 | friend std::ostream &operator<<( 78 | std::ostream &os, const String &obj) { 79 | os << obj.index; 80 | return os; 81 | } 82 | }; 83 | 84 | template 85 | int binarySearch(const list &data, const elemType &x) { 86 | int low = 0, high = data.length() - 1, mid; 87 | while (low <= high) { // 查找区间存在 88 | mid = (low + high) / 2; // 计算中间位置 89 | if (x == data.visit(mid)) 90 | return mid; // 查找完成 91 | else if (x < data.visit(mid)) 92 | high = mid - 1; 93 | else 94 | low = mid + 1; 95 | } 96 | return 0; 97 | } 98 | 99 | } // namespace trainsys 100 | 101 | #endif -------------------------------------------------------------------------------- /code/TripManager/List.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_H_ 2 | #define LIST_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | template 9 | class list { 10 | public: 11 | virtual void clear() = 0; 12 | virtual int length() const = 0; 13 | virtual void insert(int i, const elemType &x) = 0; 14 | virtual void remove(int i) = 0; 15 | virtual elemType visit(int i) const = 0; 16 | virtual ~list() {}; 17 | }; 18 | 19 | template 20 | class seqList : public list { 21 | protected: 22 | elemType *data; 23 | int currentLength; 24 | int maxSize; 25 | void doubleSpace(); 26 | 27 | public: 28 | seqList(int initSize = 10); 29 | ~seqList() { delete[] data; } 30 | void clear() { currentLength = 0; } 31 | int length() const { return currentLength; } 32 | bool empty() const { return currentLength == 0; } 33 | void insert(int i, const elemType &x); 34 | void remove(int i); 35 | elemType visit(int i) const { return data[i]; } 36 | 37 | // 新增三个成员函数对顺序表尾部进行操作 38 | void pushBack(const elemType &x) { insert(length(), x); } 39 | void popBack() { remove(length() - 1); } 40 | elemType back() const { return visit(length() - 1); } 41 | }; 42 | 43 | template 44 | seqList::seqList(int initSize) { 45 | data = new elemType[initSize]; 46 | maxSize = initSize; 47 | currentLength = 0; 48 | } 49 | 50 | // 自动扩容函数doubleSpace() 51 | template 52 | void seqList::doubleSpace() { 53 | elemType *tmp = data; 54 | maxSize *= 2; 55 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 56 | for (int i = 0; i < currentLength; ++i) 57 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 58 | delete[] tmp; // 回收旧空间 59 | } 60 | 61 | // 在第i个位置插入元素x 62 | template 63 | void seqList::insert(int i, const elemType &x) { 64 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 65 | if (currentLength == maxSize) doubleSpace(); 66 | 67 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 68 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 69 | data[i] = x; 70 | ++currentLength; 71 | } 72 | 73 | // 删除第i个位置的元素 74 | template 75 | void seqList::remove(int i) { 76 | // 将第i+1个元素到最后一个元素全部前移一个位置 77 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 78 | --currentLength; 79 | } 80 | 81 | } // namespace trainsys 82 | 83 | #endif -------------------------------------------------------------------------------- /code/TripManager/Pair.h: -------------------------------------------------------------------------------- 1 | #ifndef PAIR_H 2 | #define PAIR_H 3 | 4 | namespace trainsys { 5 | 6 | template 7 | struct Pair { 8 | FirstType first; 9 | SecondType second; 10 | 11 | Pair() {} 12 | Pair(const FirstType &first, const SecondType &second) 13 | : first(first), second(second) {} 14 | }; 15 | 16 | template 17 | bool checkPairLess(const Pair &lhs, 18 | const Pair &rhs) { 19 | if (lhs.first != rhs.first) { 20 | return lhs.first < rhs.first; 21 | } else { 22 | return lhs.second < rhs.second; 23 | } 24 | } 25 | 26 | template 27 | bool checkPairEqual(const Pair &lhs, 28 | const Pair &rhs) { 29 | return lhs.first == rhs.first && lhs.second == rhs.second; 30 | } 31 | 32 | } // namespace trainsys 33 | 34 | #endif -------------------------------------------------------------------------------- /code/TripManager/SearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef SEARCH_TABLE_H_ 2 | #define SEARCH_TABLE_H_ 3 | 4 | namespace trainsys { 5 | 6 | template 7 | class StorageSearchTable { 8 | public: 9 | virtual seqList find(const KeyType &key) = 0; 10 | virtual void insert(const KeyType &key, const ValueType &val) = 0; 11 | virtual void remove(const KeyType &key, const ValueType &val) = 0; 12 | virtual ~StorageSearchTable() {}; 13 | }; 14 | 15 | } // namespace trainsys 16 | 17 | #endif -------------------------------------------------------------------------------- /code/TripManager/TripInfo.h: -------------------------------------------------------------------------------- 1 | // 代码清单8-13 行程信息TripInfo 结构体的定义 2 | #ifndef TRIPINFO_H_ 3 | #define TRIPINFO_H_ 4 | 5 | #include "Utils.h" 6 | 7 | namespace trainsys { 8 | 9 | struct TripInfo { 10 | TrainID trainID; 11 | StationID departureStation; 12 | StationID arrivalStation; 13 | int duration; 14 | int price; 15 | Date date; 16 | 17 | TripInfo() = default; 18 | TripInfo(const TrainID &trainID, const StationID &departureStation, 19 | const StationID &arrivalStation, int duration, int price, 20 | const Date &date) { 21 | this->trainID = trainID; 22 | this->departureStation = departureStation; 23 | this->arrivalStation = arrivalStation; 24 | this->duration = duration; 25 | this->price = price; 26 | this->date = date; 27 | } 28 | 29 | bool operator==(const TripInfo &rhs) const { 30 | return trainID == rhs.trainID && departureStation == rhs.departureStation && 31 | arrivalStation == rhs.arrivalStation && duration == rhs.duration && 32 | price == rhs.price && date == rhs.date; 33 | } 34 | 35 | bool operator!=(const TripInfo &rhs) const { return !(*this == rhs); } 36 | 37 | bool operator<(const TripInfo &rhs) const { 38 | if (trainID != rhs.trainID) { 39 | return trainID < rhs.trainID; 40 | } else if (departureStation != rhs.departureStation) { 41 | return departureStation < rhs.departureStation; 42 | } else if (arrivalStation != rhs.arrivalStation) { 43 | return arrivalStation < rhs.arrivalStation; 44 | } else if (date != rhs.date) { 45 | return date < rhs.date; 46 | } else if (price != rhs.price) { 47 | return price < rhs.price; 48 | } else { 49 | return duration < rhs.duration; 50 | } 51 | } 52 | 53 | friend std::ostream &operator<<(std::ostream &os, const TripInfo &tripInfo) { 54 | os << "TripInfo:" << std::endl; 55 | os << "trainID: " << tripInfo.trainID << std::endl; 56 | os << "departureStation: " << tripInfo.departureStation << std::endl; 57 | os << "arrivalStation: " << tripInfo.arrivalStation << std::endl; 58 | os << "duration: " << tripInfo.duration << std::endl; 59 | os << "price: " << tripInfo.price << std::endl; 60 | os << "date: " << tripInfo.date << std::endl; 61 | return os; 62 | } 63 | }; 64 | 65 | } // namespace trainsys 66 | 67 | #endif -------------------------------------------------------------------------------- /code/TripManager/TripManager.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单8-15 TripManager 类的实现 2 | #include "TripManager.h" 3 | #include "List.h" 4 | 5 | namespace trainsys { 6 | 7 | TripManager::TripManager(const std::string &filename) 8 | : tripInfo(filename) {} 9 | 10 | void TripManager::addTrip(const UserID &userID, const TripInfo &trip) { 11 | tripInfo.insert(userID, trip); 12 | } 13 | 14 | seqList TripManager::queryTrip(const UserID &userID) { 15 | return tripInfo.find(userID); 16 | } 17 | 18 | void TripManager::removeTrip(const UserID &userID, const TripInfo &trip) { 19 | tripInfo.remove(userID, trip); 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /code/TripManager/TripManager.h: -------------------------------------------------------------------------------- 1 | // 代码清单8-14 TripManager 类的定义 2 | #ifndef TRIP_MANAGER_H_ 3 | #define TRIP_MANAGER_H_ 4 | 5 | #include "TripInfo.h" 6 | #include "Utils.h" 7 | #include "BPlusTree.h" 8 | 9 | namespace trainsys { 10 | 11 | class TripManager { 12 | private: 13 | BPlusTree tripInfo; 14 | 15 | public: 16 | TripManager(const std::string &filename); 17 | ~TripManager() {} 18 | void addTrip(const UserID &userID, const TripInfo &trip); 19 | // 返回一个用户的多个 TripInfo,输出到 stdout 20 | seqList queryTrip(const UserID &userID); 21 | void removeTrip(const UserID &userID, const TripInfo &trip); 22 | }; 23 | 24 | } // namespace trainsys 25 | 26 | #endif -------------------------------------------------------------------------------- /code/TripManager/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | 6 | #include "DateTime.h" 7 | #include "List.h" 8 | 9 | namespace trainsys { 10 | 11 | const int MAX_TRAINID_LEN = 20; 12 | const int MAX_USERNAME_LEN = 20; 13 | const int MAX_PASSWORD_LEN = 30; 14 | 15 | const int MAX_PASSING_STATION_NUMBER = 30; 16 | 17 | const int MAX_STATIONID = 1000; 18 | const int MAX_STATIONNAME_LEN = 30; 19 | 20 | const int ADMIN_PRIVILEGE = 10; 21 | 22 | const int BUSY_STATE_TRESHOLD = 1; 23 | 24 | struct String; 25 | 26 | using UserID = long long; 27 | using StationID = int; 28 | using TrainID = String; 29 | using StationName = String; 30 | 31 | const int MAX_STRING_LENGTH = 50; 32 | 33 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 34 | struct String { 35 | char index[MAX_STRING_LENGTH]; 36 | 37 | String() = default; 38 | 39 | explicit String(const char *str) { strcpy(index, str); } 40 | 41 | String(const String &other) { 42 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { index[i] = other.index[i]; } 43 | } 44 | 45 | String &operator=(const String &other) { 46 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { index[i] = other.index[i]; } 47 | return *this; 48 | } 49 | 50 | friend bool operator>(const String &lhs, const String &rhs) { 51 | return std::string(lhs.index) > std::string(rhs.index); 52 | } 53 | 54 | friend bool operator>=(const String &lhs, const String &rhs) { 55 | return std::string(lhs.index) >= std::string(rhs.index); 56 | } 57 | 58 | friend bool operator<(const String &lhs, const String &rhs) { 59 | return std::string(lhs.index) < std::string(rhs.index); 60 | } 61 | 62 | friend bool operator<=(const String &lhs, const String &rhs) { 63 | return std::string(lhs.index) <= std::string(rhs.index); 64 | } 65 | 66 | friend bool operator==(const String &lhs, const String &rhs) { 67 | return std::string(lhs.index) == std::string(rhs.index); 68 | } 69 | 70 | friend bool operator!=(const String &lhs, const String &rhs) { 71 | return std::string(lhs.index) != std::string(rhs.index); 72 | } 73 | 74 | friend std::ostream &operator<<(std::ostream &os, const String &obj) { 75 | os << obj.index; 76 | return os; 77 | } 78 | }; 79 | 80 | template 81 | int binarySearch(const list &data, const elemType &x) { 82 | int low = 0, high = data.length() - 1, mid; 83 | while (low <= high) { // 查找区间存在 84 | mid = (low + high) / 2; // 计算中间位置 85 | if (x == data.visit(mid)) 86 | return mid; // 查找完成 87 | else if (x < data.visit(mid)) 88 | high = mid - 1; 89 | else 90 | low = mid + 1; 91 | } 92 | return 0; 93 | } 94 | 95 | } // namespace trainsys 96 | 97 | #endif -------------------------------------------------------------------------------- /code/UserManager/DynamicSearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef SEARCH_TABLE_H_ 2 | #define SEARCH_TABLE_H_ 3 | 4 | namespace trainsys { 5 | 6 | template 7 | struct SET { 8 | KEY key; 9 | OTHER other; 10 | SET(KEY k, OTHER o) { 11 | key = k; 12 | other = o; 13 | } 14 | SET() = default; 15 | }; 16 | 17 | template 18 | class DynamicSearchTable { 19 | public: 20 | virtual SET *find(const KEY &x) const = 0; 21 | virtual void insert(const SET &x) = 0; 22 | virtual void remove(const KEY &x) = 0; 23 | virtual ~DynamicSearchTable() {}; 24 | }; 25 | 26 | } // namespace trainsys 27 | 28 | #endif -------------------------------------------------------------------------------- /code/UserManager/UserManagerTest.cpp: -------------------------------------------------------------------------------- 1 | // UserManager 类的测试程序 2 | // 编译命令:g++ UserManagerTest.cpp -o code.out 3 | // 样例输出: 4 | // Printint info of user with ID = 99: 5 | // UserID: 99 6 | // Username: User99 7 | // Password: Psd99 8 | // Privilege: 99 9 | // Test_UserManager passed. 10 | #include 11 | #include 12 | 13 | #include "UserManager.h" 14 | 15 | int main() { 16 | trainsys::UserManager userManager; 17 | for (int i = 1; i <= 99; i += 2) { 18 | char *username = new char[10]; 19 | char *password = new char[10]; 20 | sprintf(username, "User%d", i); 21 | sprintf(password, "Psd%d", i); 22 | userManager.insertUser(i, username, password, i); 23 | } 24 | for (int i = 100; i >= 2; i -= 2) { 25 | char *username = new char[10]; 26 | char *password = new char[10]; 27 | sprintf(username, "User%d", i); 28 | sprintf(password, "Psd%d", i); 29 | userManager.insertUser(i, username, password, i); 30 | } 31 | for (int i = 1; i <= 100; ++i) { 32 | trainsys::UserInfo *userInfo = userManager.findUser(i); 33 | // 如果assert()的参数为false,则程序会终止 34 | assert(userInfo != nullptr && userInfo->userID == i); 35 | } 36 | for (int i = 2; i <= 100; i += 2) { userManager.removeUser(i); } 37 | for (int i = 1; i <= 100; ++i) { 38 | trainsys::UserInfo *userInfo = userManager.findUser(i); 39 | if (i % 2 == 0) { 40 | assert(userInfo == nullptr); 41 | } else { 42 | assert(userInfo != nullptr && userInfo->userID == i); 43 | } 44 | } 45 | trainsys::UserInfo *userInfo = userManager.findUser(99); 46 | assert(userInfo != nullptr); 47 | std::cout << "Printint info of user with ID = 99:" << std::endl; 48 | assert(userInfo->userID == 99); 49 | std::cout << "UserID: " << userInfo->userID << std::endl; 50 | assert(strcmp(userInfo->username, "User99") == 0); 51 | std::cout << "Username: " << userInfo->username << std::endl; 52 | assert(strcmp(userInfo->password, "Psd99") == 0); 53 | std::cout << "Password: " << userInfo->password << std::endl; 54 | assert(userInfo->privilege == 99); 55 | std::cout << "Privilege: " << userInfo->privilege << std::endl; 56 | std::cout << "Test_UserManager passed." << std::endl; 57 | return 0; 58 | } -------------------------------------------------------------------------------- /code/WaitingList/PurchaseInfo.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-22 PurchaseInfo 交易信息结构体 2 | #ifndef PURCHASEINFO_H_ 3 | #define PURCHASEINFO_H_ 4 | 5 | #include "DateTime.h" 6 | #include "Utils.h" 7 | 8 | namespace trainsys { 9 | 10 | struct PurchaseInfo { 11 | UserID userID; 12 | TrainID trainID; 13 | Date date; 14 | StationID departureStation; 15 | int type; // 1表示购票,-1表示退票 16 | 17 | PurchaseInfo() = default; 18 | PurchaseInfo(const UserID userID, const TrainID &trainID, 19 | const Date &date, const StationID &departureStation, int type) { 20 | this->userID = userID; 21 | this->trainID = trainID; 22 | this->date = date; 23 | this->departureStation = departureStation; 24 | this->type = type; 25 | } 26 | ~PurchaseInfo() = default; 27 | 28 | bool isOrdering() const { return type >= 0; } 29 | bool isRefunding() const { return type < 0; } 30 | 31 | const UserID getUser() const { return userID; } 32 | const Date getDate() const { return date; } 33 | const StationID getDepartureStation() const { 34 | return departureStation; 35 | } 36 | }; 37 | 38 | } // namespace trainsys 39 | 40 | #endif -------------------------------------------------------------------------------- /code/WaitingList/Queue.h: -------------------------------------------------------------------------------- 1 | #ifndef QUEUE_H_ 2 | #define QUEUE_H_ 3 | 4 | namespace trainsys { 5 | 6 | template 7 | class queue { 8 | public: 9 | virtual bool isEmpty() const = 0; // 判队空 10 | virtual void enQueue(const elemType &x) = 0; // 进队 11 | virtual elemType deQueue() = 0; // 出队 12 | virtual elemType getHead() const = 0; // 读队头元素 13 | virtual ~queue() {} // 虚析构函数 14 | }; 15 | 16 | template 17 | class linkQueue : public queue { 18 | private: 19 | struct node { 20 | elemType data; 21 | node *next; 22 | node(const elemType &x, node *N = nullptr) { 23 | data = x; 24 | next = N; 25 | } 26 | node() : next(nullptr) {} 27 | ~node() {} 28 | }; 29 | node *front, *rear; 30 | 31 | public: 32 | linkQueue(); 33 | ~linkQueue(); 34 | bool isEmpty() const; 35 | void enQueue(const elemType &x); 36 | elemType deQueue(); 37 | elemType getHead() const; 38 | }; 39 | 40 | template 41 | linkQueue::linkQueue() { 42 | front = rear = nullptr; 43 | } 44 | 45 | // linkQueue类的析构函数 46 | template 47 | linkQueue::~linkQueue() { 48 | node *tmp; 49 | while (front != nullptr) { 50 | tmp = front; 51 | front = front->next; 52 | delete tmp; 53 | } 54 | } 55 | 56 | // 判断队列是否为空 57 | template 58 | bool linkQueue::isEmpty() const { 59 | return front == nullptr; 60 | } 61 | 62 | // 读队头元素 63 | template 64 | elemType linkQueue::getHead() const { 65 | return front->data; 66 | } 67 | 68 | // 进队 69 | template 70 | void linkQueue::enQueue(const elemType &x) { 71 | if (rear == nullptr) // 入队前为空队列 72 | front = rear = new node(x); 73 | else 74 | rear = rear->next = new node(x); 75 | } 76 | 77 | // 出队 78 | template 79 | elemType linkQueue::deQueue() { 80 | node *tmp = front; 81 | elemType value = front->data; 82 | front = front->next; 83 | if (front == nullptr) rear = nullptr; // 出队后为空队列 84 | delete tmp; 85 | return value; 86 | } 87 | 88 | } // namespace trainsys 89 | 90 | #endif -------------------------------------------------------------------------------- /code/WaitingList/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | #include 6 | 7 | namespace trainsys { 8 | 9 | const int MAX_TRAINID_LEN = 20; 10 | const int MAX_USERNAME_LEN = 20; 11 | const int MAX_PASSWORD_LEN = 30; 12 | 13 | const int MAX_PASSING_STATION_NUMBER = 30; 14 | 15 | const int MAX_STATIONID = 1000; 16 | const int MAX_STATIONNAME_LEN = 30; 17 | 18 | const int ADMIN_PRIVILEGE = 10; 19 | 20 | const int BUSY_STATE_TRESHOLD = 1; 21 | 22 | struct String; 23 | 24 | using UserID = long long; 25 | using StationID = int; 26 | using TrainID = String; 27 | using StationName = String; 28 | 29 | const int MAX_STRING_LENGTH = 50; 30 | 31 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 32 | struct String { 33 | char index[MAX_STRING_LENGTH]; 34 | 35 | String() = default; 36 | 37 | explicit String(const char *str) { strcpy(index, str); } 38 | 39 | String(const String &other) { 40 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 41 | index[i] = other.index[i]; 42 | } 43 | } 44 | 45 | String &operator=(const String &other) { 46 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 47 | index[i] = other.index[i]; 48 | } 49 | return *this; 50 | } 51 | 52 | friend bool operator>(const String &lhs, const String &rhs) { 53 | return std::string(lhs.index) > std::string(rhs.index); 54 | } 55 | 56 | friend bool operator>=(const String &lhs, const String &rhs) { 57 | return std::string(lhs.index) >= std::string(rhs.index); 58 | } 59 | 60 | friend bool operator<(const String &lhs, const String &rhs) { 61 | return std::string(lhs.index) < std::string(rhs.index); 62 | } 63 | 64 | friend bool operator<=(const String &lhs, const String &rhs) { 65 | return std::string(lhs.index) <= std::string(rhs.index); 66 | } 67 | 68 | friend bool operator==(const String &lhs, const String &rhs) { 69 | return std::string(lhs.index) == std::string(rhs.index); 70 | } 71 | 72 | friend bool operator!=(const String &lhs, const String &rhs) { 73 | return std::string(lhs.index) != std::string(rhs.index); 74 | } 75 | 76 | friend std::ostream &operator<<( 77 | std::ostream &os, const String &obj) { 78 | os << obj.index; 79 | return os; 80 | } 81 | }; 82 | 83 | } // namespace trainsys 84 | 85 | #endif -------------------------------------------------------------------------------- /code/WaitingList/WaitingList.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单3-23 WaitingList 类的实现 2 | #include "WaitingList.h" 3 | #include 4 | #include 5 | #include "DateTime.h" 6 | #include "PurchaseInfo.h" 7 | #include "Queue.h" 8 | 9 | namespace trainsys { 10 | 11 | WaitingList::WaitingList() {} 12 | 13 | WaitingList::~WaitingList() {} 14 | 15 | void WaitingList::addToWaitingList(const PurchaseInfo &purchaseInfo) { 16 | purchaseQueue.enQueue(purchaseInfo); 17 | } 18 | 19 | void WaitingList::removeHeadFromWaitingList() { 20 | purchaseQueue.deQueue(); 21 | } 22 | 23 | const PurchaseInfo WaitingList::getFrontPurchaseInfo() const { 24 | return purchaseQueue.getHead(); 25 | } 26 | 27 | bool WaitingList::isEmpty() const { return purchaseQueue.isEmpty(); } 28 | 29 | } // namespace trainsys 30 | -------------------------------------------------------------------------------- /code/WaitingList/WaitingList.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-23 WaitingList 类的定义 2 | #ifndef WAITINGLIST_H 3 | #define WAITINGLIST_H 4 | 5 | #include "DateTime.h" 6 | #include "PurchaseInfo.h" 7 | #include "Queue.h" 8 | #include "Utils.h" 9 | 10 | namespace trainsys { 11 | 12 | class WaitingList { // 排队交易类 13 | private: 14 | linkQueue purchaseQueue; 15 | 16 | public: 17 | WaitingList(); 18 | ~WaitingList(); 19 | // 将订单加入队列 20 | void addToWaitingList(const PurchaseInfo &purchaseInfo); 21 | // 将队头的订单移出队列 22 | void removeHeadFromWaitingList(); 23 | // 获取队列头部的订单 24 | const PurchaseInfo getFrontPurchaseInfo() const; 25 | // 判断队列是否为空 26 | bool isEmpty() const; 27 | }; 28 | 29 | } // namespace trainsys 30 | 31 | #endif // WAITINGLIST_H -------------------------------------------------------------------------------- /code/WaitingList/WaitingListTest.cpp: -------------------------------------------------------------------------------- 1 | // WaitingList 类的测试程序 2 | // 编译命令:g++ WaitingList.cpp WaitingListTest.cpp DateTime.cpp -o code.out 3 | // 样例输出: 4 | // User: 1 5 | // Date: 01-01 6 | // DepartureStation: 295 7 | // Type: Ordering 8 | 9 | // User: 2 10 | // Date: 02-02 11 | // DepartureStation: 470 12 | // Type: Ordering 13 | 14 | // User: 3 15 | // Date: 03-03 16 | // DepartureStation: 626 17 | // Type: Ordering 18 | 19 | // User: 4 20 | // Date: 04-04 21 | // DepartureStation: 1318 22 | // Type: Ordering 23 | 24 | // User: 4 25 | // Date: 04-04 26 | // DepartureStation: 1318 27 | // Type: Refunding 28 | 29 | #include "WaitingList.h" 30 | int main() { 31 | trainsys::WaitingList wl; 32 | wl.addToWaitingList(trainsys::PurchaseInfo( 33 | 1, trainsys::TrainID("1462"), trainsys::Date(1, 1), 295, 1)); 34 | wl.addToWaitingList(trainsys::PurchaseInfo( 35 | 2, trainsys::TrainID("G8"), trainsys::Date(2, 2), 470, 1)); 36 | wl.addToWaitingList(trainsys::PurchaseInfo( 37 | 3, trainsys::TrainID("T110"), trainsys::Date(3, 3), 626, 1)); 38 | wl.addToWaitingList(trainsys::PurchaseInfo( 39 | 4, trainsys::TrainID("G18"), trainsys::Date(4, 4), 1318, 1)); 40 | wl.addToWaitingList(trainsys::PurchaseInfo( 41 | 4, trainsys::TrainID("G18"), trainsys::Date(4, 4), 1318, -1)); 42 | while (!wl.isEmpty()) { 43 | std::cout << "User: " << wl.getFrontPurchaseInfo().getUser() << std::endl; 44 | std::cout << "Date: " << wl.getFrontPurchaseInfo().getDate() << std::endl; 45 | std::cout << "DepartureStation: " 46 | << wl.getFrontPurchaseInfo().getDepartureStation() << std::endl; 47 | std::cout << "Type: " 48 | << (wl.getFrontPurchaseInfo().isOrdering() ? "Ordering" : "Refunding") 49 | << std::endl << std::endl; 50 | wl.removeHeadFromWaitingList(); 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /init_database.sh: -------------------------------------------------------------------------------- 1 | rm *leafFile 2 | rm *treeNodeFile -------------------------------------------------------------------------------- /input.in: -------------------------------------------------------------------------------- 1 | login -i 0 -p admin 2 | logout 3 | login -i 0 -p qwq 4 | login -i 0 -p admin 5 | register -u user -p 123456 -i 1 6 | logout 7 | login -i 1 -p 123456 8 | query_profile -i 0 9 | modify_password -i 0 -p 147258 10 | logout 11 | login -i 0 -p admin 12 | query_profile -i 1 13 | modify_password -i 1 -p 987654 14 | modify_privilege -i 1 -g 2 15 | query_profile -i 1 16 | add_train -i SJTUTRAIN -n 3 -m 1000 -s SiyuanGate|ZhiyuanCollege|HanzeLake -p 100|200 -x 19:19 -t 20|20 17 | display_route -s SiyuanGate -t ZhiyuanCollege 18 | query_train -i FDUTRAIN 19 | query_train -i SJTUTRAIN 20 | buy_ticket -i SJTUTRAIN -d 06-05 -f SiyuanGate 21 | release_ticket -i SJTUTRAIN -d 06-05 22 | buy_ticket -i SJTUTRAIN -d 06-05 -f ZhiyuanCollege 23 | expire_ticket -i SJTUTRAIN -d 06-05 24 | buy_ticket -i SJTUTRAIN -d 06-05 -f SiyuanGate 25 | query_order 26 | refund_ticket -i SJTUTRAIN -d 06-05 -f SiyuanGate 27 | query_order 28 | exit -------------------------------------------------------------------------------- /station.txt: -------------------------------------------------------------------------------- 1 | SiyuanGate 1 2 | ZhiyuanCollege 2 3 | HanzeLake 3 -------------------------------------------------------------------------------- /textcode/chapter1/max1max2Test.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单1-1 函数max1与max2的实现及其测试程序 2 | // 输入序列长度n,乘数d,以及序列中的数字a[i],输出序列中的最大值和d的乘积 3 | // 样例输入: 4 | // 5 2 5 | // 2 3 -1 2 -3 6 | // 样例输出: 7 | // max1: 6 8 | // max2: 6 9 | #include 10 | using namespace std; 11 | int max1(int array[], int size, int d) { 12 | int max = 0, i; 13 | for (i = 0; i < size; ++i) array[i] *= d; 14 | for (i = 0; i < size; ++i) 15 | if (array[i] > max) max = array[i]; 16 | return max; 17 | } 18 | 19 | int max2(int array[], int size, int d) { 20 | int max = 0, i; 21 | for (i = 0; i < size; ++i) 22 | if (array[i] > max) max = array[i]; 23 | return max * d; 24 | } 25 | 26 | int main(){ 27 | int n, d; 28 | cin >> n >> d; 29 | int *a = new int[n]; 30 | int *b = new int[n]; 31 | for (int i = 0; i < n; i++){ 32 | cin >> a[i]; 33 | b[i] = a[i]; 34 | } 35 | int start, end; 36 | cout << "max1:" << max1(a, n, d) << endl; 37 | cout << "max2:" << max2(b, n, d) << endl; 38 | } 39 | -------------------------------------------------------------------------------- /textcode/chapter1/maxSubsequenceSum1.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单1-2 最大连续子序列和的枚举算法及其测试程序 2 | // 输入序列长度n,以及序列中的数字a[i],输出最大连续子序列的和以及子序列的终点和起点 3 | // 样例输入: 4 | // 5 5 | // 2 3 -1 2 -3 6 | // 样例输出: 7 | // 最大连续子序列和为:6 8 | // 子序列的起点:0,子序列的终点:3 9 | #include 10 | using namespace std; 11 | 12 | int maxSubsequenceSum(int a[], int size, int &start, int &end) { 13 | int maxSum = 0; // 当前的最大连续子序列之和 14 | 15 | for (int i = 0; i < size; i++) // 子序列的起始位置 16 | for (int j = i; j < size; j++) { // 子序列的终止位置 17 | int thisSum = 0; 18 | for (int k = i; k <= j; k++) // 求从i开始到j结束的序列之和 19 | thisSum += a[k]; 20 | if (thisSum > maxSum) { // 找到一个更好的序列 21 | maxSum = thisSum; 22 | start = i; 23 | end = j; 24 | } 25 | } 26 | 27 | return maxSum; 28 | } 29 | 30 | int main(){ 31 | int n; 32 | cin >> n; 33 | int *a = new int[n]; 34 | for (int i = 0; i < n; i++){ 35 | cin >> a[i]; 36 | } 37 | int start, end; 38 | cout << "最大连续子序列和为:" << maxSubsequenceSum(a, n, start, end) << endl; 39 | cout << "子序列的起点:" << start << ",子序列的终点" << end << endl; 40 | } -------------------------------------------------------------------------------- /textcode/chapter1/maxSubsequenceSum2.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单1-3 最大连续子序列和的O(n^2)两重循环算法及其测试程序 2 | // 输入序列长度n,以及序列中的数字a[i],输出最大连续子序列的和以及子序列的终点和起点 3 | // 样例输入: 4 | // 5 5 | // 2 3 -1 2 -3 6 | // 样例输出: 7 | // 最大连续子序列和为:6 8 | // 子序列的起点:0,子序列的终点:3 9 | #include 10 | using namespace std; 11 | 12 | int maxSubsequenceSum(int a[], int size, int &start, int &end) { 13 | int maxSum = 0; // 已知的最大连续子序列之和 14 | 15 | for (int i = 0; i < size; i++) { // 连续子序列的起始位置 16 | int thisSum = 0; // 从i开始的连续子序列之和 17 | for (int j = i; j < size; j++) { // 连续子序列的终止位置 18 | thisSum += a[j]; // 计算从第i到第j个元素的连续子序列之和 19 | if (thisSum > maxSum) { 20 | maxSum = thisSum; 21 | start = i; 22 | end = j; 23 | } 24 | } 25 | } 26 | return maxSum; 27 | } 28 | 29 | int main(){ 30 | int n; 31 | cin >> n; 32 | int *a = new int[n]; 33 | for (int i = 0; i < n; i++){ 34 | cin >> a[i]; 35 | } 36 | int start, end; 37 | cout << "最大连续子序列和为:" << maxSubsequenceSum(a, n, start, end) << endl; 38 | cout << "子序列的起点:" << start << ",子序列的终点" << end << endl; 39 | } -------------------------------------------------------------------------------- /textcode/chapter1/maxSubsequenceSum3.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单1-4 最大连续子序列和的O(nlogn)递归算法及其测试程序 2 | // 输入序列长度n,以及序列中的数字a[i],输出最大连续子序列的和以及子序列的终点和起点 3 | // 样例输入: 4 | // 5 5 | // 2 3 -1 2 -3 6 | // 样例输出: 7 | // 最大连续子序列和为:6 8 | // 子序列的起点:0,子序列的终点:3 9 | #include 10 | using namespace std; 11 | 12 | // 递归解决方案 13 | int maxSum(int a[], int left, int right, int &start, int &end) { 14 | int maxLeft, maxRight, center; 15 | // maxLeft和maxRight分别为前半部分、后半部分的最大连续子序列和 16 | int leftSum = 0, rightSum = 0; // 情况3中,左、右半段的连续子序列和 17 | int maxLeftTmp = 0, 18 | maxRightTmp = 0; // 情况3中,情况3中,左、右半段的最大连续子序列和 19 | int startL, startR, endL, 20 | endR; // 前半部分、后半部分的最大连续子序列的起点和终点 21 | 22 | if (left == right) { // 仅有一个元素,递归终止 23 | start = end = left; 24 | return a[left] > 0 ? a[left] : 0; 25 | } 26 | 27 | center = (left + right) / 2; 28 | // 找前半部分的最大连续子序列和 29 | maxLeft = maxSum(a, left, center, startL, endL); 30 | // 找后半部分的最大连续子序列和 31 | maxRight = maxSum(a, center + 1, right, startR, endR); 32 | 33 | // 找从前半部分开始但在后半部分结束的最大连续子序列 34 | start = center; 35 | for (int i = center; i >= left; --i) { 36 | leftSum += a[i]; 37 | if (leftSum > maxLeftTmp) { 38 | maxLeftTmp = leftSum; 39 | start = i; 40 | } 41 | } 42 | end = center + 1; 43 | for (int i = center + 1; i <= right; ++i) { 44 | rightSum += a[i]; 45 | if (rightSum > maxRightTmp) { 46 | maxRightTmp = rightSum; 47 | end = i; 48 | } 49 | } 50 | // 找3种情况中的最大连续子序列和 51 | if (maxLeft > maxRight) 52 | if (maxLeft > maxLeftTmp + maxRightTmp) { 53 | start = startL; 54 | end = endL; 55 | return maxLeft; 56 | } else 57 | return maxLeftTmp + maxRightTmp; 58 | else if (maxRight > maxLeftTmp + maxRightTmp) { 59 | start = startR; 60 | end = endR; 61 | return maxRight; 62 | } else 63 | return maxLeftTmp + maxRightTmp; 64 | } 65 | 66 | // 包裹函数 67 | int maxSubsequenceSum(int a[], int size, int &start, int &end) { 68 | return maxSum(a, 0, size - 1, start, end); 69 | } 70 | 71 | int main(){ 72 | int n; 73 | cin >> n; 74 | int *a = new int[n]; 75 | for (int i = 0; i < n; i++){ 76 | cin >> a[i]; 77 | } 78 | int start, end; 79 | cout << "最大连续子序列和为:" << maxSubsequenceSum(a, n, start, end) << endl; 80 | cout << "子序列的起点:" << start << ",子序列的终点" << end << endl; 81 | } 82 | -------------------------------------------------------------------------------- /textcode/chapter1/maxSubsequenceSum4.cpp: -------------------------------------------------------------------------------- 1 | //代码清单1-5 最大连续子序列和的线性算法及其测试程序 2 | // 输入序列长度n,以及序列中的数字a[i],输出最大连续子序列的和以及子序列的终点和起点 3 | // 样例输入: 4 | // 5 5 | // 2 3 -1 2 -3 6 | // 样例输出: 7 | // 最大连续子序列和为:6 8 | // 子序列的起点:0,子序列的终点:3 9 | 10 | #include 11 | using namespace std; 12 | int maxSubsequenceSum(int a[], int size, int &start, int &end) { 13 | int maxSum, starttmp, thisSum; 14 | start = end = maxSum = starttmp = thisSum = 0; 15 | for (int j = 0; j < size; ++j) { 16 | thisSum += a[j]; 17 | if (thisSum <= 0) { // 排除前面的连续子序列 18 | thisSum = 0; 19 | starttmp = j + 1; 20 | } else if (thisSum > maxSum) { // 找到一个连续子序列和更大的连续子序列 21 | maxSum = thisSum; 22 | start = starttmp; 23 | end = j; 24 | } 25 | } 26 | return maxSum; 27 | } 28 | 29 | int main(){ 30 | int n; 31 | cin >> n; 32 | int *a = new int[n]; 33 | for (int i = 0; i < n; i++){ 34 | cin >> a[i]; 35 | } 36 | int start, end; 37 | cout << "最大连续子序列和为:" << maxSubsequenceSum(a, n, start, end) << endl; 38 | cout << "子序列的起点:" << start << ",子序列的终点" << end << endl; 39 | } -------------------------------------------------------------------------------- /textcode/chapter10/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter10) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter10 7 | floydTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter10/dijkstraTest.cpp: -------------------------------------------------------------------------------- 1 | // 加权图单源最短路径(Dijkstra算法)测试程序 2 | // 样例输入(以图10-5(a)为例,顶点下标为0-base): 3 | // 请输入图的顶点个数:5 4 | // 请依次输入非加权无向图的边(-1 -1 -1表示输入完毕): 5 | // 0 1 4 6 | // 0 2 1 7 | // 0 3 1 8 | // 1 2 2 9 | // 2 1 1 10 | // 2 3 2 11 | // 2 4 1 12 | // 3 4 1 13 | // 4 1 1 14 | // -1 -1 -1 15 | // 样例输出: 16 | // Dijkstra最短路径: 17 | // 从0到0的路径为: 18 | // 0 长度为:0 19 | // 从0到1的路径为: 20 | // 0 - 2 - 1 长度为:2 21 | // 从0到2的路径为: 22 | // 0 - 2 长度为:1 23 | // 从0到3的路径为: 24 | // 0 - 3 长度为:1 25 | // 从0到4的路径为: 26 | // 0 - 2 - 4 长度为:2 27 | 28 | #include 29 | 30 | #include "adjListGraph.h" 31 | using namespace std; 32 | int main() { 33 | cout << "请输入图的顶点个数:"; 34 | int verSize; 35 | cin >> verSize; 36 | int *d = new int[verSize]; 37 | for (int i = 0; i < verSize; i++) d[i] = i; 38 | adjListGraph *adj_list_graph = 39 | new adjListGraph(verSize, d); 40 | cout << "请依次输入有向图的边(-1 -1表示输入完毕):"; 41 | while (true) { 42 | int u, v; 43 | double w; 44 | cin >> u >> v >> w; 45 | if (u == -1) { 46 | break; 47 | } else { 48 | adj_list_graph->insert(u, v, w); 49 | } 50 | } 51 | cout << "Dijkstra最短路径:" << endl; 52 | adj_list_graph->dijkstra(0, 1e9); 53 | return 0; 54 | } -------------------------------------------------------------------------------- /textcode/chapter10/floydTest.cpp: -------------------------------------------------------------------------------- 1 | // 所有顶点对的最短路径(Floyd算法)测试程序 2 | // 样例输入(以图10-8(a)为例): 3 | // 请输入图的顶点个数:3 4 | // 请依次输入非加权无向图的边(-1 -1 -1表示输入完毕): 5 | // 0 1 8 6 | // 1 0 3 7 | // 0 2 5 8 | // 2 0 6 9 | // 2 1 2 10 | // -1 -1 -1 11 | // 样例输出: 12 | // 最短路径长度: 13 | // 0 7 5 14 | // 3 0 8 15 | // 5 2 0 16 | // 最短路径: 17 | // 0 2 0 18 | // 1 1 0 19 | // 1 2 2 20 | 21 | #include 22 | 23 | #include "adjMatrixGraph.h" 24 | using namespace std; 25 | int main() { 26 | cout << "请输入图的顶点个数:"; 27 | int verSize; 28 | cin >> verSize; 29 | int *d = new int[verSize]; 30 | for (int i = 0; i < verSize; i++) d[i] = i; 31 | adjMatrixGraph *adj_matrix_graph = 32 | new adjMatrixGraph(verSize, d, 1e9); 33 | cout << "请依次输入有向图的边(-1 -1表示输入完毕):"; 34 | while (true) { 35 | int u, v; 36 | double w; 37 | cin >> u >> v >> w; 38 | if (u == -1) { 39 | break; 40 | } else { 41 | adj_matrix_graph->insert(u, v, w); 42 | } 43 | } 44 | adj_matrix_graph->floyd(); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /textcode/chapter10/kruskalPrimTest.cpp: -------------------------------------------------------------------------------- 1 | // 最小生成树:kruskal算法及prim算法的测试程序 2 | // 样例输入(以图10-1为例,顶点下标改为0-base): 3 | // 请输入图的顶点个数:6 4 | // 请依次输入无向图的加权边(-1 -1 -1表示输入完毕): 5 | // 0 1 6 6 | // 0 2 1 7 | // 0 3 5 8 | // 1 2 5 9 | // 1 4 3 10 | // 2 4 6 11 | // 2 5 4 12 | // 3 5 2 13 | // 4 5 6 14 | // -1 -1 -1 15 | // 样例输出: 16 | // Kruskal:(0,2) (3,5) (1,4) (2,5) (1,2) 17 | // Prim:(0,2) (2,5) (5,3) (2,1) (1,4) 18 | 19 | #include 20 | 21 | #include "adjListGraph.h" 22 | using namespace std; 23 | int main() { 24 | cout << "请输入图的顶点个数:"; 25 | int verSize; 26 | cin >> verSize; 27 | int *d = new int[verSize]; 28 | for (int i = 0; i < verSize; i++) d[i] = i; 29 | adjListGraph *adj_list_graph = 30 | new adjListGraph(verSize, d); 31 | cout << "请依次输入无向图的边(-1 -1表示输入完毕):"; 32 | while (true) { 33 | int u, v; 34 | double w; 35 | cin >> u >> v >> w; 36 | if (u == -1) { 37 | break; 38 | } else { 39 | adj_list_graph->insert(u, v, w); 40 | adj_list_graph->insert(v, u, w); 41 | } 42 | } 43 | cout << "Kruskal:"; 44 | adj_list_graph->kruskal(); 45 | cout << endl; 46 | cout << "Prim:"; 47 | adj_list_graph->prim(1e9); 48 | cout << endl; 49 | return 0; 50 | } -------------------------------------------------------------------------------- /textcode/chapter10/unweightedShortDistanceTest.cpp: -------------------------------------------------------------------------------- 1 | // 非加权图的单源最短路径测试程序 2 | // 样例输入(以图10-4为例,顶点下标改为0-base): 3 | // 请输入图的顶点个数:4 4 | // 请依次输入非加权无向图的边(-1 -1表示输入完毕): 5 | // 0 1 6 | // 1 0 7 | // 0 3 8 | // 1 2 9 | // 3 2 10 | // -1 -1 11 | // 样例输出: 12 | // 非加权图的单源最短路径:从1到0的路径为: 13 | // 1 - 0 14 | // 从1到1的路径为: 15 | // 1 16 | // 从1到2的路径为: 17 | // 1 - 2 18 | // 从1到3的路径为: 19 | // 1 - 0 - 3 20 | 21 | #include 22 | 23 | #include "adjListGraph.h" 24 | using namespace std; 25 | int main() { 26 | cout << "请输入图的顶点个数:"; 27 | int verSize; 28 | cin >> verSize; 29 | int *d = new int[verSize]; 30 | for (int i = 0; i < verSize; i++) d[i] = i; 31 | adjListGraph *adj_list_graph = 32 | new adjListGraph(verSize, d); 33 | cout << "请依次输入有向图的边(-1 -1表示输入完毕):"; 34 | while (true) { 35 | int u, v; 36 | double w; 37 | cin >> u >> v; 38 | if (u == -1) { 39 | break; 40 | } else { 41 | adj_list_graph->insert(u, v, 1); 42 | } 43 | } 44 | cout << "非加权图的单源最短路径:" << endl; 45 | adj_list_graph->unweightedShortDistance(1, 1e9); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /textcode/chapter11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter11) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter11 7 | knapsack.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter11/climbStairs.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单11-4 爬楼梯问题 2 | // 输入楼梯数n,输出爬楼梯的方案数 3 | // 样例输入: 4 | // 5 5 | // 样例输出: 6 | // 5 stairs: 8 7 | #include 8 | using namespace std; 9 | int climbStairs(int n) { 10 | int *dp = new int[n + 1]; 11 | dp[0] = 1; 12 | dp[1] = 1; 13 | for (int i = 2; i <= n; ++i) 14 | dp[i] = dp[i - 1] + dp[i - 2]; 15 | return dp[n]; 16 | } 17 | 18 | int main() { 19 | int n; 20 | cin >> n; 21 | int ways = climbStairs(n); 22 | cout << n << " stairs: " << ways << endl; 23 | return 0; 24 | } -------------------------------------------------------------------------------- /textcode/chapter11/isPrime.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单11-1 判断数字是否为质数的测试程序 2 | // 输入数字,返回是否为素数的结果 3 | // 样例输入: 4 | // 11 5 | // 样例输出: 6 | // 该数字是素数 7 | #include 8 | #include 9 | using namespace std; 10 | bool isPrime(int n) { 11 | if (n == 1 || n == 2) return true; 12 | int sq = int(sqrt(n)); 13 | for (int factor = 2; factor < sq; factor++) { 14 | if (n % factor == 0) return false; 15 | } 16 | return true; 17 | } 18 | 19 | int main() { 20 | cout << "请输入待判断的数字:"; 21 | int n; 22 | cin >> n; 23 | cout << "该数字" << (isPrime(n) ? "是" : "不是") << "素数" << endl; 24 | } 25 | -------------------------------------------------------------------------------- /textcode/chapter11/knapsack.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单11-5 01背包问题 2 | // 样例输入: 3 | // 4 5 4 | // 1 4 5 | // 2 5 6 | // 3 5 7 | // 1 1 8 | // 样例输出: 9 | // 10 10 | #include 11 | using namespace std; 12 | int dp[10000][10000] = {0}; 13 | int weights[10000] = {0}; 14 | int values[10000] = {0}; 15 | 16 | int knapsack(int W, int n) { 17 | for (int i = 1; i <= n; i++) { 18 | for (int j = 1; j <= W; j++) { 19 | if (weights[i - 1] <= j) { 20 | dp[i][j] = 21 | max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1]); 22 | } else { 23 | dp[i][j] = dp[i - 1][j]; 24 | } 25 | } 26 | } 27 | 28 | return dp[n][W]; 29 | } 30 | 31 | int main() { 32 | int n, W; 33 | cin >> n >> W; 34 | for (int i = 0; i < n; i++) 35 | cin >> weights[i] >> values[i]; 36 | int max_value = knapsack(W, n); 37 | cout << max_value << endl; 38 | return 0; 39 | } -------------------------------------------------------------------------------- /textcode/chapter11/nearestPointPair2D.cpp: -------------------------------------------------------------------------------- 1 | //代码清单11-2 二维平面的最近点对算法的实现 2 | // 样例输入: 3 | // 4 4 | // 1 1 5 | // 2 3 6 | // 4 5 7 | // 5 4 8 | // 样例输出:(即点对(4,5)和(5,4)的距离) 9 | // 1.41421 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | #define Inf 1 << 31 - 1 15 | #define MAXN 1000000 16 | struct node { 17 | double x; 18 | double y; 19 | }; 20 | 21 | struct node point[MAXN]; 22 | int mpt[MAXN]; 23 | 24 | double dis(node a, node b) { // 求欧几里得距离 25 | return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); 26 | } 27 | 28 | bool cmp1(node a, node b) { // 按照x坐标排序 29 | if (a.x == b.x) return a.y < b.y; 30 | return a.x < b.x; 31 | } 32 | 33 | bool cmp2(int a, int b) { // 第二个排序是选择中间的点 34 | return point[a].y < point[b].y; 35 | } 36 | 37 | double minDist(int left, int right) { 38 | // 递归求从point[left]到point[right]的点的最短距离 39 | double d = Inf; 40 | if (left == right) 41 | return d; // 自己和自己不可以被选择,因此距离设成正无穷 42 | // 这两个点中间没有任何点,所以直接求距离 43 | if (left + 1 == right) return dis(point[left], point[right]); 44 | // 如果中间还有其他点,那就在中间分开 45 | int mid = (left + right) >> 1; 46 | double d1 = minDist(mid, right); // 情况1: 找左边的最小距离 47 | double d2 = minDist(left, mid - 1); // 情况2: 找右边的最小距离 48 | d = min(d1, d2); // 求出两个最小距离中的最小值 49 | int k = 0; 50 | for (int i = left; i <= right; i++) { 51 | if (fabs(point[mid].x - point[i].x) <= d) { mpt[++k] = i; } 52 | } 53 | sort(mpt + 1, mpt + k + 1, cmp2); // 按这些点的y轴坐标排序 54 | for (int i = 1; i <= k; i++) { 55 | for (int j = i + 1; 56 | j <= k && point[mpt[j]].y - point[mpt[i]].y <= d; j++) { 57 | if (d >= dis(point[mpt[i]], point[mpt[j]])) 58 | d = dis(point[mpt[i]], point[mpt[j]]); 59 | } 60 | } // 线性扫描,找这些点的最小距离 61 | return d; 62 | } 63 | 64 | int main() { 65 | int n; 66 | cin >> n; 67 | for (int i = 1; i <= n; i++) { 68 | cin >> point[i].x >> point[i].y; // 读入所有的点 69 | } 70 | sort(point + 1, point + n + 1, cmp1); // 根据点坐标的x轴排序 71 | cout << minDist(1, n) << endl; 72 | return 0; 73 | } -------------------------------------------------------------------------------- /textcode/chapter11/queenAll.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单11-3 求解八皇后问题的程序 2 | // 寻找棋盘八皇后问题 3 | // 样例输出: 4 | // 1: 1 2: 5 3: 8 4: 6 5: 3 6: 7 7: 2 8: 4 5 | #include 6 | using namespace std; 7 | void queen_all(int k); 8 | int col[9]; 9 | 10 | bool row[9], digLeft[16], digRight[16]; 11 | // 在8*8的棋盘的第k列上找合理的配置 12 | 13 | void queen_all(int k) { 14 | int i, j; 15 | char awn; // 保存是否需要继续寻找的标志 16 | for (i = 1; i < 9; i++) // 依次在l~8行上配置k列的皇后 17 | if (row[i] && digLeft[k + i - 1] && digRight[8 + k - i]) { 18 | // 可行位置 19 | col[k] = i; 20 | // 对应位置有皇后 21 | row[i] = digLeft[k + i - 1] = digRight[8 + k - i] = false; 22 | 23 | if (k == 8) { // 找到一个可行解 24 | for (j = 1; j <= 8; j++) cout << j << ": " << col[j] << '\t'; 25 | cout << endl << "是否需要继续寻找(按Q退出,按其他键继续:)"; 26 | cin >> awn; 27 | if (awn == 'Q' || awn == 'q') exit(0); 28 | } else 29 | queen_all(k + 1); // 递归至第k+1列 30 | // 恢复对应位置无皇后的状态 31 | row[i] = digLeft[k + i - 1] = digRight[8 + k - i] = true; 32 | } 33 | } 34 | 35 | int main() { 36 | int j; 37 | for (j = 0; j <= 8; j++) row[j] = true; 38 | for (j = 0; j < 16; j++) digLeft[j] = digRight[j] = true; 39 | queen_all(1); 40 | return 0; 41 | } -------------------------------------------------------------------------------- /textcode/chapter2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter2) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | include_directories(.) 7 | 8 | add_executable(chapter2 9 | seqListTest.cpp 10 | ) 11 | -------------------------------------------------------------------------------- /textcode/chapter2/LongLongIntTest.cpp: -------------------------------------------------------------------------------- 1 | // LongLongInt类的测试程序 2 | // 输入两个大整数(位数不超过100),输出其对应的a+b和a-b 3 | // 样例输入:124 421 4 | // 样例输出: a plus b is +545 5 | // a minus b is -297 6 | #include "LongLongInt.h" 7 | int main() { 8 | char a[100], b[100]; 9 | cin >> a >> b; 10 | LongLongInt inta(a), intb(b); 11 | LongLongInt intc(inta); 12 | cout << "a plus b is " << inta + intb << endl; 13 | cout << "a minus b is " << intc - intb << endl; 14 | } -------------------------------------------------------------------------------- /textcode/chapter2/list.h: -------------------------------------------------------------------------------- 1 | // 代码清单2-1 线性表抽象类的定义 2 | #ifndef CHAPTER2_LIST_H 3 | #define CHAPTER2_LIST_H 4 | template 5 | class list { 6 | public: 7 | virtual void clear() = 0; // 清空线性表 8 | virtual int length() const = 0; // 获取线性表的长度,即元素个数 9 | // 在第i个位置插入一个元素x 10 | virtual void insert(int i, const elemType &x) = 0; 11 | virtual void remove(int i) = 0; // 删除第i个元素 12 | // 搜索元素x是否在线性表中出现 13 | virtual int search(const elemType &x) const = 0; 14 | virtual elemType visit(int i) const = 0; // 访问线性表第i个元素 15 | virtual void traverse() const = 0; // 遍历线性表 16 | virtual ~list() {}; 17 | }; 18 | 19 | #endif // CHAPTER2_LIST_H 20 | -------------------------------------------------------------------------------- /textcode/chapter2/multinomial.h: -------------------------------------------------------------------------------- 1 | // 代码清单2-14 多项式单链表的结点类Node的定义和功能函数add()的实现 2 | #ifndef CHAPTER2_MULTINOMIAL_H 3 | #define CHAPTER2_MULTINOMIAL_H 4 | #include 5 | using namespace std; 6 | 7 | class Node { // 多项式单链表的结点类定义 8 | public: 9 | int coff, exp; // coff保存系数,exp保存指数 10 | Node *next; 11 | Node() { next = nullptr; } 12 | Node(int n1, int n2, Node *p = nullptr) : coff(n1), exp(n2), next(p) {} 13 | }; 14 | Node *add(Node *exp1, Node *exp2) { 15 | Node *res, *p, *tmp; 16 | // res是保存加的结果值的单链表,p指向res的表尾结点 17 | res = p = new Node(); // 为存储结果值的单链表申请头结点 18 | exp1 = exp1->next; 19 | exp2 = exp2->next; 20 | while (exp1 != nullptr && exp2 != nullptr) { // 归并两个单链表 21 | if (exp1->exp < exp2->exp) { // 直接复制表达式1的项 22 | p = p->next = new Node(exp1->coff, exp1->exp); 23 | exp1 = exp1->next; 24 | } else if (exp1->exp > exp2->exp) { // 直接复制表达式2的项 25 | p = p->next = new Node(exp2->coff, exp2->exp); 26 | exp2 = exp2->next; 27 | } else if (exp1->coff + exp2->coff != 0) { 28 | // 归并两个表达式的同次项 29 | p = p->next = new Node(exp1->coff + exp2->coff, exp2->exp); 30 | exp1 = exp1->next; 31 | exp2 = exp2->next; 32 | } 33 | } 34 | // 将遍历尚未结束的表达式并入结果表达式 35 | if (exp1 == nullptr) 36 | tmp = exp2; 37 | else 38 | tmp = exp1; 39 | while (tmp != nullptr) { 40 | p->next = new Node(tmp->coff, tmp->exp); 41 | tmp = tmp->next; 42 | p = p->next; 43 | } 44 | return res; 45 | } 46 | #endif // CHAPTER2_MULTINOMIAL_H 47 | -------------------------------------------------------------------------------- /textcode/chapter2/multinomialTest.cpp: -------------------------------------------------------------------------------- 1 | // multinomial类的测试程序 2 | // 按样例格式输入两个多项式表达式(expression1)(expression2),输出两个多项式的和 3 | // 输入样例: 4 | // 1 0 (第一个数字是多项式的系数,第二个数字为多项式的指数,按照指数从小到大依次输入) 5 | // 2 2 6 | // 0 -1 (系数为-1表示多项式结束) 7 | // 1 2 8 | // 2 3 9 | // 0 -1 (系数为-1表示多项式结束) 10 | // 输出样例:+1x^0+3x^2+2x^3 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "multinomial.h" 17 | using namespace std; 18 | 19 | void print_poly(Node *head) { 20 | Node *node = head->next; 21 | while (node != nullptr) { 22 | if (node->coff > 0) { 23 | cout << '+' << node->coff << "x^" << node->exp; 24 | } else if (node->coff < 0) { 25 | cout << node->coff << "x^" << node->exp; 26 | } 27 | node = node->next; 28 | } 29 | } 30 | 31 | int main() { 32 | Node *exp_linked_list1 = new Node; 33 | Node *current_node = exp_linked_list1; 34 | int coff, exp = 0; 35 | while (1) { 36 | cin >> coff >> exp; 37 | if (exp == -1) break; 38 | Node *new_node = new Node(coff, exp); 39 | current_node->next = new_node; 40 | current_node = new_node; 41 | } 42 | Node *exp_linked_list2 = new Node; 43 | current_node = exp_linked_list2; 44 | coff = 0, exp = 0; 45 | while (1) { 46 | cin >> coff >> exp; 47 | if (exp == -1) break; 48 | Node *new_node = new Node(coff, exp); 49 | current_node->next = new_node; 50 | current_node = new_node; 51 | } 52 | Node *sum = add(exp_linked_list1, exp_linked_list2); 53 | print_poly(sum); 54 | return 0; 55 | } -------------------------------------------------------------------------------- /textcode/chapter2/sLinkListTest.cpp: -------------------------------------------------------------------------------- 1 | // sLinkList类的测试程序 2 | // 插入:insert i x 3 | // 删除:remove i 4 | // 查找:search x 5 | // 清除: clear 6 | // 访问:visit i 7 | // 结束: exit 8 | 9 | // 输入样例: 10 | // insert 0 1 11 | // insert 1 2 12 | // insert 2 3 13 | // search 2 14 | // remove 1 15 | // search 2 16 | // visit 1 17 | // exit 18 | // 输出样例: 19 | // The index is 1 20 | // Not found 21 | // Visit element 3 22 | // 1 3 23 | #include 24 | #include 25 | 26 | #include "sLinkList.h" 27 | using namespace std; 28 | int main() { 29 | sLinkList slinklist; 30 | while (true) { 31 | char op[10]; 32 | cin >> op; 33 | 34 | if (strcmp(op, "insert") == 0) { 35 | int index, x; 36 | cin >> index >> x; 37 | if (index != slinklist.length()) 38 | cout << "Insert index is invalid!" << endl; 39 | else 40 | slinklist.insert(index, x); 41 | } else if (strcmp(op, "remove") == 0) { 42 | int index; 43 | cin >> index; 44 | slinklist.remove(index); 45 | } else if (strcmp(op, "search") == 0) { 46 | int x; 47 | cin >> x; 48 | int res = slinklist.search(x); 49 | if (res == -1) { 50 | cout << "Not found" << endl; 51 | } else { 52 | cout << "The index is " << res << endl; 53 | } 54 | } else if (strcmp(op, "visit") == 0) { 55 | int i; 56 | cin >> i; 57 | if (i >= slinklist.length()) { 58 | cout << "Element does not exists" << endl; 59 | continue; 60 | } 61 | int res = slinklist.visit(i); 62 | cout << "Visit element " << res << endl; 63 | } else if (strcmp(op, "exit") == 0) { 64 | break; 65 | } else if (strcmp(op, "clear") == 0) { 66 | slinklist.clear(); 67 | } else { 68 | cout << "Invalid operation!" << endl; 69 | } 70 | } 71 | slinklist.traverse(); 72 | return 0; 73 | } -------------------------------------------------------------------------------- /textcode/chapter2/seqList.h: -------------------------------------------------------------------------------- 1 | // 代码清单2-2至2-5 顺序表类的定义和实现 2 | #ifndef CHAPTER2_SEQLIST_H 3 | #define CHAPTER2_SEQLIST_H 4 | 5 | #include 6 | 7 | #include "list.h" 8 | using namespace std; 9 | 10 | template 11 | class seqList : public list { 12 | private: 13 | elemType *data; 14 | int currentLength; 15 | int maxSize; 16 | void doubleSpace(); 17 | 18 | public: 19 | seqList(int initSize = 10); 20 | ~seqList() { delete[] data; } // 释放动态数组的空间 21 | void clear() { currentLength = 0; } 22 | int length() const { return currentLength; } 23 | void insert(int i, const elemType &x); 24 | void remove(int i); 25 | int search(const elemType &x) const; 26 | elemType visit(int i) const { return data[i]; } 27 | void traverse() const; 28 | }; 29 | 30 | template 31 | seqList::seqList(int initSize) { 32 | data = new elemType[initSize]; 33 | maxSize = initSize; 34 | currentLength = 0; 35 | } 36 | 37 | template 38 | int seqList::search(const elemType &x) const { 39 | int i; 40 | // 使用for循环逐位搜索data[i]是否等于x 41 | for (i = 0; i < currentLength && data[i] != x; ++i); 42 | if (i == currentLength) 43 | return -1; 44 | else 45 | return i; 46 | } 47 | 48 | template 49 | void seqList::traverse() const { 50 | for (int i = 0; i < currentLength; ++i) cout << data[i] << ' '; 51 | cout << endl; 52 | } 53 | 54 | // 在第i个位置插入元素x 55 | template 56 | void seqList::insert(int i, const elemType &x) { 57 | // 如果当前表长已经达到了申请空间的上限,则必须执行扩大数组空间的操作 58 | if (currentLength == maxSize) doubleSpace(); 59 | 60 | // 将第 i 个元素到最后一个元素的储存位置全部后移一个位置 61 | for (int j = currentLength; j > i; j--) data[j] = data[j - 1]; 62 | data[i] = x; 63 | ++currentLength; 64 | } 65 | 66 | // 自动扩容函数doubleSpace() 67 | template 68 | void seqList::doubleSpace() { 69 | elemType *tmp = data; 70 | maxSize *= 2; 71 | data = new elemType[maxSize]; // 申请容量翻倍的新空间 72 | for (int i = 0; i < currentLength; ++i) 73 | data[i] = tmp[i]; // 将数据从旧空间复制到新空间 74 | delete[] tmp; // 回收旧空间 75 | } 76 | 77 | // 删除第i个位置的元素 78 | template 79 | void seqList::remove(int i) { 80 | // 将第i+1个元素到最后一个元素全部前移一个位置 81 | for (int j = i; j < currentLength - 1; j++) data[j] = data[j + 1]; 82 | --currentLength; 83 | } 84 | #endif // CHAPTER2_SEQLIST_H 85 | -------------------------------------------------------------------------------- /textcode/chapter2/seqListTest.cpp: -------------------------------------------------------------------------------- 1 | // seqList类的测试程序 2 | // 插入:insert i x 3 | // 删除:remove i 4 | // 查找:search x 5 | // 清除: clear 6 | // 访问:visit i 7 | // 结束: exit 8 | 9 | // 输入样例: 10 | // insert 0 1 11 | // insert 1 2 12 | // insert 2 3 13 | // search 2 14 | // remove 1 15 | // search 2 16 | // visit 1 17 | // exit 18 | // 输出样例: 19 | // The index is 1 20 | // Not found 21 | // Visit element 3 22 | // 1 3 23 | #include 24 | #include 25 | 26 | #include "seqList.h" 27 | using namespace std; 28 | int main() { 29 | seqList seqlist(20); 30 | while (true) { 31 | char op[10]; 32 | cin >> op; 33 | 34 | if (strcmp(op, "insert") == 0) { 35 | int index, x; 36 | cin >> index >> x; 37 | if (index != seqlist.length()) 38 | cout << "Insert index is invalid!" << endl; 39 | else 40 | seqlist.insert(index, x); 41 | } else if (strcmp(op, "remove") == 0) { 42 | int index; 43 | cin >> index; 44 | seqlist.remove(index); 45 | } else if (strcmp(op, "search") == 0) { 46 | int x; 47 | cin >> x; 48 | int res = seqlist.search(x); 49 | if (res == -1) { 50 | cout << "Not found" << endl; 51 | } else { 52 | cout << "The index is " << res << endl; 53 | } 54 | } else if (strcmp(op, "visit") == 0) { 55 | int i; 56 | cin >> i; 57 | if (i >= seqlist.length()) { 58 | cout << "Element does not exists" << endl; 59 | continue; 60 | } 61 | int res = seqlist.visit(i); 62 | cout << "Visit element " << res << endl; 63 | } else if (strcmp(op, "exit") == 0) { 64 | break; 65 | } else if (strcmp(op, "clear") == 0) { 66 | seqlist.clear(); 67 | } else { 68 | cout << "Invalid operation!" << endl; 69 | } 70 | } 71 | seqlist.traverse(); 72 | return 0; 73 | } -------------------------------------------------------------------------------- /textcode/chapter3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter3) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter3 7 | seqStackTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter3/bracketMatcher.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单3-21 括号匹配样例代码 2 | #include 3 | #include 4 | 5 | #include "seqStack.h" 6 | using namespace std; 7 | 8 | int main() { 9 | std::string s; 10 | cin >> s; 11 | seqStack bracket; // 用一个栈存储左括号 12 | for (int i = 0; i < s.length(); i++) { 13 | char cur = s[i]; 14 | if (cur == ']' || cur == ')' || cur == '}') { 15 | // 下一个字符是右括号时 16 | if (bracket.isEmpty()) { // 栈为空 17 | cout << "false" << endl; 18 | return 0; 19 | } 20 | char prev = bracket.pop(); // 和栈顶的左括号做匹配 21 | if (((prev == '[') && (cur == ']')) || 22 | ((prev == '(') && (cur == ')') || 23 | ((prev == '{') && (cur == '}')))) { 24 | continue; 25 | } else { 26 | cout << "false" << endl; // 左右括号不匹配,例如(} 27 | return 0; 28 | } 29 | } else if (cur == '[' || cur == '(' || cur == '{') { 30 | bracket.push(cur); // 将左括号进栈 31 | } 32 | } 33 | if (bracket.isEmpty()) { 34 | cout << "true" << endl; 35 | } else { 36 | cout << "false" << endl; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /textcode/chapter3/linkQueue.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-8至3-9 链接队列类 2 | #ifndef CHAPTER3_LINKQUEUE_H 3 | #define CHAPTER3_LINKQUEUE_H 4 | 5 | #include 6 | 7 | #include "queue.h" 8 | template 9 | class linkQueue : public queue { 10 | private: 11 | struct node { 12 | elemType data; 13 | node *next; 14 | node(const elemType &x, node *N = nullptr) { 15 | data = x; 16 | next = N; 17 | } 18 | node() : next(nullptr) {} 19 | ~node() {} 20 | }; 21 | 22 | node *front, *rear; 23 | 24 | public: 25 | linkQueue(); 26 | ~linkQueue(); 27 | bool isEmpty() const; 28 | void enQueue(const elemType &x); 29 | elemType deQueue(); 30 | elemType getHead() const; 31 | }; 32 | 33 | template 34 | linkQueue::linkQueue() { 35 | front = rear = nullptr; 36 | } 37 | 38 | template 39 | linkQueue::~linkQueue() { 40 | node *tmp; 41 | while (front != nullptr) { 42 | tmp = front; 43 | front = front->next; 44 | delete tmp; 45 | } 46 | } 47 | 48 | template 49 | bool linkQueue::isEmpty() const { 50 | return front == nullptr; 51 | } 52 | 53 | template 54 | elemType linkQueue::getHead() const { 55 | return front->data; 56 | } 57 | 58 | template 59 | void linkQueue::enQueue(const elemType &x) { 60 | if (rear == nullptr) // 入队前为空队列 61 | front = rear = new node(x); 62 | else 63 | rear = rear->next = new node(x); 64 | } 65 | 66 | template 67 | elemType linkQueue::deQueue() { 68 | node *tmp = front; 69 | elemType value = front->data; 70 | front = front->next; 71 | if (front == nullptr) rear = nullptr; // 出队后为空队列 72 | delete tmp; 73 | return value; 74 | } 75 | 76 | #endif // CHAPTER3_LINKQUEUE_H 77 | -------------------------------------------------------------------------------- /textcode/chapter3/linkQueueTest.cpp: -------------------------------------------------------------------------------- 1 | // 链接队列类的测试程序 2 | // 入队: enqueue 3 | // 出队: dequeue 4 | // 获取头元素:gethead 5 | // 样例输入: 6 | // enqueue 1 7 | // enqueue 2 8 | // enqueue 3 9 | // dequeue 10 | // gethead 11 | // dequeue 12 | // dequeue 13 | // 样例输出: 14 | // Dequeue element 1 15 | // Head element is 2 16 | // Dequeue element 2 17 | // Dequeue element 3 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #include "linkQueue.h" 24 | 25 | using namespace std; 26 | int main() { 27 | linkQueue *link_queue = new linkQueue(); 28 | assert(link_queue->isEmpty()); // 检查isEmpty函数 29 | while (true) { 30 | char op[10]; 31 | cin >> op; 32 | if (strcmp(op, "enqueue") == 0) { 33 | int x; 34 | cin >> x; 35 | link_queue->enQueue(x); 36 | } else if (strcmp(op, "dequeue") == 0) { 37 | cout << "Dequeue element " << link_queue->deQueue() << endl; 38 | } else if (strcmp(op, "gethead") == 0) { 39 | cout << "Head element is " << link_queue->getHead() << endl; 40 | } else if (strcmp(op, "exit") == 0) { 41 | return 0; 42 | } else 43 | cout << "Invalid operation!" << endl; 44 | } 45 | } -------------------------------------------------------------------------------- /textcode/chapter3/linkStack.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-18至3-20 链接栈 2 | #ifndef CHAPTER3_LINKSTACK_H 3 | #define CHAPTER3_LINKSTACK_H 4 | #include 5 | 6 | #include "stack.h" 7 | template 8 | class linkStack : public stack { 9 | private: 10 | struct node { 11 | elemType data; 12 | node *next; 13 | node(const elemType &x, node *N = nullptr) { 14 | data = x; 15 | next = N; 16 | } 17 | node() : next(nullptr) {} 18 | ~node() {} 19 | }; 20 | 21 | node *top_p; 22 | 23 | public: 24 | linkStack(); 25 | ~linkStack(); 26 | void push(const elemType &x); 27 | elemType pop(); 28 | elemType top() const; 29 | bool isEmpty() const; 30 | }; 31 | 32 | template 33 | linkStack::linkStack() { 34 | top_p = nullptr; 35 | } 36 | 37 | template 38 | linkStack::~linkStack() { 39 | node *tmp; 40 | while (top_p != nullptr) { 41 | tmp = top_p; 42 | top_p = top_p->next; 43 | delete tmp; 44 | } 45 | } 46 | 47 | template 48 | void linkStack::push(const elemType &x) { 49 | top_p = new node(x, top_p); // 申请一个存放元素x的结点,插入单链表的表头 50 | } 51 | 52 | template 53 | elemType linkStack::pop() { 54 | node *tmp = top_p; 55 | elemType x = tmp->data; // 保存栈顶元素值,以备返回 56 | top_p = top_p->next; // 从单链表中删除栈顶结点 57 | delete tmp; // 释放被删除的表头结点的空间 58 | return x; 59 | } 60 | 61 | template 62 | elemType linkStack::top() const { 63 | return top_p->data; 64 | } 65 | 66 | template 67 | bool linkStack::isEmpty() const { 68 | return top_p == nullptr; 69 | } 70 | 71 | #endif // CHAPTER3_LINKSTACK_H 72 | -------------------------------------------------------------------------------- /textcode/chapter3/linkStackTest.cpp: -------------------------------------------------------------------------------- 1 | // 链接栈的测试程序 2 | // 入栈:push 3 | // 出栈并获取栈顶元素:pop 4 | // 获取栈顶元素:top 5 | // 退出:exit 6 | // 样例输入: 7 | // push 1 8 | // push 2 9 | // top 10 | // push 3 11 | // pop 12 | // pop 13 | // pop 14 | // exit 15 | // 样例输出: 16 | // Top element is 2 17 | // Pop element 3 18 | // Pop element 2 19 | // Pop element 1 20 | #include 21 | #include 22 | #include 23 | 24 | #include "linkStack.h" 25 | 26 | using namespace std; 27 | int main() { 28 | linkStack *link_stack = new linkStack(); 29 | assert(link_stack->isEmpty()); // 检查isEmpty函数 30 | while (true) { 31 | char op[10]; 32 | cin >> op; 33 | if (strcmp(op, "push") == 0) { 34 | int x; 35 | cin >> x; 36 | link_stack->push(x); 37 | } else if (strcmp(op, "pop") == 0) { 38 | cout << "Pop element " << link_stack->pop() << endl; 39 | } else if (strcmp(op, "top") == 0) { 40 | cout << "Top element is " << link_stack->top() << endl; 41 | } else if (strcmp(op, "exit") == 0) { 42 | return 0; 43 | } else 44 | cout << "Invalid operation!" << endl; 45 | } 46 | } -------------------------------------------------------------------------------- /textcode/chapter3/queue.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-1 队列抽象类的定义 2 | #ifndef CHAPTER3_QUEUE_H 3 | #define CHAPTER3_QUEUE_H 4 | 5 | template 6 | class queue { 7 | public: 8 | virtual void enQueue(const elemType &x) = 0; // 入队 9 | virtual elemType deQueue() = 0; // 出队 10 | virtual elemType getHead() const = 0; // 读取队头元素 11 | virtual bool isEmpty() const = 0; // 判队列空 12 | virtual ~queue() {} // 虚析构函数 13 | }; 14 | #endif // CHAPTER3_QUEUE_H 15 | -------------------------------------------------------------------------------- /textcode/chapter3/seqQueue.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-2至3-7 循环队列类 2 | #ifndef CHAPTER3_SEQQUEUE_H 3 | #define CHAPTER3_SEQQUEUE_H 4 | 5 | #include "queue.h" 6 | template 7 | class seqQueue : public queue { 8 | private: 9 | elemType *elem; 10 | int maxSize; 11 | int front, rear; 12 | 13 | void doubleSpace(); 14 | bool isFull() const; 15 | 16 | public: 17 | seqQueue(int size = 10); 18 | ~seqQueue(); 19 | bool isEmpty() const; 20 | void enQueue(const elemType &x); 21 | elemType deQueue(); 22 | elemType getHead() const; 23 | }; 24 | 25 | template 26 | seqQueue::seqQueue(int size) { 27 | elem = new elemType[size]; 28 | maxSize = size; 29 | front = rear = 0; 30 | } 31 | 32 | template 33 | seqQueue::~seqQueue() { 34 | delete[] elem; 35 | } 36 | 37 | template 38 | void seqQueue::enQueue(const elemType &x) { 39 | if (isFull()) doubleSpace(); 40 | rear = (rear + 1) % maxSize; 41 | elem[rear] = x; 42 | } 43 | 44 | template 45 | elemType seqQueue::deQueue() { 46 | front = (front + 1) % maxSize; 47 | return elem[front]; 48 | } 49 | 50 | template 51 | elemType seqQueue::getHead() const { 52 | return elem[(front + 1) % maxSize]; 53 | } 54 | 55 | template 56 | bool seqQueue::isEmpty() const { 57 | return front == rear; 58 | } 59 | template 60 | bool seqQueue::isFull() const { 61 | return (rear + 1) % maxSize == front; 62 | } 63 | 64 | template 65 | void seqQueue::doubleSpace() { 66 | elemType *tmp = elem; 67 | elem = new elemType[2 * maxSize]; 68 | for (int i = 1; i < maxSize; ++i) { 69 | elem[i] = tmp[(front + i) % maxSize]; 70 | } 71 | front = 0; 72 | rear = maxSize - 1; 73 | maxSize *= 2; 74 | delete[] tmp; 75 | } 76 | #endif // CHAPTER3_SEQQUEUE_H 77 | -------------------------------------------------------------------------------- /textcode/chapter3/seqQueueTest.cpp: -------------------------------------------------------------------------------- 1 | // 循环队列类的测试程序 2 | // 入队: enqueue 3 | // 出队: dequeue 4 | // 获取头元素:gethead 5 | // 样例输入: 6 | // enqueue 1 7 | // enqueue 2 8 | // enqueue 3 9 | // dequeue 10 | // gethead 11 | // dequeue 12 | // dequeue 13 | // 样例输出: 14 | // Dequeue element 1 15 | // Head element is 2 16 | // Dequeue element 2 17 | // Dequeue element 3 18 | #include 19 | #include 20 | #include 21 | 22 | #include "seqQueue.h" 23 | 24 | using namespace std; 25 | int main() { 26 | seqQueue *seq_queue = new seqQueue(); 27 | assert(seq_queue->isEmpty()); // 检查isEmpty函数 28 | while (true) { 29 | char op[10]; 30 | cin >> op; 31 | if (strcmp(op, "enqueue") == 0) { 32 | int x; 33 | cin >> x; 34 | seq_queue->enQueue(x); 35 | } else if (strcmp(op, "dequeue") == 0) { 36 | cout << "Dequeue element " << seq_queue->deQueue() << endl; 37 | } else if (strcmp(op, "gethead") == 0) { 38 | cout << "Head element is " << seq_queue->getHead() << endl; 39 | } else if (strcmp(op, "exit") == 0) { 40 | return 0; 41 | } else 42 | cout << "Invalid operation!" << endl; 43 | } 44 | } -------------------------------------------------------------------------------- /textcode/chapter3/seqStack.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-12至代码清单3-17 顺序栈 2 | 3 | #ifndef CHAPTER3_SEQSTACK_H 4 | #define CHAPTER3_SEQSTACK_H 5 | #include "stack.h" 6 | template 7 | class seqStack : public stack { 8 | private: 9 | elemType *elem; // 栈的存储空间,即动态数组 10 | int maxSize; // 数组规模 11 | int top_p; // 保存栈顶位置 12 | void doubleSpace(); // 用于扩展数组空间的私有工具函数 13 | 14 | public: 15 | // 函数继承于stack基类 16 | seqStack(int initSize = 10); 17 | ~seqStack(); 18 | 19 | void push(const elemType &x); 20 | elemType pop(); 21 | elemType top() const; 22 | bool isEmpty() const; 23 | }; 24 | template 25 | seqStack::seqStack(int initSize) { 26 | elem = new elemType[initSize]; 27 | maxSize = initSize; 28 | top_p = -1; 29 | } 30 | 31 | template 32 | seqStack::~seqStack() { 33 | delete[] elem; 34 | } 35 | template 36 | void seqStack::doubleSpace() { 37 | elemType *tmp = elem; // 创建空间是原数组两倍的新数组 38 | elem = new elemType[2 * maxSize]; 39 | // 将原数组的数据移动到新数组中 40 | for (int i = 0; i < maxSize; ++i) elem[i] = tmp[i]; 41 | maxSize *= 2; 42 | delete[] tmp; // 将旧的数组空间销毁 43 | } 44 | template 45 | void seqStack::push(const elemType &x) { 46 | if (top_p == maxSize - 1) doubleSpace(); 47 | elem[++top_p] = x; 48 | } 49 | template 50 | elemType seqStack::pop() { 51 | return elem[top_p--]; 52 | } 53 | 54 | template 55 | elemType seqStack::top() const { 56 | return elem[top_p]; 57 | } 58 | template 59 | bool seqStack::isEmpty() const { 60 | return top_p == -1; 61 | } 62 | #endif // CHAPTER3_SEQSTACK_H 63 | -------------------------------------------------------------------------------- /textcode/chapter3/seqStackTest.cpp: -------------------------------------------------------------------------------- 1 | // 顺序栈的测试程序 2 | // 入栈:push 3 | // 出栈并获取栈顶元素:pop 4 | // 获取栈顶元素:top 5 | // 退出:exit 6 | // 样例输入: 7 | // push 1 8 | // push 2 9 | // top 10 | // push 3 11 | // pop 12 | // pop 13 | // pop 14 | // exit 15 | // 样例输出: 16 | // Top element is 2 17 | // Pop element 3 18 | // Pop element 2 19 | // Pop element 1 20 | #include 21 | #include 22 | #include 23 | 24 | #include "seqStack.h" 25 | 26 | using namespace std; 27 | int main() { 28 | seqStack *seq_stack = new seqStack(); 29 | assert(seq_stack->isEmpty()); // 检查isEmpty函数 30 | while (true) { 31 | char op[10]; 32 | cin >> op; 33 | if (strcmp(op, "push") == 0) { 34 | int x; 35 | cin >> x; 36 | seq_stack->push(x); 37 | } else if (strcmp(op, "pop") == 0) { 38 | cout << "Pop element " << seq_stack->pop() << endl; 39 | } else if (strcmp(op, "top") == 0) { 40 | cout << "Top element is " << seq_stack->top() << endl; 41 | } else if (strcmp(op, "exit") == 0) { 42 | return 0; 43 | } else 44 | cout << "Invalid operation!" << endl; 45 | } 46 | } -------------------------------------------------------------------------------- /textcode/chapter3/stack.h: -------------------------------------------------------------------------------- 1 | // 代码清单3-11 栈的抽象类的定义 2 | #ifndef CHAPTER3_STACK_H 3 | #define CHAPTER3_STACK_H 4 | 5 | template 6 | class stack { 7 | public: 8 | virtual void push(const elemType &x) = 0; // 进栈 9 | virtual elemType pop() = 0; // 出栈 10 | virtual elemType top() const = 0; // 读取栈顶元素 11 | virtual bool isEmpty() const = 0; // 判栈空 12 | virtual ~stack() {} // 虚析构函数 13 | }; 14 | 15 | #endif // CHAPTER3_STACK_H 16 | -------------------------------------------------------------------------------- /textcode/chapter3/washer.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单3-10 排队洗衣样例代码 2 | #include 3 | 4 | #include "seqQueue.h" 5 | using namespace std; 6 | 7 | int min(int a, int b) { 8 | if (a < b) return a; 9 | return b; 10 | } 11 | int max(int a, int b) { 12 | if (a > b) return a; 13 | return b; 14 | } 15 | 16 | int main() { 17 | int k; 18 | cout << "请输入学生个数:" << endl; 19 | cin >> k; 20 | seqQueue studentQueue(k); 21 | cout << "请依次输入学生洗衣时长:" << endl; 22 | for (int i = 0; i < k; i++) { 23 | int t; 24 | cin >> t; 25 | studentQueue.enQueue(t); // 创建学生洗衣服的队列 26 | } 27 | 28 | int time = 0; 29 | int washer1 = 0, washer2 = 0; 30 | if (studentQueue.isEmpty()) { // 当天没有学生预约洗衣服 31 | cout << 0; 32 | return 0; 33 | } else { 34 | washer1 = studentQueue.deQueue(); 35 | if (studentQueue.isEmpty()) { // 当天只有一位学生预约洗衣服 36 | cout << washer1 << endl; 37 | return 0; 38 | } else { 39 | washer2 = studentQueue.deQueue(); 40 | // 2台洗衣机开始完成前两位同学的洗衣请求 41 | } 42 | } 43 | while (!studentQueue.isEmpty()) { 44 | time += min(washer1, washer2); 45 | // 其中一台洗衣机完成了工作,总时长为time 46 | washer1 -= min(washer1, washer2); 47 | washer2 -= min(washer1, washer2); 48 | if (washer1 == 0) { 49 | washer1 = studentQueue.deQueue(); 50 | // 洗衣机1完成了工作,新的同学开始使用洗衣机1 51 | } else { // washer2 == 0 52 | washer2 = studentQueue.deQueue(); 53 | // 洗衣机2完成了工作,新的同学开始使用洗衣机2 54 | } 55 | } 56 | cout << time + max(washer1, washer2) << endl; 57 | // 总时间等于已经经过的时间加上washer1和washer2中剩余需要洗衣服时间更长者的时间 58 | return 0; 59 | } -------------------------------------------------------------------------------- /textcode/chapter4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter4) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | include_directories(.) 7 | 8 | add_executable(chapter4 9 | priorityQueueTest.cpp) 10 | -------------------------------------------------------------------------------- /textcode/chapter4/binaryTreeTest.cpp: -------------------------------------------------------------------------------- 1 | // 采用链接存储的二叉树类的测试程序 2 | // 首先,根据createTree函数的流程,构建二叉树 3 | // 例如: 4 | // 输入根结点:4 5 | // 输入4的两个儿子(-1表示空结点):1 2 6 | // 输入1的两个儿子(-1表示空结点):-1 5 7 | // 输入2的两个儿子(-1表示空结点):3 -1 8 | // 输入5的两个儿子(-1表示空结点):-1 -1 9 | // 输入3的两个儿子(-1表示空结点):-1 -1 10 | // create completed! 11 | // 现在的树的形状输出如下: 12 | // 层次遍历:4 1 2 5 3 13 | // 前序遍历:4 1 5 2 3 14 | // 中序遍历:1 5 4 3 2 15 | // 前序遍历:4 1 5 2 3 16 | // 这时可以开始调用成员函数 17 | // 输入: getRoot 输出:二叉树根的值为:4 18 | // 输入:lchild 2 输出:The left child of node 2 is 3 19 | // 输入:rchild 1 输出:The right child of node 1 is 5 20 | // 输入: 21 | // delLeft 2 22 | // delRight 1 23 | // print 24 | // 输出: 25 | // 现在的树的形状输出如下: 26 | // 层次遍历:4 1 2 27 | // 前序遍历:4 1 2 28 | // 中序遍历:1 4 2 29 | // 前序遍历:4 1 2 30 | // exit 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "binaryTree.h" 37 | using namespace std; 38 | const int N = 50, M = 10, W = 50; 39 | 40 | void print_tree(binaryTree *binary_tree) { 41 | // 测试输出整棵树 42 | cout << "现在的树的形状输出如下:"; 43 | binary_tree->levelOrder(); 44 | binary_tree->preOrder(); 45 | binary_tree->midOrder(); 46 | binary_tree->preOrder(); 47 | cout << endl; 48 | } 49 | int main() { 50 | binaryTree *binary_tree = new binaryTree; 51 | binary_tree->createTree(-1); 52 | print_tree(binary_tree); 53 | assert(!binary_tree->isEmpty()); 54 | while (true) { 55 | char op[30]; 56 | cin >> op; 57 | if (strcmp(op, "delLeft") == 0) { 58 | int x; 59 | cin >> x; 60 | binary_tree->delLeft(x); 61 | } else if (strcmp(op, "delRight") == 0) { 62 | int x; 63 | cin >> x; 64 | binary_tree->delRight(x); 65 | } else if (strcmp(op, "getRoot") == 0) { 66 | cout << "二叉树根的值为:" << binary_tree->getRoot(-1) << endl; 67 | } else if (strcmp(op, "print") == 0) { 68 | print_tree(binary_tree); 69 | } else if (strcmp(op, "lchild") == 0) { 70 | int x; 71 | cin >> x; 72 | cout << "The left child of node " << x << " is " 73 | << binary_tree->lchild(x, -1) << endl; 74 | } else if (strcmp(op, "rchild") == 0) { 75 | int x; 76 | cin >> x; 77 | cout << "The right child of node " << x << " is " 78 | << binary_tree->rchild(x, -1) << endl; 79 | } else if (strcmp(op, "exit") == 0) { 80 | break; 81 | } else { 82 | cout << "Invalid operation!" << endl; 83 | } 84 | } 85 | return 0; 86 | } -------------------------------------------------------------------------------- /textcode/chapter4/btree.h: -------------------------------------------------------------------------------- 1 | // 代码清单4-2 二叉树的抽象类定义 2 | template 3 | class bTree { 4 | public: 5 | virtual void clear() = 0; // 建立一棵空的二叉树 6 | virtual bool isEmpty() const = 0; // 判别二叉树是否为空树 7 | // 返回二叉树的根结点的值,如果根结点不存在,则返回一个特殊值flag 8 | virtual elemType getRoot(elemType flag) const = 0; 9 | // 返回结点x的父结点的值,如果x是根结点,则返回一个特殊值flag 10 | virtual elemType parent(elemType x, elemType flag) const = 0; 11 | // 返回结点x的左子结点的值,如果x不存在或x的左子结点不存在,则返回一个特殊值flag 12 | virtual elemType lchild(elemType x, elemType flag) const = 0; 13 | // 返回结点x的右子结点的值,如果x不存在或x的右子结点不存在,则返回一个特殊值flag 14 | virtual elemType rchild(elemType x, elemType flag) const = 0; 15 | virtual void delLeft(elemType x) = 0; // 删除结点x的左子树 16 | virtual void delRight(elemType x) = 0; // 删除结点x的右子树 17 | virtual void preOrder() const = 0; // 前序遍历二叉树 18 | virtual void midOrder() const = 0; // 中序遍历二叉树 19 | virtual void postOrder() const = 0; // 后序遍历二叉树 20 | virtual void levelOrder() const = 0; // 层次遍历二叉树 21 | virtual ~bTree() {} // 虚析构函数 22 | }; 23 | -------------------------------------------------------------------------------- /textcode/chapter4/hfTree.h: -------------------------------------------------------------------------------- 1 | // 代码清单4-9至4-10 哈夫曼树的实现 2 | #ifndef CHAPTER4_HFTREE_H 3 | #define CHAPTER4_HFTREE_H 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | template 9 | class hfTree { 10 | private: 11 | struct Node // 数组中的元素类型 12 | { 13 | elemType data; // 结点值 14 | int weight; // 结点的权值 15 | int parent, left, right; // 父结点及左\右儿子的下标 16 | }; 17 | 18 | Node *elem; 19 | int length; 20 | 21 | public: 22 | struct hfCode { // 哈夫曼编码的类型 23 | elemType data; // 待编码的字符 24 | string code; // 对应的哈夫曼编码 25 | }; 26 | 27 | hfTree(const elemType *x, const int *w, int size); 28 | void getCode(hfCode result[]); // 由哈夫曼树生成哈夫曼编码 29 | ~hfTree() { delete[] elem; } 30 | }; 31 | 32 | template 33 | hfTree::hfTree(const elemType *v, const int *w, int size) { 34 | const int MAX_INT = 32767; 35 | int min1, min2; // 最小树、次最小树的权值 36 | int minIndex1, minIndex2; // 最小树、次最小树的下标 37 | 38 | // 置初值 39 | length = 2 * size; 40 | elem = new Node[length]; 41 | for (int i = size; i < length; ++i) { 42 | elem[i].weight = w[i - size]; 43 | elem[i].data = v[i - size]; 44 | elem[i].parent = elem[i].left = elem[i].right = 0; 45 | } 46 | // 归并森林中的树 47 | for (int i = size - 1; i > 0; --i) { 48 | min1 = min2 = MAX_INT; 49 | minIndex1 = minIndex2 = 0; 50 | for (int j = i + 1; j < length; ++j) 51 | if (elem[j].parent == 0) 52 | if (elem[j].weight < min1) { // 元素j最小 53 | min2 = min1; 54 | min1 = elem[j].weight; 55 | minIndex1 = minIndex2; 56 | minIndex2 = j; 57 | } else if (elem[j].weight < min2) { // 元素j次小 58 | min2 = elem[j].weight; 59 | minIndex1 = j; 60 | } 61 | elem[i].weight = min1 + min2; 62 | elem[i].left = minIndex1; 63 | elem[i].right = minIndex2; 64 | elem[i].parent = 0; 65 | elem[minIndex1].parent = i; 66 | elem[minIndex2].parent = i; 67 | } 68 | } 69 | 70 | template 71 | void hfTree::getCode(hfCode result[]) { 72 | int size = length / 2; 73 | int p, s; // s是追溯过程中正在处理的结点,p是s的父结点下标 74 | 75 | for (int i = size; i < length; ++i) { // 遍历每个待编码的字符 76 | result[i - size].data = elem[i].data; 77 | result[i - size].code = ""; 78 | p = elem[i].parent; 79 | s = i; 80 | while (p) { // 向根追溯 81 | if (elem[p].left == s) 82 | result[i - size].code = '0' + result[i - size].code; 83 | else 84 | result[i - size].code = '1' + result[i - size].code; 85 | s = p; 86 | p = elem[p].parent; 87 | } 88 | } 89 | } 90 | 91 | #endif // CHAPTER4_HFTREE_H 92 | -------------------------------------------------------------------------------- /textcode/chapter4/hfTreeTest.cpp: -------------------------------------------------------------------------------- 1 | // 哈夫曼树的测试程序(修改自代码清单4-11) 2 | // 输入待编码字符及其对应的权值,可以获得其哈夫曼编码 3 | // 样例输入: 4 | // abcd 5 | // 请输入字符对应的权值: 6 | // a:1 7 | // b:2 8 | // c:3 9 | // d:4 10 | // 样例输出: 11 | // a:011 12 | // b:010 13 | // c:00 14 | // d:1 15 | #include 16 | #include 17 | 18 | #include "hfTree.h" 19 | using namespace std; 20 | 21 | int main() { 22 | char ch[100]; 23 | cin >> ch; 24 | int length = strlen(ch); 25 | int *w = new int[length]; 26 | cout << "请输入字符对应的权值:\n"; 27 | for (int i = 0; i < length; i++) { 28 | cout << ch[i] << ":"; 29 | cin >> w[i]; 30 | } 31 | hfTree tree(ch, w, length); 32 | hfTree::hfCode *result = new hfTree::hfCode[length]; 33 | 34 | tree.getCode(result); 35 | 36 | for (int i = 0; i < length; ++i) 37 | cout << result[i].data << ':' << result[i].code << endl; 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /textcode/chapter4/priorityQueueTest.cpp: -------------------------------------------------------------------------------- 1 | // 优先级队列测试程序 2 | // 首先,初始化优先级队列。 3 | // 样例: 4 | // 初始化优先级队列,请输入元素个数:5 5 | // 请输入初始化的元素:1 4 2 3 6 6 | // 优先级队列初始化已完成! 7 | // 接下来,可以输入enqueue,dequeue和getHead,执行入队、出队、获取队列头 8 | // 输入:dequeue 输出:Dequeue element 1 9 | // 输入:enqueue 5 10 | // 输入:getHead 输出:Head element is 2 11 | // 输入:dequeue 输出:Dequeue element 2 12 | // 输入:dequeue 输出:Dequeue element 3 13 | // 输入:dequeue 输出:Dequeue element 4 14 | // 输入:dequeue 输出:Dequeue element 5 15 | // 输入:dequeue 输出:Dequeue element 6 16 | // 输入:exit 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "priorityQueue.h" 24 | using namespace std; 25 | 26 | int main() { 27 | cout << "初始化优先级队列,请输入元素个数:"; 28 | int n; 29 | cin >> n; 30 | cout << "请输入初始化的元素:"; 31 | int *items = new int[n]; 32 | for (int i = 0; i < n; i++) { cin >> items[i]; } 33 | priorityQueue *priority_queue = new priorityQueue(items, n); 34 | cout << "优先级队列初始化已完成!" << endl; 35 | while (true) { 36 | char op[30]; 37 | cin >> op; 38 | if (strcmp(op, "enqueue") == 0) { 39 | int x; 40 | cin >> x; 41 | priority_queue->enQueue(x); 42 | } else if (strcmp(op, "dequeue") == 0) { 43 | cout << "Dequeue element " << priority_queue->deQueue() << endl; 44 | } else if (strcmp(op, "getHead") == 0) { 45 | cout << "Head element is " << priority_queue->getHead() << endl; 46 | } else if (strcmp(op, "exit") == 0) { 47 | break; 48 | } else { 49 | cout << "Invalid Operation!" << endl; 50 | } 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /textcode/chapter4/tree.h: -------------------------------------------------------------------------------- 1 | // 代码清单4-1 树的抽象类定义 2 | template 3 | class tree { 4 | public: 5 | virtual void clear() = 0; // 清空树 6 | virtual bool isEmpty() const = 0; // 判断树是否为空树 7 | // 返回树的根结点的值,如果根结点不存在,则返回一个特殊值flag 8 | virtual elemType getRoot(elemType flag) const = 0; 9 | // 返回结点x的父结点的值,如果x是根结点,则返回一个特殊值flag 10 | virtual elemType parent(elemType x, elemType fl ag) const = 0; 11 | // 返回结点x的第i个子结点的值,如果x不存在或x的第i个子结点不存在,则返回一个特殊值fl 12 | // ag 13 | virtual elemType child(elemType x, int i, elemType fl ag) const = 0; 14 | // 删除结点x的第i棵子树 15 | virtual void remove(elemType x, int i) = 0; 16 | virtual void traverse() const = 0; // 访问树的每个结点 17 | virtual ~tree() {} 18 | }; 19 | -------------------------------------------------------------------------------- /textcode/chapter5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter5) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | include_directories(.) 7 | 8 | add_executable(chapter5 9 | disjointSetTest.cpp) 10 | -------------------------------------------------------------------------------- /textcode/chapter5/binarySearchTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单5-5 二分查找的实现及其测试程序 2 | // 首先,输入初始化数据个数n,系统会自动生成n对对并排序 3 | // 样例: 4 | // 请输入初始化数据个数:10 5 | // 生成的数据为:<7,Z> <23,v> <27,x> <30,w> <40,J> <40,a> <44,0> <73,C> <87,J> <92,a> 6 | // 然后,可以输入search来搜索对应的key,other对 7 | // 输入:search 23 输出:Data key:23, value:v 8 | // 输入:search 40 输出:Data key:40, value:J 9 | // 输入:search 22 输出:Data does not exist! 10 | // exit 11 | #include 12 | #include 13 | #include 14 | 15 | #include "set.h" 16 | 17 | using namespace std; 18 | 19 | const int W = 100; 20 | const string charset = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 22 | 23 | template 24 | int binarySearch(SET data[], int size, const KEY &x) { 25 | int low = 1, high = size, mid; 26 | while (low <= high) { // 查找区间存在 27 | mid = (low + high) / 2; // 计算中间位置 28 | if (x == data[mid].key) return mid; // 查找完成 29 | if (x < data[mid].key) 30 | high = mid - 1; // 数据元素键值大于目标键值,目标位置在low和mid−1之间 31 | else 32 | low = mid + 1; // 数据元素键值小于目标键值,目标位置在mid+1和high之间 33 | } 34 | return 0; 35 | } 36 | 37 | void random_initialize(SET *data, int size) { 38 | cout << "生成的数据为:"; 39 | for (int i = 0; i < size; i++) { 40 | int randomNumber = rand() % W; 41 | data[i + 1].key = randomNumber; 42 | int index = rand() % charset.length(); 43 | char randomString = charset[index]; 44 | data[i + 1].other = randomString; 45 | } 46 | sort(data + 1, size); 47 | for (int i = 0; i < size; i++) { 48 | cout << '<' << data[i + 1].key << ',' << data[i + 1].other << "> "; 49 | } 50 | 51 | cout << endl; 52 | } 53 | int main() { 54 | int n; 55 | cout << "请输入初始化数据个数:"; 56 | cin >> n; 57 | SET *data = new SET[n]; 58 | random_initialize(data, n); 59 | while (true) { 60 | char op[30]; 61 | cin >> op; 62 | if (strcmp(op, "search") == 0) { 63 | int x; 64 | cin >> x; 65 | int index = binarySearch(data, n, x); 66 | if (index == -1) 67 | cout << "Data does not exist!" << endl; 68 | else { 69 | cout << "Data key:" << data[index].key 70 | << ", value:" << data[index].other << endl; 71 | } 72 | } else if (strcmp(op, "exit") == 0) { 73 | break; 74 | } else { 75 | cout << "Invalid Operation!" << endl; 76 | } 77 | } 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /textcode/chapter5/disjointSet.h: -------------------------------------------------------------------------------- 1 | // 代码清单5-6至5-8 不相交集合类的定义和实现 2 | 3 | #ifndef CHAPTER5_disjointSet_H 4 | #define CHAPTER5_disjointSet_H 5 | class disjointSet { 6 | private: 7 | int size; 8 | int *parent; 9 | 10 | public: 11 | disjointSet(int s); 12 | ~disjointSet() { delete[] parent; } 13 | void join(int root1, int root2); 14 | int find(int x); 15 | }; 16 | 17 | disjointSet::disjointSet(int n) { 18 | size = n; 19 | parent = new int[size]; 20 | for (int i = 0; i < size; ++i) parent[i] = -1; 21 | } 22 | 23 | int disjointSet::find(int x) { 24 | if (parent[x] < 0) return x; 25 | return parent[x] = find(parent[x]); 26 | } 27 | 28 | void disjointSet::join(int root1, int root2) { 29 | if (root1 == root2) return; 30 | if (parent[root1] > parent[root2]) { 31 | parent[root2] += parent[root1]; 32 | parent[root1] = root2; 33 | } else { 34 | parent[root1] += parent[root2]; 35 | parent[root2] = root1; 36 | } 37 | } 38 | 39 | #endif // CHAPTER5_disjointSet_H 40 | -------------------------------------------------------------------------------- /textcode/chapter5/disjointSetTest.cpp: -------------------------------------------------------------------------------- 1 | // 不相交集的测试程序 2 | // 首先,输入并查集集合元素个数 3 | // 请输入并查集集合元素个数:10 4 | // 接下来可以输入join命令或者find命令来执行并/查的操作 5 | // 样例输入: 6 | // join 5 6 7 | // join 6 7 8 | // find 7 9 | // exit 10 | // 样例输出: 11 | // The root of 7 is: 5 12 | #include 13 | #include 14 | 15 | #include "disjointSet.h" 16 | using namespace std; 17 | int main() { 18 | int n; 19 | cout << "请输入并查集集合元素个数:"; 20 | cin >> n; 21 | disjointSet *disjointset = new disjointSet(n); 22 | 23 | while (true) { 24 | char op[30]; 25 | cin >> op; 26 | if (strcmp(op, "join") == 0) { 27 | int a, b; 28 | cin >> a >> b; 29 | int roota = disjointset->find(a); 30 | int rootb = disjointset->find(b); 31 | disjointset->join(roota, rootb); 32 | } else if (strcmp(op, "find") == 0) { 33 | int x; 34 | cin >> x; 35 | cout << "The root of " << x << " is: " << disjointset->find(x) << endl; 36 | } else if (strcmp(op, "exit") == 0) { 37 | break; 38 | } else { 39 | cout << "Invalid Operation!" << endl; 40 | } 41 | } 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /textcode/chapter5/orderedSeqSearchTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单5-4 有序表的顺序查找实现及其测试程序 2 | // 首先,输入初始化数据个数n,系统会自动生成n对对并排序 3 | // 样例: 4 | // 请输入初始化数据个数:10 5 | // 生成的数据为:<7,Z> <23,v> <27,x> <30,w> <40,J> <40,a> <44,0> <73,C> <87,J> <92,a> 6 | // 然后,可以输入search来搜索对应的key,other对 7 | // 输入:search 23 输出:Data key:23, value:v 8 | // 输入:search 40 输出:Data key:40, value:J 9 | // 输入:search 22 输出:Data does not exist! 10 | // exit 11 | #include 12 | #include 13 | #include 14 | 15 | #include "set.h" 16 | 17 | using namespace std; 18 | 19 | const int W = 100; 20 | const string charset = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 22 | 23 | template 24 | int seqSearch(SET data[], int size, const KEY &x) { 25 | data[0].key = x; 26 | int i; 27 | for (i = size; x < data[i].key; --i); 28 | if (x == data[i].key) 29 | return i; 30 | else 31 | return 0; 32 | } 33 | 34 | void random_initialize(SET *data, int size) { 35 | cout << "生成的数据为:"; 36 | for (int i = 0; i < size; i++) { 37 | int randomNumber = rand() % W; 38 | data[i + 1].key = randomNumber; 39 | int index = rand() % charset.length(); 40 | char randomString = charset[index]; 41 | data[i + 1].other = randomString; 42 | } 43 | sort(data + 1, size); 44 | for (int i = 0; i < size; i++) { 45 | cout << '<' << data[i + 1].key << ',' << data[i + 1].other << "> "; 46 | } 47 | 48 | cout << endl; 49 | } 50 | int main() { 51 | int n; 52 | cout << "请输入初始化数据个数:"; 53 | cin >> n; 54 | SET *data = new SET[n]; 55 | random_initialize(data, n); 56 | while (true) { 57 | char op[30]; 58 | cin >> op; 59 | if (strcmp(op, "search") == 0) { 60 | int x; 61 | cin >> x; 62 | int index = seqSearch(data, n, x); 63 | if (index == 0) 64 | cout << "Data does not exist!" << endl; 65 | else { 66 | cout << "Data key:" << data[index].key 67 | << ", value:" << data[index].other << endl; 68 | } 69 | } else if (strcmp(op, "exit") == 0) { 70 | break; 71 | } else { 72 | cout << "Invalid Operation!" << endl; 73 | } 74 | } 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /textcode/chapter5/seqSearchTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单5-2 无序表的顺序查找实现及其测试程序 2 | // 首先,输入初始化数据个数n,系统会自动生成n对对 3 | // 样例: 4 | // 请输入初始化数据个数:10 5 | // 生成的数据为:<7,Z> <73,C> <30,w> <44,0> <23,v> <40,J> <92,a> <87,J> <27,x> <40,a> 6 | // 然后,可以输入search来搜索对应的key,other对 7 | // 输入:search 30 输出:Data key:30, value:w 8 | // 输入:search 27 输出:Data key:27, value:x 9 | // 输入:search 22 输出:Data does not exist! 10 | // exit 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "set.h" 17 | 18 | using namespace std; 19 | const int W = 100; 20 | const string charset = 21 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 22 | 23 | template 24 | int seqSearch(SET data[], int size, const KEY &x) { 25 | for (int i = 0; i < size; i++) { 26 | if (data[i].key == x) return i; 27 | } 28 | return -1; // 找不到,返回-1 29 | } 30 | 31 | void random_initialize(SET data[], int size) { 32 | cout << "生成的数据为:"; 33 | for (int i = 0; i < size; i++) { 34 | int randomNumber = rand() % W; 35 | data[i].key = randomNumber; 36 | int index = rand() % charset.length(); 37 | char randomString = charset[index]; 38 | data[i].other = randomString; 39 | cout << '<' << randomNumber << ',' << randomString << "> "; 40 | } 41 | cout << endl; 42 | } 43 | int main() { 44 | int n; 45 | cout << "请输入初始化数据个数:"; 46 | cin >> n; 47 | SET *data = new SET[n]; 48 | random_initialize(data, n); 49 | while (true) { 50 | char op[30]; 51 | cin >> op; 52 | if (strcmp(op, "search") == 0) { 53 | int x; 54 | cin >> x; 55 | int index = seqSearch(data, n, x); 56 | if (index == -1) 57 | cout << "Data does not exist!" << endl; 58 | else { 59 | cout << "Data key:" << data[index].key 60 | << ", value:" << data[index].other << endl; 61 | } 62 | } else if (strcmp(op, "exit") == 0) { 63 | break; 64 | } else { 65 | cout << "Invalid Operation!" << endl; 66 | } 67 | } 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /textcode/chapter5/set.h: -------------------------------------------------------------------------------- 1 | // 代码清单5-1 集合数据元素类型的定义 2 | 3 | #ifndef CHAPTER5_SET_H 4 | #define CHAPTER5_SET_H 5 | template 6 | struct SET { 7 | KEY key = 0; 8 | OTHER other = 0; 9 | SET(KEY k, OTHER o) { 10 | key = k; 11 | other = o; 12 | } 13 | SET() = default; 14 | }; 15 | 16 | template 17 | bool compareByKey(const SET &s1, const SET &s2) { 18 | return s1.key < s2.key; 19 | } 20 | 21 | template 22 | void sort(SET data[], int size) { 23 | // 实现了简单的冒泡排序 24 | for (int i = 0; i < size - 1; ++i) { 25 | for (int j = 0; j < size - i - 1; ++j) { 26 | if (data[j].key > data[j + 1].key) { 27 | // 交换位置 28 | SET temp = data[j]; 29 | data[j] = data[j + 1]; 30 | data[j + 1] = temp; 31 | } 32 | } 33 | } 34 | } 35 | 36 | #endif // CHAPTER5_SET_H 37 | -------------------------------------------------------------------------------- /textcode/chapter6/AVLTreeTest.cpp: -------------------------------------------------------------------------------- 1 | // AVL树的测试程序 2 | // 和std库中的map对照随机插入、删除后的结果,如果结果一致,则输出测试通过,否则测试失败。 3 | // 输出样例: 4 | // Insertion test passed. 5 | // Removal test passed. 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "AVLTree.h" 13 | 14 | using my_table_t = AVLTree; 15 | using std_table_t = map; 16 | 17 | const int N = 50, M = 10, W = 50; 18 | 19 | // 查找测试 20 | bool runLookupTest(my_table_t &my_table, std_table_t &std_table) { 21 | for (int i = 0; i < M; ++i) { 22 | int x = rand() % W; 23 | auto my_lookup = my_table.find(x); 24 | auto std_lookup = std_table.find(x); 25 | if (my_lookup != nullptr && std_lookup == std_table.end()) { 26 | std::cout << "unexpected key was found: " << x << std::endl; 27 | return false; 28 | } 29 | if (my_lookup == nullptr && std_lookup != std_table.end()) { 30 | std::cout << "expected key was not found: " << x << std::endl; 31 | return false; 32 | } 33 | if (std_lookup == std_table.end()) continue; 34 | if (std_lookup->second != my_lookup->other) { 35 | std::cout << "differ in value for key " << x << std::endl; 36 | return false; 37 | } 38 | } 39 | return true; 40 | } 41 | 42 | // 插入测试 43 | bool runInsertionTest(my_table_t &my_table, std_table_t &std_table) { 44 | for (int i = 0; i < N; ++i) { 45 | int x = rand() % W; 46 | std::cout << "insert #" << i << ": " << x << "\n"; 47 | my_table.insert(SET(x, 2 * x + 1)); 48 | std_table.insert(make_pair(x, 2 * x + 1)); 49 | if (!runLookupTest(my_table, std_table)) return false; 50 | } 51 | return true; 52 | } 53 | 54 | // 删除测试 55 | bool runRemovalTest(my_table_t &my_table, std_table_t &std_table) { 56 | for (int i = 0; i < N; ++i) { 57 | int x = rand() % W; 58 | std::cout << "remove #" << i << ", " << x << "\n"; 59 | my_table.remove(x); 60 | std_table.erase(x); 61 | if (!runLookupTest(my_table, std_table)) return false; 62 | } 63 | return true; 64 | } 65 | 66 | int main() { 67 | srand(time(0)); 68 | AVLTree my_table; 69 | std_table_t std_table; 70 | 71 | if (runInsertionTest(my_table, std_table)) { 72 | std::cout << "Insertion test passed.\n" << std::endl; 73 | } else { 74 | std::cout << "Insertion test failed.\n" << std::endl; 75 | return 0; 76 | } 77 | 78 | if (runRemovalTest(my_table, std_table)) { 79 | std::cout << "Removal test passed.\n" << std::endl; 80 | } else { 81 | std::cout << "Removal test failed.\n" << std::endl; 82 | return 0; 83 | } 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /textcode/chapter6/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter6) 3 | 4 | set(CMAKE_C_STANDARD 14) 5 | 6 | add_executable(chapter6 7 | RedBlackTreeTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter6/binarySearchTreeTest.cpp: -------------------------------------------------------------------------------- 1 | // 二叉查找树类的测试程序 2 | // 和std库中的map对照随机插入、删除后的结果,如果结果一致,则输出测试通过,否则测试失败。 3 | // 输出样例: 4 | // Insertion test passed. 5 | // Removal test passed. 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "binarySearchTree.h" 13 | 14 | using my_table_t = binarySearchTree; 15 | using std_table_t = map; 16 | 17 | const int N = 50, M = 10, W = 50; 18 | 19 | // 查找测试 20 | bool runLookupTest(my_table_t &my_table, std_table_t &std_table) { 21 | for (int i = 0; i < M; ++i) { 22 | int x = rand() % W; 23 | auto my_lookup = my_table.find(x); 24 | auto std_lookup = std_table.find(x); 25 | if (my_lookup != nullptr && std_lookup == std_table.end()) { 26 | std::cout << "unexpected key was found: " << x << std::endl; 27 | return false; 28 | } 29 | if (my_lookup == nullptr && std_lookup != std_table.end()) { 30 | std::cout << "expected key was not found: " << x << std::endl; 31 | return false; 32 | } 33 | if (std_lookup == std_table.end()) continue; 34 | if (std_lookup->second != my_lookup->other) { 35 | std::cout << "differ in value for key " << x << std::endl; 36 | return false; 37 | } 38 | } 39 | return true; 40 | } 41 | 42 | // 插入测试 43 | bool runInsertionTest(my_table_t &my_table, std_table_t &std_table) { 44 | for (int i = 0; i < N; ++i) { 45 | int x = rand() % W; 46 | std::cout << "insert #" << i << ": " << x << "\n"; 47 | my_table.insert(SET(x, 2 * x + 1)); 48 | std_table.insert(make_pair(x, 2 * x + 1)); 49 | if (!runLookupTest(my_table, std_table)) return false; 50 | } 51 | return true; 52 | } 53 | 54 | // 删除测试 55 | bool runRemovalTest(my_table_t &my_table, std_table_t &std_table) { 56 | for (int i = 0; i < N; ++i) { 57 | int x = rand() % W; 58 | std::cout << "remove #" << i << ", " << x << "\n"; 59 | my_table.remove(x); 60 | std_table.erase(x); 61 | if (!runLookupTest(my_table, std_table)) return false; 62 | } 63 | return true; 64 | } 65 | 66 | int main() { 67 | srand(time(0)); 68 | binarySearchTree my_table; 69 | std_table_t std_table; 70 | 71 | if (runInsertionTest(my_table, std_table)) { 72 | std::cout << "Insertion test passed.\n" << std::endl; 73 | } else { 74 | std::cout << "Insertion test failed.\n" << std::endl; 75 | return 0; 76 | } 77 | 78 | if (runRemovalTest(my_table, std_table)) { 79 | std::cout << "Removal test passed.\n" << std::endl; 80 | } else { 81 | std::cout << "Removal test failed.\n" << std::endl; 82 | return 0; 83 | } 84 | 85 | return 0; 86 | } -------------------------------------------------------------------------------- /textcode/chapter6/closeHashTable.h: -------------------------------------------------------------------------------- 1 | // 代码清单6-17 基于线性探测法的闭哈希表的实现 2 | 3 | #ifndef CHAPTER6_CLOSEHASHTABLE_H 4 | #define CHAPTER6_CLOSEHASHTABLE_H 5 | #include 6 | 7 | #include "dynamicSearchTable.h" 8 | using namespace std; 9 | 10 | template 11 | class closeHashTable : public dynamicSearchTable { 12 | private: 13 | struct node { // 哈希表的结点类 14 | SET data; 15 | int state; // 0:结点为空 1:结点已用 2:结点已被删除 16 | node() { state = 0; } 17 | }; 18 | 19 | node *array; 20 | int size; 21 | int (*key)(const KEY &x); 22 | static int defaultKey(const int &x) { return x; } 23 | 24 | public: 25 | closeHashTable(int length = 101, int (*f)(const KEY &x) = defaultKey); 26 | ~closeHashTable() { delete[] array; } 27 | SET *find(const KEY &x) const; 28 | void insert(const SET &x); 29 | void remove(const KEY &x); 30 | }; 31 | 32 | template 33 | closeHashTable::closeHashTable( 34 | int length, int (*f)(const KEY &x)) { 35 | size = length; 36 | array = new node[size]; 37 | key = f; 38 | } 39 | 40 | template 41 | void closeHashTable::insert(const SET &x) { 42 | int initPos, pos; 43 | 44 | initPos = pos = key(x.key) % size; 45 | do { 46 | if (array[pos].state != 1) { // 找到空位置 47 | array[pos].data = x; 48 | array[pos].state = 1; 49 | return; 50 | } 51 | pos = (pos + 1) % size; 52 | } while (pos != initPos); 53 | } 54 | 55 | template 56 | void closeHashTable::remove(const KEY &x) { 57 | int initPos, pos; 58 | initPos = pos = key(x) % size; 59 | do { 60 | if (array[pos].state == 0) return; 61 | if (array[pos].state == 1 && 62 | array[pos].data.key == x) { // 找到键值为x的数据元素,删除 63 | array[pos].state = 2; 64 | return; 65 | } 66 | pos = (pos + 1) % size; 67 | } while (pos != initPos); 68 | } 69 | 70 | template 71 | SET *closeHashTable::find(const KEY &x) const { 72 | int initPos, pos; 73 | initPos = pos = key(x) % size; 74 | do { 75 | if (array[pos].state == 0) return nullptr; // 没有找到 76 | if (array[pos].state == 1 && array[pos].data.key == x) // 找到 77 | return (SET *)&array[pos]; 78 | pos = (pos + 1) % size; 79 | } while (pos != initPos); 80 | } 81 | 82 | #endif // CHAPTER6_CLOSEHASHTABLE_H 83 | -------------------------------------------------------------------------------- /textcode/chapter6/dynamicSearchTable.h: -------------------------------------------------------------------------------- 1 | // 代码清单6-1 动态查找表抽象类的定义 2 | 3 | #ifndef CHAPTER6_DYNAMICSEARCHTABLE_H 4 | #define CHAPTER6_DYNAMICSEARCHTABLE_H 5 | 6 | #include "../chapter5/set.h" 7 | template 8 | class dynamicSearchTable { 9 | public: 10 | virtual SET *find(const KEY &x) const = 0; 11 | virtual void insert(const SET &x) = 0; 12 | virtual void remove(const KEY &x) = 0; 13 | virtual ~dynamicSearchTable() {}; 14 | }; 15 | 16 | #endif // CHAPTER6_DYNAMICSEARCHTABLE_H 17 | -------------------------------------------------------------------------------- /textcode/chapter6/openHashTable.h: -------------------------------------------------------------------------------- 1 | // 代码清单6-18 开哈希表的定义和实现 2 | 3 | #ifndef CHAPTER6_openHashTable_H 4 | #define CHAPTER6_openHashTable_H 5 | #include 6 | 7 | #include "dynamicSearchTable.h" 8 | using namespace std; 9 | 10 | template 11 | class openHashTable : public dynamicSearchTable { 12 | private: 13 | struct node { // 开哈希表中链接表的结点类 14 | SET data; 15 | node *next; 16 | node(const SET &d, node *n = nullptr) { 17 | data = d; 18 | next = n; 19 | } 20 | node() { next = nullptr; } 21 | }; 22 | 23 | node **array; // 指针数组 24 | int size; 25 | int (*key)(const KEY &x); 26 | static int defaultKey(const int &x) { return x; } 27 | 28 | public: 29 | openHashTable(int length = 101, int (*f)(const KEY &x) = defaultKey); 30 | ~openHashTable(); 31 | SET *find(const KEY &x) const; 32 | void insert(const SET &x); 33 | void remove(const KEY &x); 34 | }; 35 | 36 | template 37 | openHashTable::openHashTable(int length, int (*f)(const KEY &x)) { 38 | size = length; 39 | array = new node *[size]; 40 | key = f; 41 | for (int i = 0; i < size; ++i) array[i] = nullptr; 42 | } 43 | 44 | template 45 | openHashTable::~openHashTable() { 46 | node *p, *q; 47 | 48 | for (int i = 0; i < size; ++i) { // 释放所有单链表的空间 49 | p = array[i]; 50 | while (p != nullptr) { 51 | q = p->next; 52 | delete p; 53 | p = q; 54 | }; 55 | } 56 | 57 | delete[] array; 58 | } 59 | 60 | template 61 | void openHashTable::insert(const SET &x) { 62 | int pos; 63 | node *p; 64 | 65 | pos = key(x.key) % size; 66 | array[pos] = new node(x, array[pos]); 67 | } 68 | 69 | template 70 | void openHashTable::remove(const KEY &x) { 71 | int pos; 72 | node *p, *q; 73 | 74 | pos = key(x) % size; 75 | if (array[pos] == nullptr) return; 76 | p = array[pos]; 77 | if (array[pos]->data.key == x) { 78 | array[pos] = p->next; 79 | delete p; 80 | return; 81 | } 82 | while (p->next != nullptr && !(p->next->data.key == x)) p = p->next; 83 | if (p->next != nullptr) { 84 | q = p->next; 85 | p->next = q->next; 86 | delete q; 87 | } 88 | } 89 | 90 | template 91 | SET *openHashTable::find(const KEY &x) const { 92 | int pos; 93 | node *p; 94 | 95 | pos = key(x) % size; 96 | p = array[pos]; 97 | while (p != nullptr && !(p->data.key == x)) p = p->next; 98 | if (p == nullptr) 99 | return nullptr; 100 | else 101 | return (SET *)p; 102 | } 103 | 104 | #endif // CHAPTER6_openHashTable_H 105 | -------------------------------------------------------------------------------- /textcode/chapter6/redBlackTreeTest.cpp: -------------------------------------------------------------------------------- 1 | // 红黑树的测试程序 2 | // 和std库中的map对照随机插入、删除后的结果,如果结果一致,则输出测试通过,否则测试失败。 3 | // 输出样例: 4 | // Insertion test passed. 5 | // Removal test passed. 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "redBlackTree.h" 12 | 13 | using my_table_t = redBlackTree; 14 | using std_table_t = map; 15 | 16 | const int N = 50, M = 10, W = 50; 17 | 18 | // 查找测试 19 | bool runLookupTest(my_table_t &my_table, std_table_t &std_table) { 20 | for (int i = 0; i < M; ++i) { 21 | int x = rand() % W; 22 | auto my_lookup = my_table.find(x); 23 | auto std_lookup = std_table.find(x); 24 | if (my_lookup != nullptr && std_lookup == std_table.end()) { 25 | std::cout << "unexpected key was found: " << x << std::endl; 26 | return false; 27 | } 28 | if (my_lookup == nullptr && std_lookup != std_table.end()) { 29 | std::cout << "expected key was not found: " << x << std::endl; 30 | return false; 31 | } 32 | if (std_lookup == std_table.end()) continue; 33 | if (std_lookup->second != my_lookup->other) { 34 | std::cout << "differ in value for key " << x << std::endl; 35 | return false; 36 | } 37 | } 38 | return true; 39 | } 40 | 41 | // 插入测试 42 | bool runInsertionTest(my_table_t &my_table, std_table_t &std_table) { 43 | for (int i = 0; i < N; ++i) { 44 | int x = rand() % W; 45 | std::cout << "insert #" << i << ": " << x << "\n"; 46 | my_table.insert(SET(x, 2 * x + 1)); 47 | std_table.insert(make_pair(x, 2 * x + 1)); 48 | if (!runLookupTest(my_table, std_table)) return false; 49 | } 50 | return true; 51 | } 52 | 53 | // 删除测试 54 | bool runRemovalTest(my_table_t &my_table, std_table_t &std_table) { 55 | for (int i = 0; i < N; ++i) { 56 | int x = rand() % W; 57 | std::cout << "remove #" << i << ", " << x << "\n"; 58 | my_table.remove(x); 59 | std_table.erase(x); 60 | if (!runLookupTest(my_table, std_table)) return false; 61 | } 62 | return true; 63 | } 64 | 65 | int main() { 66 | srand(time(0)); 67 | redBlackTree my_table; 68 | std_table_t std_table; 69 | 70 | if (runInsertionTest(my_table, std_table)) { 71 | std::cout << "Insertion test passed.\n" << std::endl; 72 | } else { 73 | std::cout << "Insertion test failed.\n" << std::endl; 74 | return 0; 75 | } 76 | 77 | if (runRemovalTest(my_table, std_table)) { 78 | std::cout << "Removal test passed.\n" << std::endl; 79 | } else { 80 | std::cout << "Removal test failed.\n" << std::endl; 81 | return 0; 82 | } 83 | 84 | return 0; 85 | } -------------------------------------------------------------------------------- /textcode/chapter7/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter7) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter7 7 | bucketSortTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter7/bubbleSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-6 冒泡排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 冒泡排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | 19 | using namespace std; 20 | template 21 | void bubbleSort(SET a[], int size) { 22 | int i, j; 23 | SET tmp; 24 | bool flag = true; // 记录一趟起泡中有没有进行过数据元素的交换 25 | 26 | for (i = 1; i < size && flag; ++i) { // (size-1)趟起泡 27 | flag = false; 28 | for (j = 0; j < size - i; ++j) // 第i趟起泡 29 | if (a[j + 1].key < a[j].key) { 30 | tmp = a[j]; 31 | a[j] = a[j + 1]; 32 | a[j + 1] = tmp; 33 | flag = true; 34 | } 35 | } 36 | } 37 | 38 | SET a[100000]; 39 | int main() { 40 | cout << "请输入待排序数组的元素个数:"; 41 | int n; 42 | cin >> n; 43 | 44 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 45 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 46 | bubbleSort(a, n); 47 | cout << "\n冒泡排序后的数组元素为:\n"; 48 | for (int i = 0; i < n; i++) { 49 | cout << a[i].key << ' ' << a[i].other << endl; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /textcode/chapter7/bucketSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-10 基数排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 基数排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | using namespace std; 19 | 20 | template 21 | struct node { 22 | SET data; 23 | node *next; 24 | node() { next = nullptr; } 25 | node(SET d) : data(d) { next = nullptr; } 26 | }; 27 | 28 | template 29 | void bucketSort(node *&p) // p是链接表表头 30 | { 31 | // bucket, last:10个口袋 32 | node *bucket[10], *last[10], *tail; 33 | int i, j, k, base = 1, max = 0, len = 0; 34 | 35 | for (tail = p; tail != nullptr; tail = tail->next) // 找最大键值 36 | if (tail->data.key > max) max = tail->data.key; 37 | 38 | // 寻找最大键值的位数 39 | if (max == 0) 40 | len = 0; 41 | else 42 | while (max > 0) { 43 | ++len; 44 | max /= 10; 45 | } 46 | 47 | for (i = 1; i <= len; ++i) { // 执行len次分配和重组操作 48 | for (j = 0; j <= 9; ++j) 49 | bucket[j] = last[j] = nullptr; // 清空口袋 50 | while (p != nullptr) { // 执行一次分配 51 | k = p->data.key / base % 10; // 计算结点所在的口袋 52 | if (bucket[k] == nullptr) 53 | bucket[k] = last[k] = p; 54 | else 55 | last[k] = last[k]->next = p; 56 | p = p->next; 57 | } 58 | p = nullptr; // 重组后的链接表表头 59 | for (j = 0; j <= 9; ++j) { // 执行重组 60 | if (bucket[j] == nullptr) continue; 61 | if (p == nullptr) 62 | p = bucket[j]; 63 | else 64 | tail->next = bucket[j]; 65 | tail = last[j]; 66 | } 67 | tail->next = nullptr; // 尾结点置空 68 | base *= 10; // 为下一次分配做准备 69 | } 70 | } 71 | 72 | SET a[100000]; 73 | int main() { 74 | cout << "请输入待排序数组的元素个数:"; 75 | int n; 76 | cin >> n; 77 | node *head; 78 | node *tail = nullptr; 79 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 80 | int i = 0, key, other; 81 | do { 82 | cin >> key >> other; 83 | if (i == 0) { 84 | head = new node(SET(key, other)); 85 | tail = head; 86 | } else { 87 | node *currentNode = 88 | new node(SET(key, other)); 89 | tail->next = currentNode; 90 | tail = currentNode; 91 | } 92 | i++; 93 | } while (i < n); 94 | bucketSort(head); 95 | cout << "\n基数排序后的数组元素为:\n"; 96 | node *currentNode = head; 97 | while (currentNode != nullptr) { 98 | cout << currentNode->data.key << ' ' << currentNode->data.other 99 | << endl; 100 | currentNode = currentNode->next; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /textcode/chapter7/heapSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-4至7-5 堆排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 堆排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | 19 | using namespace std; 20 | 21 | template 22 | void heapSort(SET a[], int size) { 23 | int i; 24 | SET tmp; 25 | 26 | // 创建初始的堆 27 | for (i = size / 2 - 1; i >= 0; i--) percolateDown(a, i, size); 28 | 29 | // 执行n-1次出队操作 30 | for (i = size - 1; i > 0; --i) { 31 | tmp = a[0]; 32 | a[0] = a[i]; 33 | a[i] = tmp; // delete a[0] 34 | percolateDown(a, 0, i); 35 | } 36 | } 37 | 38 | template 39 | void percolateDown(SET a[], int hole, int size) { 40 | int child; 41 | SET tmp = a[hole]; 42 | 43 | for (; hole * 2 + 1 < size; hole = child) { 44 | child = hole * 2 + 1; 45 | if (child != size - 1 && a[child + 1].key > a[child].key) child++; 46 | if (a[child].key > tmp.key) 47 | a[hole] = a[child]; 48 | else 49 | break; 50 | } 51 | a[hole] = tmp; 52 | } 53 | 54 | SET a[100000]; 55 | int main() { 56 | cout << "请输入待排序数组的元素个数:"; 57 | int n; 58 | cin >> n; 59 | 60 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 61 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 62 | heapSort(a, n); 63 | cout << "\n堆排序后的数组元素为:\n"; 64 | for (int i = 0; i < n; i++) { 65 | cout << a[i].key << ' ' << a[i].other << endl; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /textcode/chapter7/mergeSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-8至7-9 归并排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 归并排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | using namespace std; 19 | template 20 | void mergeSort(SET a[], int left, int right) { 21 | int mid = (left + right) / 2; 22 | 23 | if (left == right) return; 24 | mergeSort(a, left, mid); 25 | mergeSort(a, mid + 1, right); 26 | merge(a, left, mid + 1, right); 27 | } 28 | 29 | template 30 | void mergeSort(SET a[], int size) { 31 | mergeSort(a, 0, size - 1); 32 | } 33 | 34 | template 35 | void merge(SET a[], int left, int mid, int right) { 36 | SET *tmp = new SET[right - left + 1]; 37 | 38 | int i = left, j = mid, k = 0; 39 | 40 | while (i < mid && j <= right) // 两表都未结束 41 | if (a[i].key < a[j].key) 42 | tmp[k++] = a[i++]; 43 | else 44 | tmp[k++] = a[j++]; 45 | 46 | while (i < mid) tmp[k++] = a[i++]; // 前半部分没有结束 47 | while (j <= right) tmp[k++] = a[j++]; // 后半部分没有结束 48 | 49 | for (i = 0, k = left; k <= right;) a[k++] = tmp[i++]; 50 | delete[] tmp; 51 | } 52 | 53 | SET a[100000]; 54 | int main() { 55 | cout << "请输入待排序数组的元素个数:"; 56 | int n; 57 | cin >> n; 58 | 59 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 60 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 61 | mergeSort(a, n); 62 | cout << "\n归并排序后的数组元素为:\n"; 63 | for (int i = 0; i < n; i++) { 64 | cout << a[i].key << ' ' << a[i].other << endl; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /textcode/chapter7/quickSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-7 快速排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 快速排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | using namespace std; 19 | template 20 | int divide(SET a[], int low, int high) { 21 | SET k = a[low]; 22 | do { // 循环直到low和high重叠 23 | while (low < high && a[high].key > k.key) 24 | --high; // 从右向左找到小于k的值 25 | if (low < high) { 26 | a[low] = a[high]; 27 | ++low; 28 | } // 将找到的小于k的值放入low位置 29 | while (low < high && a[low].key <= k.key) 30 | ++low; // 从左向右找到大于k的值 31 | if (low < high) { 32 | a[high] = a[low]; 33 | --high; 34 | } // 将找到的大于k的值放入high位置 35 | } while (low != high); 36 | a[low] = k; 37 | return low; 38 | } 39 | template 40 | void quickSort(SET a[], int low, int high) { 41 | int mid; 42 | if (low >= high) return; // 待分段的元素只有1个或0个,递归终止 43 | mid = divide(a, low, high); 44 | quickSort(a, low, mid - 1); // 排序左边一半 45 | quickSort(a, mid + 1, high); // 排序右边一半 46 | } 47 | 48 | template 49 | void quickSort(SET a[], int size) { // 包裹函数 50 | quickSort(a, 0, size - 1); 51 | } 52 | 53 | SET a[100000]; 54 | int main() { 55 | cout << "请输入待排序数组的元素个数:"; 56 | int n; 57 | cin >> n; 58 | 59 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 60 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 61 | quickSort(a, n); 62 | cout << "\n快速排序后的数组元素为:\n"; 63 | for (int i = 0; i < n; i++) { 64 | cout << a[i].key << ' ' << a[i].other << endl; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /textcode/chapter7/shellSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-2 希尔排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 希尔排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | 19 | using namespace std; 20 | template 21 | void shellSort(SET a[], int size) { 22 | int step, i, j; 23 | SET tmp; 24 | for (step = size / 2; step > 0; step /= 2) // step为希尔增量 25 | for (i = step; i < size; ++i) { 26 | // 对相距step的元素序列采用直接插入排序 27 | tmp = a[i]; 28 | for (j = i - step; j >= 0 && a[j].key > tmp.key; j -= step) 29 | a[j + step] = a[j]; 30 | a[j + step] = tmp; 31 | } 32 | } 33 | 34 | SET a[100000]; 35 | int main() { 36 | cout << "请输入待排序数组的元素个数:"; 37 | int n; 38 | cin >> n; 39 | 40 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 41 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 42 | shellSort(a, n); 43 | cout << "\n希尔排序后的数组元素为:\n"; 44 | for (int i = 0; i < n; i++) { 45 | cout << a[i].key << ' ' << a[i].other << endl; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /textcode/chapter7/simpleInsertSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-1 直接插入排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 插入排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | 19 | using namespace std; 20 | 21 | template 22 | void simpleInsertSort(SET a[], int size) { 23 | int k; 24 | SET tmp; 25 | 26 | for (int j = 1; j < size; ++j) { 27 | tmp = a[j]; 28 | for (k = j - 1; k >= 0 && tmp.key < a[k].key; --k) 29 | a[k + 1] = a[k]; 30 | a[k + 1] = tmp; 31 | } 32 | } 33 | 34 | SET a[100000]; 35 | int main() { 36 | cout << "请输入待排序数组的元素个数:"; 37 | int n; 38 | cin >> n; 39 | 40 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 41 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 42 | simpleInsertSort(a, n); 43 | cout << "\n插入排序后的数组元素为:\n"; 44 | for (int i = 0; i < n; i++) { 45 | cout << a[i].key << ' ' << a[i].other << endl; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /textcode/chapter7/simpleSelectSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 代码清单7-3 直接选择排序 2 | // 样例输入: 3 | // 请输入待排序数组的元素个数: 4 4 | // 请依次输入待排序数组元素(按照key,other的形式): 5 | // 1 1 6 | // 4 4 7 | // 7 2 8 | // 3 6 9 | // 样例输出: 10 | // 选择排序后的数组元素为: 11 | // 1 1 12 | // 3 6 13 | // 4 4 14 | // 7 2 15 | #include 16 | 17 | #include "../chapter5/set.h" 18 | 19 | using namespace std; 20 | template 21 | void simpleSelectSort(SET a[], int size) { 22 | int i, j, min; 23 | SET tmp; 24 | 25 | for (i = 0; i < size - 1; ++i) { 26 | min = i; 27 | for (j = i + 1; j < size; ++j) 28 | if (a[j].key < a[min].key) min = j; 29 | tmp = a[i]; 30 | a[i] = a[min]; 31 | a[min] = tmp; 32 | } 33 | } 34 | 35 | SET a[100000]; 36 | int main() { 37 | cout << "请输入待排序数组的元素个数:"; 38 | int n; 39 | cin >> n; 40 | 41 | cout << "\n请依次输入待排序数组元素(按照key,other的形式):\n"; 42 | for (int i = 0; i < n; i++) { cin >> a[i].key >> a[i].other; } 43 | simpleSelectSort(a, n); 44 | cout << "\n选择排序后的数组元素为:\n"; 45 | for (int i = 0; i < n; i++) { 46 | cout << a[i].key << ' ' << a[i].other << endl; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /textcode/chapter8/BPlusTreeTest.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "BPlusTree.h" 5 | #include "List.h" 6 | #include "Pair.h" 7 | 8 | const int N = 1000; 9 | 10 | // 请注意,B+树在运行时,会生成一些存放数据的文件 11 | // 如果程序正常终止,下次运行时会自动加载这些文件中的数据 12 | // 在调试B+树代码时,如果程序出现异常终止,你需要先删除B+树生成的数据文件再重新运行 13 | void runTest1() { 14 | BPlusTree bpt("test"); 15 | for (int i = 1; i <= N; ++i) { bpt.insert(i, i); } 16 | int cnt = 0; 17 | for (int i = 1; i <= N; ++i) { 18 | int val; 19 | bool found = bpt.find(i, val); 20 | cnt += found; 21 | } 22 | assert(cnt == N); 23 | for (int i = 2; i <= N; i += 2) { bpt.remove(i); } 24 | cnt = 0; 25 | for (int i = 1; i <= N; ++i) { 26 | int val; 27 | bool found = bpt.find(i, val); 28 | cnt += found; 29 | } 30 | assert(cnt == N / 2); 31 | for (int i = 3; i <= N; i += 3) { bpt.remove(i); } 32 | cnt = 0; 33 | for (int i = 1; i <= N; ++i) { 34 | int val; 35 | bool found = bpt.find(i, val); 36 | cnt += found; 37 | } 38 | assert(cnt == N - N / 2 - N / 3 + N / 6); 39 | for (int i = 1; i <= N; i += 100) { 40 | int val; 41 | bool found = bpt.find(i, val); 42 | if (found) { 43 | assert(val == i); 44 | assert(i % 2 != 0 && i % 3 != 0); 45 | std::cout << "key = " << i << ", value = " << val << std::endl; 46 | } 47 | } 48 | std::cout << "test1 passed" << std::endl; 49 | } 50 | 51 | // 还需要测试,重新打开的程序能否正确加载磁盘中的数据 52 | // runTest1()中的B+树已经析构,这里重新构造一个B+树,然后从磁盘中加载数据 53 | void runTest2() { 54 | BPlusTree bpt("test"); 55 | int cnt = 0; 56 | for (int i = 1; i <= N; ++i) { 57 | int val; 58 | bool found = bpt.find(i, val); 59 | cnt += found; 60 | } 61 | assert(cnt == N - N / 2 - N / 3 + N / 6); 62 | for (int i = 1; i <= N; i += 100) { 63 | int val; 64 | bool found = bpt.find(i, val); 65 | if (found) { 66 | assert(val == i); 67 | assert(i % 2 != 0 && i % 3 != 0); 68 | std::cout << "key = " << i << ", value = " << val << std::endl; 69 | } 70 | } 71 | std::cout << "test2 passed" << std::endl; 72 | } 73 | 74 | // 输出所有的key和value 75 | void runTest3() { 76 | BPlusTree bpt("test"); 77 | std::cout << "traversing B+ tree" << std::endl; 78 | bpt.traverse(); 79 | std::cout << "traverse finished" << std::endl; 80 | } 81 | 82 | int main() { 83 | runTest1(); 84 | runTest2(); 85 | runTest3(); 86 | return 0; 87 | } -------------------------------------------------------------------------------- /textcode/chapter8/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter8) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter8 7 | BPlusTreeTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter8/Pair.h: -------------------------------------------------------------------------------- 1 | #ifndef PAIR_H 2 | #define PAIR_H 3 | 4 | template 5 | struct Pair { 6 | FirstType first; 7 | SecondType second; 8 | 9 | Pair() {} 10 | Pair(const FirstType &first, const SecondType &second) 11 | : first(first), second(second) {} 12 | bool operator<(const Pair &rhs) const { 13 | if (first != rhs.first) { 14 | return first < rhs.first; 15 | } else { 16 | return second < rhs.second; 17 | } 18 | } 19 | bool operator==(const Pair &rhs) const { 20 | return first == rhs.first && second == rhs.second; 21 | } 22 | bool operator!=(const Pair &rhs) const { return !(*this == rhs); } 23 | bool operator>(const Pair &rhs) const { return rhs < *this; } 24 | bool operator<=(const Pair &rhs) const { return !(*this > rhs); } 25 | bool operator>=(const Pair &rhs) const { return !(*this < rhs); } 26 | }; 27 | 28 | #endif -------------------------------------------------------------------------------- /textcode/chapter8/StorageSearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef STORAGE_SEARCH_TABLE_INTERFACE_H 2 | #define STORAGE_SEARCH_TABLE_INTERFACE_H 3 | 4 | #include "List.h" 5 | 6 | template 7 | struct Pair; 8 | 9 | template 10 | class StorageSearchTable { 11 | public: 12 | virtual bool find(const KeyType &key, ValueType &value) = 0; 13 | virtual void insert(const KeyType &key, const ValueType &val) = 0; 14 | virtual void remove(const KeyType &key) = 0; 15 | virtual ~StorageSearchTable() {}; 16 | }; 17 | 18 | #endif // STORAGE_SEARCH_TABLE_INTERFACE_H -------------------------------------------------------------------------------- /textcode/chapter9/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.23) 2 | project(chapter9) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | add_executable(chapter9 7 | topSortTest.cpp) 8 | -------------------------------------------------------------------------------- /textcode/chapter9/EulerCircuitTest.cpp: -------------------------------------------------------------------------------- 1 | // 邻接表实现的欧拉回路的测试程序 2 | // 样例输入(以图9-11为例): 3 | // 请输入图的顶点个数:6 4 | // 请依次输入无向图的边(-1 -1表示输入完毕): 5 | // 0 1 6 | // 0 2 7 | // 1 2 8 | // 1 3 9 | // 1 4 10 | // 2 3 11 | // 2 4 12 | // 3 4 13 | // 3 5 14 | // 4 5 15 | // -1 -1 16 | // 请输入查询欧拉回路的起点编号:5 17 | // 样例输出: 18 | // 欧拉回路是: 19 | // 5 4 2 1 0 2 3 1 4 3 5 20 | 21 | #include 22 | 23 | #include "adjListGraph.h" 24 | using namespace std; 25 | int main() { 26 | cout << "请输入图的顶点个数:"; 27 | int verSize; 28 | cin >> verSize; 29 | int *d = new int[verSize]; 30 | for (int i = 0; i < verSize; i++) d[i] = i; 31 | adjListGraph *adj_list_graph = 32 | new adjListGraph(verSize, d); 33 | cout << "请依次输入无向图的边(-1 -1表示输入完毕):"; 34 | while (true) { 35 | int u, v; 36 | 37 | cin >> u >> v; 38 | if (u == -1) { 39 | break; 40 | } else { 41 | adj_list_graph->insert(u, v, 1); 42 | adj_list_graph->insert(v, u, 1); 43 | } 44 | } 45 | cout << "请输入查询欧拉回路的起点编号:"; 46 | int start; 47 | cin >> start; 48 | EulerNode *beg, *end; 49 | adj_list_graph->EulerCircuit(start); 50 | return 0; 51 | } -------------------------------------------------------------------------------- /textcode/chapter9/adjListGraphTest.cpp: -------------------------------------------------------------------------------- 1 | // 邻接表实现的图类的测试程序 2 | // 插入边:insert 3 | // 查询边:exist 4 | // 移除: remove 5 | // 退出:exit 6 | // 广度优先搜索:bfs 7 | // 深度优先搜索:dfs 8 | // 样例输入: 9 | // 请输入图的顶点个数:4 10 | // 请输入操作: 11 | // insert 0 1 0.1 12 | // insert 1 2 1 13 | // insert 0 3 0.5 14 | // insert 3 2 0.5 15 | // insert 1 0 0.9 16 | // exist 1 2 17 | // exist 2 3 18 | // bfs 19 | // dfs 20 | // remove 1 2 21 | // exist 1 2 22 | // exit 23 | 24 | // 样例输出: 25 | // true 26 | // false 27 | // 当前图的BFS序列为: 28 | // 0 3 1 2 29 | // 当前图的DFS序列为: 30 | // 0 3 2 1 31 | // false 32 | #include 33 | #include 34 | 35 | #include "adjListGraph.h" 36 | using namespace std; 37 | int main() { 38 | cout << "请输入图的顶点个数:"; 39 | int verSize; 40 | cin >> verSize; 41 | int *d = new int[verSize]; 42 | for (int i = 0; i < verSize; i++) d[i] = i; 43 | adjListGraph *adj_list_graph = 44 | new adjListGraph(verSize, d); 45 | cout << "\n请输入操作:" << endl; 46 | int u, v; 47 | double w; 48 | while (true) { 49 | char op[10]; 50 | cin >> op; 51 | if (strcmp(op, "insert") == 0) { 52 | cin >> u >> v >> w; 53 | adj_list_graph->insert(u, v, w); 54 | } else if (strcmp(op, "remove") == 0) { 55 | cin >> u >> v; 56 | adj_list_graph->remove(u, v); 57 | } else if (strcmp(op, "exist") == 0) { 58 | cin >> u >> v; 59 | cout << (adj_list_graph->exist(u, v) ? "true" : "false") 60 | << endl; 61 | } else if (strcmp(op, "bfs") == 0) { 62 | adj_list_graph->bfs(); 63 | } else if (strcmp(op, "dfs") == 0) { 64 | adj_list_graph->dfs(); 65 | } else if (strcmp(op, "exit") == 0) { 66 | break; 67 | } else { 68 | cout << "Invalid Operation!" << endl; 69 | } 70 | } 71 | 72 | return 0; 73 | } -------------------------------------------------------------------------------- /textcode/chapter9/adjMatrixGraph.h: -------------------------------------------------------------------------------- 1 | // 代码清单9-2至9-4 基于邻接矩阵的图类 2 | 3 | #ifndef CHAPTER9_ADJMATRIXGRAPH_H 4 | #define CHAPTER9_ADJMATRIXGRAPH_H 5 | #include "graph.h" 6 | template 7 | class adjMatrixGraph : public graph { 8 | public: 9 | adjMatrixGraph(int vSize, const TypeOfVer d[], const TypeOfEdge noEdgeFlag); 10 | void insert(TypeOfVer x, TypeOfVer y, TypeOfEdge w); 11 | void remove(TypeOfVer x, TypeOfVer y); 12 | bool exist(TypeOfVer x, TypeOfVer y) const; 13 | ~adjMatrixGraph(); 14 | 15 | private: 16 | TypeOfEdge **edge; // 保存邻接矩阵 17 | TypeOfVer *ver; // 保存顶点值 18 | TypeOfEdge noEdge; // 邻接矩阵中没有边的表示值 19 | int find(TypeOfVer v) const { 20 | for (int i = 0; i < this->Vers; ++i) 21 | if (ver[i] == v) return i; 22 | } 23 | }; 24 | 25 | template 26 | adjMatrixGraph::adjMatrixGraph( 27 | int vSize, const TypeOfVer d[], const TypeOfEdge noEdgeFlag) { 28 | int i, j; 29 | this->Vers = vSize; 30 | this->Edges = 0; 31 | noEdge = noEdgeFlag; 32 | // 存储顶点的数组的初始化 33 | ver = new TypeOfVer[vSize]; 34 | for (i = 0; i < vSize; ++i) ver[i] = d[i]; 35 | // 邻接矩阵的初始化 36 | edge = new TypeOfEdge *[vSize]; 37 | for (i = 0; i < vSize; ++i) { 38 | edge[i] = new TypeOfEdge[vSize]; 39 | for (j = 0; j < vSize; ++j) edge[i][j] = noEdge; 40 | edge[i][i] = 0; 41 | } 42 | } 43 | template 44 | adjMatrixGraph::~adjMatrixGraph() { 45 | delete[] ver; 46 | for (int i = 0; i < this->Vers; ++i) 47 | delete[] edge[i]; // 释放邻接矩阵中的每一行 48 | delete[] edge; 49 | } 50 | template 51 | void adjMatrixGraph::insert( 52 | TypeOfVer x, TypeOfVer y, TypeOfEdge w) { 53 | int u = find(x), v = find(y); 54 | edge[u][v] = w; 55 | ++this->Edges; 56 | } 57 | template 58 | void adjMatrixGraph::remove( 59 | TypeOfVer x, TypeOfVer y) { 60 | int u = find(x), v = find(y); 61 | edge[u][v] = noEdge; 62 | --this->Edges; 63 | } 64 | template 65 | bool adjMatrixGraph::exist( 66 | TypeOfVer x, TypeOfVer y) const { 67 | int u = find(x), v = find(y); 68 | if (edge[u][v] == noEdge) 69 | return false; 70 | else 71 | return true; 72 | } 73 | 74 | #endif // CHAPTER9_ADJMATRIXGRAPH_H 75 | -------------------------------------------------------------------------------- /textcode/chapter9/adjMatrixGraphTest.cpp: -------------------------------------------------------------------------------- 1 | // 基于邻接矩阵的图类的测试程序 2 | // 插入边:insert 3 | // 查询边:exist 4 | // 移除: remove 5 | // 退出:exit 6 | // 样例输入: 7 | // 请输入图的顶点个数:4 8 | // 请输入操作: 9 | // insert 0 1 0.1 10 | // insert 1 2 1 11 | // insert 0 3 0.5 12 | // insert 3 2 0.5 13 | // insert 1 0 0.9 14 | // exist 1 2 15 | // exist 2 3 16 | // remove 1 2 17 | // exist 1 2 18 | // exit 19 | 20 | // 样例输出: 21 | // true 22 | // false 23 | // false 24 | #include 25 | #include 26 | 27 | #include "adjMatrixGraph.h" 28 | using namespace std; 29 | int main() { 30 | cout << "请输入图的顶点个数:"; 31 | int verSize; 32 | cin >> verSize; 33 | int *d = new int[verSize]; 34 | for (int i = 0; i < verSize; i++) d[i] = i; 35 | adjMatrixGraph *adj_matrix_graph = 36 | new adjMatrixGraph(verSize, d, -1); 37 | cout << "\n请输入操作:" << endl; 38 | int u, v; 39 | double w; 40 | while (true) { 41 | char op[10]; 42 | cin >> op; 43 | if (strcmp(op, "insert") == 0) { 44 | cin >> u >> v >> w; 45 | adj_matrix_graph->insert(u, v, w); 46 | } else if (strcmp(op, "remove") == 0) { 47 | cin >> u >> v; 48 | adj_matrix_graph->remove(u, v); 49 | } else if (strcmp(op, "exist") == 0) { 50 | cin >> u >> v; 51 | cout << (adj_matrix_graph->exist(u, v) ? "true" : "false") 52 | << endl; 53 | } else if (strcmp(op, "exit") == 0) { 54 | break; 55 | } else { 56 | cout << "Invalid Operation!" << endl; 57 | } 58 | } 59 | 60 | return 0; 61 | } -------------------------------------------------------------------------------- /textcode/chapter9/criticalPathTest.cpp: -------------------------------------------------------------------------------- 1 | // 邻接表实现的关键路径的测试程序 2 | // 样例输入(以图9-14为例): 3 | // 请输入图的顶点个数:7 4 | // 请依次输入有向图的边(-1 -1 -1表示输入完毕): 5 | // 0 1 1 6 | // 1 2 2 7 | // 1 3 3 8 | // 2 4 4 9 | // 3 4 2 10 | // 3 5 3 11 | // 5 6 2 12 | // 4 6 1 13 | // -1 -1 -1 14 | // 样例输出: 15 | // 当前图的关键路径是:(0, 0) (1, 1) (3, 4) (5, 7) (6, 9) 16 | 17 | #include 18 | 19 | #include "adjListGraph.h" 20 | using namespace std; 21 | int main() { 22 | cout << "请输入图的顶点个数:"; 23 | int verSize; 24 | cin >> verSize; 25 | int *d = new int[verSize]; 26 | for (int i = 0; i < verSize; i++) d[i] = i; 27 | adjListGraph *adj_list_graph = 28 | new adjListGraph(verSize, d); 29 | cout << "请依次输入有向图的边(-1 -1 -1表示输入完毕):"; 30 | while (true) { 31 | int u, v; 32 | double w; 33 | cin >> u >> v >> w; 34 | if (u == -1) { 35 | break; 36 | } else { 37 | adj_list_graph->insert(u, v, w); 38 | } 39 | } 40 | 41 | adj_list_graph->criticalPath(); 42 | return 0; 43 | } -------------------------------------------------------------------------------- /textcode/chapter9/graph.h: -------------------------------------------------------------------------------- 1 | // 代码清单9-1 图的抽象类定义 2 | #ifndef CHAPTER9_GRAPH_H 3 | #define CHAPTER9_GRAPH_H 4 | 5 | template 6 | class graph { 7 | public: 8 | virtual void insert(TypeOfVer x, TypeOfVer y, TypeOfEdge w) = 0; 9 | virtual void remove(TypeOfVer x, TypeOfVer y) = 0; 10 | virtual bool exist(TypeOfVer x, TypeOfVer y) const = 0; 11 | virtual ~graph() {}; 12 | int numOfVer() const { return Vers; } 13 | int numOfEdge() const { return Edges; } 14 | 15 | protected: 16 | int Vers, Edges; 17 | }; 18 | #endif // CHAPTER9_GRAPH_H 19 | -------------------------------------------------------------------------------- /textcode/chapter9/topSortTest.cpp: -------------------------------------------------------------------------------- 1 | // 邻接表实现的拓扑排序的测试程序 2 | // 样例输入(以图9-12为例): 3 | // 请输入图的顶点个数:8 4 | // 请依次输入有向图的边(-1 -1表示输入完毕): 5 | // 0 1 6 | // 1 2 7 | // 1 3 8 | // 3 5 9 | // 2 5 10 | // 2 4 11 | // 2 6 12 | // 3 7 13 | // 5 6 14 | // 6 4 15 | // 5 7 16 | // -1 -1 17 | // 样例输出: 18 | // 拓扑排序为: 19 | // 0 1 3 2 5 6 7 4 20 | 21 | #include 22 | 23 | #include "adjListGraph.h" 24 | using namespace std; 25 | int main() { 26 | cout << "请输入图的顶点个数:"; 27 | int verSize; 28 | cin >> verSize; 29 | int *d = new int[verSize]; 30 | for (int i = 0; i < verSize; i++) d[i] = i; 31 | adjListGraph *adj_list_graph = 32 | new adjListGraph(verSize, d); 33 | cout << "请依次输入有向图的边(-1 -1表示输入完毕):"; 34 | while (true) { 35 | int u, v; 36 | 37 | cin >> u >> v; 38 | if (u == -1) { 39 | break; 40 | } else { 41 | adj_list_graph->insert(u, v, 1); 42 | } 43 | } 44 | 45 | adj_list_graph->topSort(); 46 | return 0; 47 | } -------------------------------------------------------------------------------- /trainsys/CommandParser.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMAND_PARSER_H_ 2 | #define COMMAND_PARSER_H_ 3 | 4 | #include 5 | 6 | namespace trainsys { 7 | 8 | int parseCommand(const char * command); 9 | 10 | } 11 | 12 | #endif // COMMAND_PARSER_H_ -------------------------------------------------------------------------------- /trainsys/DataStructure/BinarySearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef BINARY_SEARCH_TABLE_H_ 2 | #define BINARY_SEARCH_TABLE_H_ 3 | 4 | #include "Pair.h" 5 | #include "List.h" 6 | 7 | namespace trainsys { 8 | 9 | template 10 | class BinarySearchTable : public seqList> { 11 | 12 | private: 13 | void quicksort(int l, int r) { 14 | if (l >= r) return; 15 | int i = l, j = r; 16 | Pair pivot = this->data[l]; 17 | while (i < j) { 18 | while (i < j && this->data[j].first >= pivot.first) j--; 19 | this->data[i] = this->data[j]; 20 | while (i < j && this->data[i].first <= pivot.first) i++; 21 | this->data[j] = this->data[i]; 22 | } 23 | this->data[i] = pivot; 24 | quicksort(l, i - 1); 25 | quicksort(i + 1, r); 26 | } 27 | 28 | public: 29 | BinarySearchTable(int initSize = 10): seqList>(initSize) {} 30 | ~BinarySearchTable() = default; 31 | 32 | void insertEntry(const KeyType &key, const ValueType &val) { 33 | this->insert(this->length(), Pair(key, val)); 34 | } 35 | 36 | ValueType find(const KeyType &key) const { 37 | int l = 0, r = this->currentLength - 1; 38 | while (l <= r) { 39 | int mid = (l + r) >> 1; 40 | if (this->data[mid].first == key) return this->data[mid].second; 41 | else if (this->data[mid].first < key) l = mid + 1; 42 | else r = mid - 1; 43 | } 44 | return ValueType(); 45 | } 46 | 47 | void sortEntry() { 48 | quicksort(0, this->currentLength - 1); 49 | } 50 | }; 51 | 52 | } 53 | 54 | #endif // BINARY_SEARCH_TABLE_H_ -------------------------------------------------------------------------------- /trainsys/DataStructure/CachedBPlusTree.h: -------------------------------------------------------------------------------- 1 | #ifndef CACHED_BPLUS_TREE_H_ 2 | #define CACHED_BPLUS_TREE_H_ 3 | 4 | #include "SearchTable.h" 5 | #include "BPlusTree.h" 6 | #include "RedBlackTree.h" 7 | 8 | namespace trainsys { 9 | 10 | template 11 | class CachedBPlusTree { 12 | private: 13 | // 缓存策略:write through 14 | BPlusTree storage; 15 | RedBlackTree cache; 16 | 17 | public: 18 | CachedBPlusTree(const char* filename): storage(filename), cache() {} 19 | ~CachedBPlusTree() = default; 20 | 21 | bool contains(const KeyType &x) { 22 | if (cache.find(x) != nullptr) return true; 23 | return storage.contains(x); 24 | } 25 | 26 | ValueType find(const KeyType &x) { 27 | if (cache.find(x) != nullptr) return cache.find(x)->value; 28 | return storage.findFirst(x); 29 | } 30 | void insert(const KeyType &key, const ValueType &value) { 31 | storage.insert(key, value); 32 | cache.insert(DataType(key, value)); 33 | } 34 | void remove(const KeyType &x) { 35 | storage.removeFirst(x); 36 | cache.remove(x); 37 | } 38 | }; 39 | 40 | } // namespace trainsys 41 | 42 | #endif -------------------------------------------------------------------------------- /trainsys/DataStructure/DisjointSet.h: -------------------------------------------------------------------------------- 1 | #ifndef DISJOINTSET_H_ 2 | #define DISJOINTSET_H_ 3 | 4 | namespace trainsys { 5 | 6 | class DisjointSet { 7 | private: 8 | int size; 9 | int *parent; 10 | 11 | public: 12 | DisjointSet(int n) { 13 | size = n; 14 | parent = new int [size]; 15 | for (int i=0; i parent[root2]) { 23 | parent[root2] += parent[root1]; 24 | parent[root1] = root2; 25 | } 26 | else { 27 | parent[root1] += parent[root2]; 28 | parent[root2] = root1; 29 | } 30 | } 31 | int find(int x) { 32 | if (parent[x] < 0) return x; 33 | return parent[x] = find(parent[x]); 34 | } 35 | }; 36 | 37 | } 38 | 39 | #endif -------------------------------------------------------------------------------- /trainsys/DataStructure/Pair.h: -------------------------------------------------------------------------------- 1 | #ifndef PAIR_H 2 | #define PAIR_H 3 | 4 | namespace trainsys { 5 | 6 | template 7 | struct Pair { 8 | FirstType first; 9 | SecondType second; 10 | 11 | Pair() {} 12 | Pair(const FirstType &first, const SecondType &second) 13 | : first(first), second(second) {} 14 | }; 15 | 16 | template 17 | bool checkPairLess(const Pair &lhs, const Pair &rhs) { 18 | if (lhs.first != rhs.first) { 19 | return lhs.first < rhs.first; 20 | } else { 21 | return lhs.second < rhs.second; 22 | } 23 | } 24 | 25 | template 26 | bool checkPairEqual(const Pair &lhs, const Pair &rhs) { 27 | return lhs.first == rhs.first && lhs.second == rhs.second; 28 | } 29 | 30 | } 31 | 32 | #endif -------------------------------------------------------------------------------- /trainsys/DataStructure/SearchTable.h: -------------------------------------------------------------------------------- 1 | #ifndef SEARCH_TABLE_H_ 2 | #define SEARCH_TABLE_H_ 3 | 4 | namespace trainsys { 5 | 6 | template 7 | struct DataType { 8 | KeyType key; 9 | ValueType value; 10 | DataType(const KeyType &key_, const ValueType &value_): key(key_), value(value_) {} 11 | }; 12 | 13 | template 14 | class DynamicSearchTable { 15 | public: 16 | virtual DataType *find(const KeyType &x) const = 0; 17 | virtual void insert(const DataType &x) = 0; 18 | virtual void remove(const KeyType &x) = 0; 19 | virtual ~DynamicSearchTable() {}; 20 | }; 21 | 22 | template 23 | class StorageSearchTable { 24 | public: 25 | virtual seqList find(const KeyType &key) = 0; 26 | virtual void insert(const KeyType &key, const ValueType &val) = 0; 27 | virtual void remove(const KeyType &key, const ValueType &val) = 0; 28 | virtual ~StorageSearchTable() {}; 29 | }; 30 | 31 | } 32 | 33 | #endif -------------------------------------------------------------------------------- /trainsys/PurchaseInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef PURCHASEINFO_H_ 2 | #define PURCHASEINFO_H_ 3 | 4 | #include "Utils.h" 5 | 6 | namespace trainsys { 7 | 8 | struct PurchaseInfo { 9 | UserID userID; 10 | TrainID trainID; 11 | Date date; 12 | StationID departureStation; 13 | int type; // 1表示购票,-1表示退票 14 | 15 | PurchaseInfo() = default; 16 | PurchaseInfo(const UserID userID, const TrainID &trainID, const Date &date, const StationID &departureStation, int type) { 17 | this->userID = userID; 18 | this->trainID = trainID; 19 | this->date = date; 20 | this->departureStation = departureStation; 21 | this->type = type; 22 | } 23 | ~PurchaseInfo() = default; 24 | bool operator < (const PurchaseInfo &rhs) const { 25 | if (userID != rhs.userID) return userID < rhs.userID; 26 | if (trainID != rhs.trainID) return trainID < rhs.trainID; 27 | if (date != rhs.date) return date < rhs.date; 28 | if (departureStation != rhs.departureStation) return departureStation < rhs.departureStation; 29 | return type < rhs.type; 30 | } 31 | 32 | bool isOrdering() const { return type >= 0; } 33 | bool isRefunding() const { return type < 0; } 34 | }; 35 | 36 | } 37 | 38 | #endif -------------------------------------------------------------------------------- /trainsys/RailwayGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef RAILWAY_GRAPH_H_ 2 | #define RAILWAY_GRAPH_H_ 3 | 4 | #include "Utils.h" 5 | #include "RouteSectionInfo.h" 6 | 7 | #include "DataStructure/Graph.h" 8 | #include "DataStructure/List.h" 9 | #include "DataStructure/DisjointSet.h" 10 | 11 | namespace trainsys { 12 | 13 | class RailwayGraph { 14 | private: 15 | using GraphType = adjListGraph; 16 | 17 | GraphType routeGraph; 18 | 19 | DisjointSet stationSet; 20 | 21 | seqList routeSectionPool; 22 | 23 | public: 24 | 25 | RailwayGraph(); 26 | ~RailwayGraph(); 27 | 28 | void addRoute(StationID departureStationID, StationID arrivalStationID, int duration, int price, TrainID trainID); 29 | 30 | bool checkStationAccessibility(StationID departureStationID, StationID arrivalStationID); 31 | 32 | void displayRoute(StationID departureStationID, StationID arrivalStationID); 33 | 34 | void shortestPath(StationID departureStationID, StationID arrivalStationID, int type); 35 | 36 | private: 37 | void routeDfs(int curIdx, int arrivalIdx, seqList &prevStations, bool *visited); 38 | }; 39 | 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /trainsys/RouteSectionInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "RouteSectionInfo.h" 2 | 3 | namespace trainsys { 4 | 5 | RouteSectionInfo::RouteSectionInfo(TrainID trainID, StationID arrivalStation, int price, int duration) { 6 | this->trainID = trainID; 7 | this->arrivalStation = arrivalStation; 8 | this->price = price; 9 | this->duration = duration; 10 | } 11 | 12 | RouteSectionInfo::RouteSectionInfo(const RouteSectionInfo &rhs) { 13 | this->trainID = rhs.trainID; 14 | this->arrivalStation = rhs.arrivalStation; 15 | this->price = rhs.price; 16 | this->duration = rhs.duration; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /trainsys/RouteSectionInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef ROUTE_SECTION_INFO_H_ 2 | #define ROUTE_SECTION_INFO_H_ 3 | 4 | #include "Utils.h" 5 | 6 | namespace trainsys { 7 | 8 | struct RouteSectionInfo { 9 | TrainID trainID; 10 | StationID arrivalStation; 11 | int price; 12 | int duration; 13 | 14 | RouteSectionInfo() = default; 15 | RouteSectionInfo(TrainID trainID, StationID arrivalStation, int price, int duration); 16 | RouteSectionInfo(const RouteSectionInfo &rhs); 17 | ~RouteSectionInfo() = default; 18 | }; 19 | 20 | } 21 | 22 | #endif // ROUTE_SECTION_INFO -------------------------------------------------------------------------------- /trainsys/SchedulerManager.cpp: -------------------------------------------------------------------------------- 1 | #include "SchedulerManager.h" 2 | 3 | 4 | namespace trainsys { 5 | 6 | SchedulerManager::SchedulerManager(const std::string &filename) 7 | : schedulerInfo(filename) {} 8 | 9 | // 添加一个运行计划 10 | void SchedulerManager::addScheduler(const TrainID &trainID, int seatNum, 11 | int passingStationNumber, const StationID *stations, const int *duration, const int *price) { 12 | TrainScheduler scheduler; 13 | scheduler.setTrainID(trainID); 14 | for (int i = 0; i < passingStationNumber; i++) { 15 | scheduler.addStation(stations[i]); 16 | } 17 | scheduler.setDuration(duration); 18 | scheduler.setPrice(price); 19 | scheduler.setSeatNumber(seatNum); 20 | schedulerInfo.insert(trainID, scheduler); 21 | } 22 | 23 | // 查询某个ID的运行计划是否存在 24 | bool SchedulerManager::existScheduler(const TrainID &trainID) { 25 | return schedulerInfo.contains(trainID); 26 | } 27 | 28 | // 查询某个ID的运行计划 29 | TrainScheduler SchedulerManager::getScheduler(const TrainID &trainID) { 30 | seqList relatedInfo = schedulerInfo.find(trainID); 31 | // 一个trainID理应只对应一个运行计划,但由于这里的B+树是一对多的B+树,所以需要使用seqList 32 | return relatedInfo.visit(0); 33 | } 34 | 35 | // 删除某个ID的运行计划 36 | void SchedulerManager::removeScheduler(const TrainID &trainID) { 37 | seqList relatedInfo = schedulerInfo.find(trainID); 38 | for (int i = 0; i < relatedInfo.length(); ++i) { 39 | schedulerInfo.remove(trainID, relatedInfo.visit(i)); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /trainsys/SchedulerManager.h: -------------------------------------------------------------------------------- 1 | #ifndef SCHEDULER_MANAGER_H 2 | #define SCHEDULER_MANAGER_H 3 | 4 | #include "Utils.h" 5 | #include "TrainScheduler.h" 6 | #include "DataStructure/BPlusTree.h" 7 | 8 | 9 | namespace trainsys { 10 | 11 | class SchedulerManager { 12 | private: 13 | BPlusTree schedulerInfo; 14 | 15 | public: 16 | SchedulerManager(const std::string &filename); 17 | ~SchedulerManager() {} 18 | 19 | void addScheduler(const TrainID &trainID, int seatNum, 20 | int passingStationNumber, const StationID *stations, const int *duration, const int *price); 21 | 22 | bool existScheduler(const TrainID &trainID); 23 | 24 | TrainScheduler getScheduler(const TrainID &trainID); 25 | 26 | void removeScheduler(const TrainID &trainID); 27 | }; 28 | 29 | } 30 | 31 | #endif // SCHEDULER_MANAGER_H -------------------------------------------------------------------------------- /trainsys/StationManager.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "StationManager.h" 4 | 5 | namespace trainsys { 6 | 7 | // 初始化类,从文件中读取车站信息 8 | StationManager::StationManager(const char * filename) { 9 | std::ifstream fin; 10 | fin.open(filename, std::ios::in); 11 | if (!fin.is_open()) { 12 | puts("station info not found"); 13 | return; 14 | } 15 | char stationName[MAX_STATIONNAME_LEN + 1]; 16 | StationID stationID; 17 | puts("loading station info"); 18 | while (fin >> stationName >> stationID) { 19 | idToName.insertEntry(stationID, String(stationName)); 20 | nameToID.insertEntry(String(stationName), stationID); 21 | } 22 | idToName.sortEntry(); 23 | nameToID.sortEntry(); 24 | } 25 | 26 | // 根据车站ID获取车站名称 27 | String StationManager::getStationName(const StationID &stationID) { 28 | return idToName.find(stationID); 29 | } 30 | 31 | // 根据车站名称获取车站ID 32 | StationID StationManager::getStationID(const char * stationName) { 33 | return nameToID.find(String(stationName)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /trainsys/StationManager.h: -------------------------------------------------------------------------------- 1 | #ifndef STATION_MANAGER_H_ 2 | #define STATION_MANAGER_H_ 3 | 4 | #include "Utils.h" 5 | #include "DataStructure/BinarySearchTable.h" 6 | 7 | namespace trainsys { 8 | 9 | class StationManager { 10 | 11 | private: 12 | BinarySearchTable idToName; 13 | BinarySearchTable nameToID; 14 | 15 | public: 16 | StationManager(const char * filename); 17 | ~StationManager() {} 18 | String getStationName(const StationID &stationID); 19 | StationID getStationID(const char * stationName); 20 | }; 21 | 22 | } 23 | 24 | #endif // STATION_MANAGER_H_ -------------------------------------------------------------------------------- /trainsys/TicketInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef TICKETINFO_H_ 2 | #define TICKETINFO_H_ 3 | 4 | #include "Utils.h" 5 | 6 | namespace trainsys { 7 | 8 | struct TicketInfo { 9 | TrainID trainID; 10 | StationID departureStation; 11 | StationID arrivalStation; 12 | int seatNum; 13 | int price; 14 | int duration; 15 | Date date; 16 | 17 | bool operator == (const TicketInfo &rhs) const { 18 | return trainID == rhs.trainID && departureStation == rhs.departureStation && 19 | arrivalStation == rhs.arrivalStation && seatNum == rhs.seatNum && price == rhs.price && 20 | duration == rhs.duration && date == rhs.date; 21 | } 22 | 23 | bool operator != (const TicketInfo &rhs) const { 24 | return !(*this == rhs); 25 | } 26 | 27 | bool operator < (const TicketInfo &rhs) const { 28 | if (trainID != rhs.trainID) { 29 | return trainID < rhs.trainID; 30 | } else if (departureStation != rhs.departureStation) { 31 | return departureStation < rhs.departureStation; 32 | } else if (arrivalStation != rhs.arrivalStation) { 33 | return arrivalStation < rhs.arrivalStation; 34 | } else if (date != rhs.date) { 35 | return date < rhs.date; 36 | } else if (seatNum != rhs.seatNum) { 37 | return seatNum < rhs.seatNum; 38 | } else if (price != rhs.price) { 39 | return price < rhs.price; 40 | } else { 41 | return duration < rhs.duration; 42 | } 43 | } 44 | 45 | friend std::ostream &operator << (std::ostream &os, const TicketInfo &ticketInfo) { 46 | os << "TrainID: " << ticketInfo.trainID << std::endl; 47 | os << "Departure Station: " << ticketInfo.departureStation << std::endl; 48 | os << "Arrival Station: " << ticketInfo.arrivalStation << std::endl; 49 | os << "Seat Number: " << ticketInfo.seatNum << std::endl; 50 | os << "Price: " << ticketInfo.price << std::endl; 51 | os << "Duration: " << ticketInfo.duration << std::endl; 52 | os << "Date: " << ticketInfo.date << std::endl; 53 | return os; 54 | } 55 | }; 56 | 57 | 58 | 59 | } 60 | 61 | #endif -------------------------------------------------------------------------------- /trainsys/TicketManager.cpp: -------------------------------------------------------------------------------- 1 | #include "TicketManager.h" 2 | #include "TrainScheduler.h" 3 | #include "DataStructure/List.h" 4 | 5 | namespace trainsys { 6 | 7 | TicketManager::TicketManager(const std::string &filename) : ticketInfo(filename) {} 8 | 9 | TicketManager::~TicketManager() {} 10 | 11 | int TicketManager::querySeat(const TrainID &trainID, const Date &date, const StationID &stationID) { 12 | seqList relatedInfo = ticketInfo.find(trainID); 13 | for (int i = 0; i < relatedInfo.length(); ++i) { 14 | if (relatedInfo.visit(i).date == date && relatedInfo.visit(i).departureStation == stationID) { 15 | return relatedInfo.visit(i).seatNum; 16 | } 17 | } 18 | return -1; // 出错,没有找到符合条件的车票 19 | } 20 | 21 | int TicketManager::updateSeat(const TrainID &trainID, const Date &date, const StationID &stationID, int delta) { 22 | seqList relatedInfo = ticketInfo.find(trainID); 23 | for (int i = 0; i < relatedInfo.length(); ++i) { 24 | if (relatedInfo.visit(i).date == date && relatedInfo.visit(i).departureStation == stationID) { 25 | TicketInfo updatedInfo = relatedInfo.visit(i); 26 | updatedInfo.seatNum += delta; 27 | ticketInfo.modify(trainID, relatedInfo.visit(i), updatedInfo); 28 | return relatedInfo.visit(i).price; 29 | } 30 | } 31 | return -1; // 出错,没有找到符合条件的车票 32 | } 33 | 34 | void TicketManager::releaseTicket(const TrainScheduler &scheduler, const Date &date) { 35 | int passingStationNum = scheduler.getPassingStationNum(); 36 | for (int i = 0; i + 1 < passingStationNum; ++i) { 37 | TicketInfo newTicket; 38 | newTicket.trainID = scheduler.getTrainID(); 39 | newTicket.departureStation = scheduler.getStation(i); 40 | newTicket.arrivalStation = scheduler.getStation(i + 1); 41 | newTicket.seatNum = scheduler.getSeatNum(); 42 | newTicket.price = scheduler.getPrice(i); 43 | newTicket.duration = scheduler.getDuration(i); 44 | newTicket.date = date; 45 | ticketInfo.insert(newTicket.trainID, newTicket); 46 | } 47 | } 48 | 49 | void TicketManager::expireTicket(const TrainID &trainID, const Date &date) { 50 | seqList relatedInfo = ticketInfo.find(trainID); 51 | for (int i = 0; i < relatedInfo.length(); ++i) { 52 | if (relatedInfo.visit(i).date == date) { 53 | ticketInfo.remove(trainID, relatedInfo.visit(i)); 54 | } 55 | } 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /trainsys/TicketManager.h: -------------------------------------------------------------------------------- 1 | #ifndef TICKET_MANAGER_H_ 2 | #define TICKET_MANAGER_H_ 3 | 4 | #include "Utils.h" 5 | #include "TicketInfo.h" 6 | #include "TrainScheduler.h" 7 | #include "DataStructure/BPlusTree.h" 8 | 9 | namespace trainsys { 10 | 11 | class TicketManager { 12 | private: 13 | // 数据成员:一个从 trainID 到 [一组 TicketInfo] 的 B+ 树索引 14 | BPlusTree ticketInfo; 15 | public: 16 | TicketManager(const std::string &filename); 17 | ~TicketManager(); 18 | // 功能:给定车次号、乘车日期、始发站(由于分段购票原则,始发站确定即终点站确定),查询余票数量 19 | // 由于 B+ 树索引只能从 TrainID 到 该车次号 所有日期、所有区间段的余票信息 20 | // 在拿到 TicketInfo 数组后,需要暴力枚举日期与始发站,才能查到票数 21 | int querySeat(const TrainID &trainID, const Date &date, const StationID &stationID); 22 | 23 | // 功能:给定车次号、乘车日期、始发站、购票或退票,修改余票数量,索引方式同上 24 | // 参数:delta == 1,购票;delta == -1,退票 25 | // 返回:票价 26 | int updateSeat(const TrainID &trainID, const Date &date, const StationID &stationID, int delta); 27 | 28 | // 功能:给定列车运行计划,开售列车运行计划分段、逐日的车票,导入车票管理系统 29 | // 在此处new TicketInfo的空间,构建 B+ 树等,TicketInfo 从 TrainScheduler 拷信息 30 | void releaseTicket(const TrainScheduler &scheduler, const Date &date); 31 | 32 | // 功能:给定车次与日期,停售该列车运行计划分段、逐日的车票 33 | void expireTicket(const TrainID &trainID, const Date &date); 34 | 35 | 36 | }; 37 | 38 | 39 | } 40 | 41 | #endif // TICKET_MANAGER_H_ -------------------------------------------------------------------------------- /trainsys/TrainScheduler.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAIN_SCHEDULER_H_ 2 | #define TRAIN_SCHEDULER_H_ 3 | 4 | #include "Utils.h" 5 | #include "DataStructure/List.h" 6 | 7 | namespace trainsys { 8 | 9 | class TrainScheduler { 10 | private: 11 | TrainID trainID; // 车次号 12 | int seatNum; // 额定乘员 13 | int passingStationNum; // 途径站点数 14 | StationID stations[MAX_PASSING_STATION_NUMBER]; // 途径站点的线性表 15 | int duration[MAX_PASSING_STATION_NUMBER]; // 每一段历时的线性表 16 | int price[MAX_PASSING_STATION_NUMBER]; // 每一段票价的线性表 17 | 18 | public: 19 | TrainScheduler(); 20 | ~TrainScheduler(); 21 | 22 | void addStation(const StationID &station); 23 | void insertStation(int i, const StationID &station); 24 | void removeStation(int i); 25 | int findStation(const StationID &station); 26 | void traverseStation(); 27 | 28 | void setTrainID(const TrainID &id); 29 | void setPrice(const int price[]); 30 | void setDuration(const int duration[]); 31 | void setSeatNumber(int seatNum); 32 | 33 | TrainID getTrainID() const; 34 | int getSeatNum() const; 35 | int getPassingStationNum() const; 36 | 37 | // 功能:因为要返回指针,所以参数作为返回了 38 | void getStations(StationID *stations) const; 39 | void getDuration(int* duration) const; 40 | void getPrice(int* price) const; 41 | 42 | StationID getStation(int i) const; 43 | int getDuration(int i) const; 44 | int getPrice(int i) const; 45 | 46 | bool operator == (const TrainScheduler &rhs) const; 47 | 48 | bool operator != (const TrainScheduler &rhs) const; 49 | 50 | bool operator < (const TrainScheduler &rhs) const; 51 | 52 | friend std::ostream &operator << (std::ostream &os, const TrainScheduler &trainScheduler); 53 | 54 | }; 55 | 56 | } 57 | 58 | #endif -------------------------------------------------------------------------------- /trainsys/TrainSystem.h: -------------------------------------------------------------------------------- 1 | #ifndef TRAIN_SYSTEM_H_ 2 | #define TRAIN_SYSTEM_H_ 3 | 4 | #include "Utils.h" 5 | #include "UserManager.h" 6 | #include "TripManager.h" 7 | #include "TicketManager.h" 8 | #include "TrainScheduler.h" 9 | #include "RailwayGraph.h" 10 | #include "SchedulerManager.h" 11 | #include "StationManager.h" 12 | #include "WaitingList.h" 13 | #include "DataStructure/RedBlackTree.h" 14 | 15 | namespace trainsys { 16 | 17 | /* 18 | * part1 运行计划管理子系统(需要系统管理员权限) 19 | */ 20 | 21 | void addTrainScheduler(const TrainID &trainID, int seatNum, int passingStationNumber, 22 | const StationID *stations, const int *duration, const int *price); 23 | 24 | void queryTrainScheduler(const TrainID &trainID); 25 | 26 | /* 27 | * part2 票务管理子系统(需要系统管理员权限) 28 | */ 29 | 30 | void releaseTicket(const TrainScheduler &scheduler, const Date &date); 31 | 32 | void expireTicket(const TrainID &trainID, const Date &date); 33 | 34 | /* 35 | * part3 车票交易子系统 36 | */ 37 | 38 | int queryRemainingTicket(const TrainID &trainID, const Date &date, const StationID &departureStation); 39 | 40 | void queryMyTicket(); 41 | 42 | void orderTicket(const TrainID &trainID, const Date &date, const StationID &departureStation); 43 | 44 | void refundTicket(const TrainID &trainID, const Date &date, const StationID &departureStation); 45 | 46 | /* 47 | * part4 路线查询子系统 48 | */ 49 | 50 | void findAllRoute(const StationID departureID, const StationID arrivalID); 51 | 52 | void findBestRoute(const StationID departureID, const StationID arrivalID, int preference); 53 | 54 | /* 55 | * part5 用户管理子系统 56 | */ 57 | 58 | void login(const UserID userID, const char* password); 59 | 60 | void logout(); 61 | 62 | void addUser(const UserID userID, const char *username, const char* password); 63 | 64 | void findUserInfoByUserID(const UserID userID); 65 | 66 | void modifyUserPassword(const UserID userID, const char* password); 67 | 68 | void modifyUserPrivilege(const UserID userID, int newPrivilege); 69 | 70 | } 71 | 72 | #endif -------------------------------------------------------------------------------- /trainsys/TripInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIPINFO_H_ 2 | #define TRIPINFO_H_ 3 | 4 | #include "Utils.h" 5 | #include "StationManager.h" 6 | 7 | namespace trainsys { 8 | 9 | extern StationManager *stationManager; 10 | 11 | struct TripInfo { 12 | TrainID trainID; 13 | StationID departureStation; 14 | StationID arrivalStation; 15 | int ticketNumber; 16 | int duration; 17 | int price; 18 | Date date; 19 | 20 | TripInfo() = default; 21 | TripInfo(const TrainID &trainID, const StationID &departureStation, 22 | const StationID &arrivalStation, int ticketNumber, int duration, int price, const Date &date) { 23 | this->trainID = trainID; 24 | this->departureStation = departureStation; 25 | this->arrivalStation = arrivalStation; 26 | this->ticketNumber = ticketNumber; 27 | this->duration = duration; 28 | this->price = price; 29 | this->date = date; 30 | } 31 | 32 | bool operator == (const TripInfo &rhs) const { 33 | return trainID == rhs.trainID && departureStation == rhs.departureStation && 34 | arrivalStation == rhs.arrivalStation && ticketNumber == rhs.ticketNumber && 35 | duration == rhs.duration && price == rhs.price && date == rhs.date; 36 | } 37 | 38 | bool operator != (const TripInfo &rhs) const { 39 | return !(*this == rhs); 40 | } 41 | 42 | bool operator < (const TripInfo &rhs) const { 43 | if (trainID != rhs.trainID) { 44 | return trainID < rhs.trainID; 45 | } else if (departureStation != rhs.departureStation) { 46 | return departureStation < rhs.departureStation; 47 | } else if (arrivalStation != rhs.arrivalStation) { 48 | return arrivalStation < rhs.arrivalStation; 49 | } else if (date != rhs.date) { 50 | return date < rhs.date; 51 | } else if (ticketNumber != rhs.ticketNumber) { 52 | return ticketNumber < rhs.ticketNumber; 53 | } else if (price != rhs.price) { 54 | return price < rhs.price; 55 | } else { 56 | return duration < rhs.duration; 57 | } 58 | } 59 | 60 | friend std::ostream &operator << (std::ostream &os, const TripInfo &tripInfo) { 61 | os << "TripInfo:" << std::endl; 62 | os << "trainID: " << tripInfo.trainID << std::endl; 63 | os << "departureStation: " << stationManager->getStationName(tripInfo.departureStation) << std::endl; 64 | os << "arrivalStation: " << stationManager->getStationName(tripInfo.arrivalStation) << std::endl; 65 | os << "duration: " << tripInfo.duration << std::endl; 66 | os << "price: " << tripInfo.price << std::endl; 67 | os << "date: " << tripInfo.date << std::endl; 68 | return os; 69 | } 70 | 71 | }; 72 | 73 | 74 | } 75 | 76 | #endif -------------------------------------------------------------------------------- /trainsys/TripManager.cpp: -------------------------------------------------------------------------------- 1 | #include "TripManager.h" 2 | #include "DataStructure/List.h" 3 | 4 | namespace trainsys { 5 | 6 | TripManager::TripManager(const std::string &filename) 7 | : tripInfo(filename) {} 8 | 9 | void TripManager::addTrip(const UserID &userID, const TripInfo &trip) { 10 | tripInfo.insert(userID, trip); 11 | } 12 | 13 | seqList TripManager::queryTrip(const UserID &userID) { 14 | return tripInfo.find(userID); 15 | } 16 | 17 | void TripManager::removeTrip(const UserID &userID, const TripInfo &trip) { 18 | tripInfo.remove(userID, trip); 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /trainsys/TripManager.h: -------------------------------------------------------------------------------- 1 | #ifndef TRIP_MANAGER_H_ 2 | #define TRIP_MANAGER_H_ 3 | 4 | #include "Utils.h" 5 | #include "DataStructure/BPlusTree.h" 6 | #include "TripInfo.h" 7 | 8 | namespace trainsys { 9 | 10 | class TripManager { 11 | private: 12 | // 数据成员:一个从 UserID 到 [一组 TripInfo],展现此用户购买了什么票 13 | BPlusTree tripInfo; 14 | public: 15 | TripManager(const std::string &filename); 16 | ~TripManager() {} 17 | void addTrip(const UserID &userID, const TripInfo &trip); 18 | seqList queryTrip(const UserID &userID); // 返回一个用户的多个 TripInfo,输出到 stdout 19 | void removeTrip(const UserID &userID, const TripInfo &trip); 20 | }; 21 | 22 | } // namespace trainsys 23 | 24 | #endif -------------------------------------------------------------------------------- /trainsys/UserInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "UserInfo.h" 2 | 3 | namespace trainsys { 4 | 5 | UserInfo::UserInfo(UserID userID, const char* username, const char *password, int privilege) { 6 | this->userID = userID; 7 | this->privilege = privilege; 8 | int len = strlen(username); 9 | if (len > MAX_USERNAME_LEN) len = MAX_USERNAME_LEN; 10 | memcpy(this->username, username, len); 11 | this->username[len] = '\0'; 12 | len = strlen(password); 13 | if (len > MAX_PASSWORD_LEN) len = MAX_PASSWORD_LEN; 14 | memcpy(this->password, password, len); 15 | this->password[len] = '\0'; 16 | } 17 | 18 | UserInfo::UserInfo(const UserInfo &rhs) { 19 | this->userID = rhs.userID; 20 | this->privilege = rhs.privilege; 21 | memcpy(this->username, rhs.username, MAX_USERNAME_LEN + 1); 22 | memcpy(this->password, rhs.password, MAX_PASSWORD_LEN + 1); 23 | } 24 | 25 | UserInfo& UserInfo::operator = (const UserInfo &rhs) { 26 | if (this != &rhs) { 27 | this->userID = rhs.userID; 28 | this->privilege = rhs.privilege; 29 | memcpy(this->username, rhs.username, MAX_USERNAME_LEN + 1); 30 | memcpy(this->password, rhs.password, MAX_PASSWORD_LEN + 1); 31 | } 32 | return *this; 33 | } 34 | 35 | bool UserInfo::operator == (const UserInfo &rhs) const { 36 | return userID == rhs.userID; 37 | } 38 | 39 | bool UserInfo::operator != (const UserInfo &rhs) const { 40 | return userID != rhs.userID; 41 | } 42 | 43 | bool UserInfo::operator < (const UserInfo &rhs) const { 44 | return userID < rhs.userID; 45 | } 46 | 47 | } // namespace trainsys 48 | -------------------------------------------------------------------------------- /trainsys/UserInfo.h: -------------------------------------------------------------------------------- 1 | #ifndef USERINFO_H_ 2 | #define USERINFO_H_ 3 | 4 | #include "Utils.h" 5 | 6 | namespace trainsys { 7 | 8 | struct UserInfo { 9 | UserID userID; 10 | char username[MAX_USERNAME_LEN + 1]; 11 | char password[MAX_PASSWORD_LEN + 1]; 12 | int privilege; // 数字越大,排队购票优先级越高 13 | 14 | UserInfo() = default; 15 | UserInfo(UserID userID, const char* username, const char* password, int privilege); 16 | UserInfo(const UserInfo &rhs); 17 | ~UserInfo() = default; 18 | 19 | UserInfo& operator = (const UserInfo &rhs); 20 | bool operator == (const UserInfo &rhs) const; 21 | bool operator != (const UserInfo &rhs) const; 22 | bool operator < (const UserInfo &rhs) const; 23 | }; 24 | 25 | } 26 | 27 | #endif -------------------------------------------------------------------------------- /trainsys/UserManager.cpp: -------------------------------------------------------------------------------- 1 | #include "UserManager.h" 2 | 3 | namespace trainsys { 4 | 5 | UserManager::UserManager(const char* filename): userInfoTable(filename) {} 6 | 7 | void UserManager::insertUser(const UserID &userID, const char *username, const char* password, int privilege) { 8 | userInfoTable.insert(userID, UserInfo(userID, username, password, privilege)); 9 | } 10 | 11 | bool UserManager::existUser(const UserID &userID) { 12 | return userInfoTable.contains(userID); 13 | } 14 | 15 | UserInfo UserManager::findUser(const UserID &userID) { 16 | return userInfoTable.find(userID); 17 | } 18 | 19 | void UserManager::removeUser(const UserID &userID) { 20 | userInfoTable.remove(userID); 21 | } 22 | 23 | void UserManager::modifyUserPrivilege(const UserID &userID, int newPrevilege) { 24 | UserInfo userInfo = userInfoTable.find(userID); 25 | userInfo.privilege = newPrevilege; 26 | 27 | userInfoTable.remove(userID); 28 | userInfoTable.insert(userID, userInfo); 29 | } 30 | 31 | void UserManager::modifyUserPassword(const UserID &userID, const char* newPassword) { 32 | UserInfo userInfo = userInfoTable.find(userID); 33 | int len = strlen(newPassword); 34 | if (len > MAX_PASSWORD_LEN) len = MAX_PASSWORD_LEN; 35 | memcpy(userInfo.password, newPassword, len); 36 | userInfo.password[len] = '\0'; 37 | 38 | userInfoTable.remove(userID); 39 | userInfoTable.insert(userID, userInfo); 40 | } 41 | 42 | 43 | } // namespace trainsys -------------------------------------------------------------------------------- /trainsys/UserManager.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_MANAGER_H_ 2 | #define USER_MANAGER_H_ 3 | 4 | #include "Utils.h" 5 | #include "UserInfo.h" 6 | #include "DataStructure/List.h" 7 | #include "DataStructure/BPlusTree.h" 8 | #include "DataStructure/CachedBPlusTree.h" 9 | 10 | namespace trainsys { 11 | 12 | class UserManager { 13 | private: 14 | // 可以通过给红黑树节点添加双链表的方式 实现 lru 的缓存功能 15 | // 在此将功能简化,缓存长度为无限长,红黑树一天一清 16 | CachedBPlusTree userInfoTable; 17 | public: 18 | UserManager(const char* filename); 19 | ~UserManager() = default; 20 | 21 | void insertUser(const UserID &userID, const char* username, const char* password, int privilege); 22 | bool existUser(const UserID &userID); 23 | UserInfo findUser(const UserID &userID); 24 | void removeUser(const UserID &userID); 25 | void modifyUserPrivilege(const UserID &userID, int newPrivilege); 26 | void modifyUserPassword(const UserID &userID, const char* newPassword); 27 | }; 28 | 29 | } 30 | 31 | #endif -------------------------------------------------------------------------------- /trainsys/Utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H_ 2 | #define UTILS_H_ 3 | 4 | #include 5 | #include "DateTime.h" 6 | #include "DataStructure/List.h" 7 | 8 | namespace trainsys { 9 | 10 | const int MAX_TRAINID_LEN = 20; 11 | const int MAX_USERNAME_LEN = 20; 12 | const int MAX_PASSWORD_LEN = 30; 13 | 14 | const int MAX_PASSING_STATION_NUMBER = 30; 15 | 16 | const int MAX_STATIONID = 1000; 17 | const int MAX_STATIONNAME_LEN = 30; 18 | 19 | const int ADMIN_PRIVILEGE = 10; 20 | 21 | const int BUSY_STATE_TRESHOLD = 1; 22 | 23 | struct String; 24 | 25 | using UserID = long long; 26 | using StationID = int; 27 | using TrainID = String; 28 | using StationName = String; 29 | 30 | const int MAX_STRING_LENGTH = 50; 31 | 32 | // 需要使用一个定长的字符串作为索引,而不是使用std::string 33 | struct String { 34 | char index[MAX_STRING_LENGTH]; 35 | 36 | String() = default; 37 | 38 | explicit String(const char * str) { 39 | strcpy(index, str); 40 | } 41 | 42 | String(const String &other) { 43 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 44 | index[i] = other.index[i]; 45 | } 46 | } 47 | 48 | String &operator=(const String &other) { 49 | for (int i = 0; i < MAX_STRING_LENGTH; i++) { 50 | index[i] = other.index[i]; 51 | } 52 | return *this; 53 | } 54 | 55 | friend bool operator>(const String &lhs, const String &rhs) { 56 | return std::string(lhs.index) > std::string(rhs.index); 57 | } 58 | 59 | friend bool operator>=(const String &lhs, const String &rhs) { 60 | return std::string(lhs.index) >= std::string(rhs.index); 61 | } 62 | 63 | friend bool operator<(const String &lhs, const String &rhs) { 64 | return std::string(lhs.index) < std::string(rhs.index); 65 | } 66 | 67 | friend bool operator<=(const String &lhs, const String &rhs) { 68 | return std::string(lhs.index) <= std::string(rhs.index); 69 | } 70 | 71 | friend bool operator==(const String &lhs, const String &rhs) { 72 | return std::string(lhs.index) == std::string(rhs.index); 73 | } 74 | 75 | friend bool operator!=(const String &lhs, const String &rhs) { 76 | return std::string(lhs.index) != std::string(rhs.index); 77 | } 78 | 79 | friend std::ostream &operator<<(std::ostream &os, const String &obj) { 80 | os << obj.index; 81 | return os; 82 | } 83 | }; 84 | 85 | template 86 | int binarySearch(const list &data, const elemType &x) { 87 | int low = 0, high = data.length() - 1, mid; 88 | while (low <= high) { //查找区间存在 89 | mid = (low + high) / 2; //计算中间位置 90 | if (x == data.visit(mid)) return mid; //查找完成 91 | else if (x < data.visit(mid)) high = mid - 1; 92 | else low = mid + 1; 93 | } 94 | return 0; 95 | } 96 | 97 | } 98 | 99 | #endif -------------------------------------------------------------------------------- /trainsys/WaitingList.cpp: -------------------------------------------------------------------------------- 1 | #include "WaitingList.h" 2 | 3 | namespace trainsys { 4 | 5 | void WaitingList::addToWaitingList(const PurchaseInfo &purchaseInfo) { 6 | purchaseQueue.enQueue(purchaseInfo); 7 | listSize++; 8 | } 9 | 10 | void WaitingList::removeHeadFromWaitingList() { 11 | if (!purchaseQueue.isEmpty()) { 12 | purchaseQueue.deQueue(); 13 | listSize--; 14 | } 15 | } 16 | 17 | const PurchaseInfo WaitingList::getFrontPurchaseInfo() const { 18 | return purchaseQueue.getHead(); 19 | } 20 | 21 | bool WaitingList::isEmpty() const { 22 | return purchaseQueue.isEmpty(); 23 | } 24 | 25 | bool WaitingList::isBusy() const { 26 | return listSize >= BUSY_STATE_TRESHOLD; 27 | } 28 | 29 | void PrioritizedWaitingList::addToWaitingList(const PurchaseInfo &purchaseInfo) { 30 | purchaseQueue.enQueue(purchaseInfo); 31 | listSize++; 32 | } 33 | 34 | void PrioritizedWaitingList::removeHeadFromWaitingList() { 35 | if (!purchaseQueue.isEmpty()) { 36 | purchaseQueue.deQueue(); 37 | listSize--; 38 | } 39 | } 40 | 41 | const PurchaseInfo PrioritizedWaitingList::getFrontPurchaseInfo() const { 42 | return purchaseQueue.getHead(); 43 | } 44 | 45 | bool PrioritizedWaitingList::isEmpty() const { 46 | return purchaseQueue.isEmpty(); 47 | } 48 | 49 | bool PrioritizedWaitingList::isBusy() const { 50 | return listSize >= BUSY_STATE_TRESHOLD; 51 | } 52 | 53 | } // namespace trainsys -------------------------------------------------------------------------------- /trainsys/WaitingList.h: -------------------------------------------------------------------------------- 1 | #ifndef WAITING_LIST_H_ 2 | #define WAITING_LIST_H_ 3 | 4 | #include "Utils.h" 5 | #include "PurchaseInfo.h" 6 | #include "DataStructure/Queue.h" 7 | 8 | namespace trainsys { 9 | 10 | class WaitingList { 11 | private: 12 | linkQueue purchaseQueue; 13 | int listSize; 14 | public: 15 | WaitingList(): purchaseQueue(), listSize(0) {} 16 | // PurchaseInfo 是在主逻辑里完成组装的 17 | void addToWaitingList(const PurchaseInfo &purchaseInfo); 18 | void removeHeadFromWaitingList(); 19 | const PurchaseInfo getFrontPurchaseInfo() const; 20 | bool isEmpty() const; 21 | bool isBusy() const; 22 | }; 23 | 24 | class PrioritizedWaitingList { 25 | private: 26 | priorityQueue purchaseQueue; 27 | int listSize; 28 | public: 29 | PrioritizedWaitingList(): purchaseQueue(), listSize(0) {} 30 | void addToWaitingList(const PurchaseInfo &purchaseInfo); 31 | void removeHeadFromWaitingList(); 32 | const PurchaseInfo getFrontPurchaseInfo() const; 33 | bool isEmpty() const; 34 | bool isBusy() const; 35 | }; 36 | 37 | } // namespace trainsys 38 | 39 | #endif // WAITING_LIST_H_ -------------------------------------------------------------------------------- /trainsys/main.cpp: -------------------------------------------------------------------------------- 1 | #include "TrainSystem.h" 2 | #include "CommandParser.h" 3 | #include "Utils.h" 4 | 5 | namespace trainsys { 6 | 7 | extern UserInfo currentUser; 8 | extern UserManager *userManager; 9 | extern RailwayGraph *railwayGraph; 10 | extern SchedulerManager *schedulerManager; 11 | extern TicketManager *ticketManager; 12 | extern PrioritizedWaitingList *waitingList; 13 | extern TripManager *tripManager; 14 | extern StationManager *stationManager; 15 | 16 | // 初始化系统 17 | void init() { 18 | stationManager = new StationManager("station.txt"); 19 | userManager = new UserManager("user.dat"); 20 | schedulerManager = new SchedulerManager("scheduler.dat"); 21 | ticketManager = new TicketManager("ticket.dat"); 22 | waitingList = new PrioritizedWaitingList(); 23 | tripManager = new TripManager("trip.dat"); 24 | railwayGraph = new RailwayGraph(); 25 | 26 | // 开启系统时,自动登录管理员。默认管理员账号ID为0 27 | puts("admin login"); 28 | if (userManager->existUser(0)) { 29 | currentUser = userManager->findUser(0); 30 | } else { 31 | currentUser = UserInfo(0, "admin", "admin", 100); 32 | userManager->insertUser(0, "admin", "admin", 100); 33 | } 34 | } 35 | 36 | } 37 | 38 | int main() { 39 | trainsys::init(); 40 | char command[30000]; 41 | // 读入指令 42 | while (std::cin.getline(command, 30000)) { 43 | printf("get command: %s\n", command); 44 | if (trainsys::parseCommand(command) == 1) { // 读入到exit指令 45 | break; 46 | } 47 | } 48 | delete trainsys::userManager; 49 | delete trainsys::railwayGraph; 50 | delete trainsys::schedulerManager; 51 | delete trainsys::ticketManager; 52 | delete trainsys::waitingList; 53 | delete trainsys::tripManager; 54 | return 0; 55 | } -------------------------------------------------------------------------------- /习题答案.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boyu-ai/Hands-on-DS/d96f6f67c4efdb772047a86789f01849fab2a53b/习题答案.docx --------------------------------------------------------------------------------