├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── 图 ├── BFS_AdjMatrix.cpp ├── BFS_Min_Distance.cpp ├── DFS_Matrix.cpp └── DijkstraAlgorithm.cpp ├── 字符串处理 └── 十进制转二进制.cpp ├── 常用算法数据结构 └── 堆.cpp ├── 排序 ├── 冒泡排序.cpp ├── 双向冒泡排序.cpp ├── 堆排序.cpp ├── 希尔排序.cpp ├── 归并2.cpp ├── 归并排序.cpp ├── 快速排序-非递归版.cpp ├── 快速排序.cpp ├── 所有奇数移动到偶数前的算法.cpp ├── 插入排序.cpp ├── 第k小的数字.cpp └── 选择排序.cpp ├── 数据结构公式总结.md ├── 查找 ├── KMP.cpp ├── 折半查找.cpp └── 折半查找递归版.cpp ├── 树 ├── TreeTraverse.cpp ├── 判断是否为平衡二叉树的算法.cpp ├── 平衡二叉树.cpp ├── 求二叉树的高度.cpp └── 给定高度求平衡二叉树结点个数.cpp ├── 线性表 └── 课后算法习题.c ├── 经典算法练习题 ├── L01二维数组中的查找.cpp ├── L02替换空格.cpp ├── L03从尾到头打印链表.cpp ├── L04重建二叉树.cpp ├── L05两个栈实现一个队列.cpp ├── L06旋转数组中最小的元素.cpp ├── L07斐波那契数列.cpp ├── L08跳台阶.cpp ├── L09变态跳台阶.cpp ├── L10矩形覆盖.cpp ├── L11二进制中1的个数.cpp ├── L12数值的整数次方.cpp ├── L13调整数组顺序使得奇数在偶数前面.cpp ├── L14链表中倒数第k个结点.cpp ├── L15反转链表.cpp ├── L16合并两个排序的链表.cpp ├── L17树的子结构.cpp ├── L18二叉树的镜像.cpp ├── L19顺时针打印矩阵.cpp ├── L20包含min函数的栈.cpp ├── L21栈的压入弹出序列.cpp ├── L22从上往下打印二叉树.cpp ├── L23二叉搜索树的后续遍历序列.cpp ├── L24二叉树中和为某一值的路径.cpp ├── L25复杂链表的复制.cpp ├── L26二叉搜索树与双向链表.cpp ├── L27字符串的排列.cpp ├── L28数组中出现次数超过一半的数字.cpp ├── L29最小的K个数.cpp ├── L30连续数组的最大和.cpp ├── L31从1到n中1出现的次数.cpp ├── L32把数组排列成最小的数.cpp ├── L33丑数.cpp ├── L34第一个只出现一次的字符.cpp ├── L35数组中的逆序对.cpp ├── 两个链表的第一个公共结点.cpp ├── 二叉搜索树的第k个结点.cpp ├── 二叉树的下一个结点.cpp ├── 二叉树的深度.cpp ├── 删除链表中重复的结点.cpp ├── 判断是否是平衡二叉树.cpp ├── 和为S的两个数字.cpp ├── 和为S的连续正数序列.cpp ├── 字符流中第一个不重复的字符.cpp ├── 孩子们的游戏.cpp ├── 对称的二叉树.cpp ├── 左旋转字符串.cpp ├── 巧妙两数相加.cpp ├── 巧妙计算1加到n.cpp ├── 序列化二叉树.cpp ├── 按层打印二叉树.cpp ├── 按照之字型打印二叉树.cpp ├── 数据流中的中位数.cpp ├── 数组中只出现一次的数字.cpp ├── 机器人的运动范围.cpp ├── 构建数组乘积.cpp ├── 矩阵中的路径.cpp ├── 统计一个数字在排序数组中出现的次数.cpp ├── 翻转单词顺序序列.cpp ├── 链表中环的入口结点.cpp └── 默写-快速排序.cpp └── 考研算法真题 ├── 2010算法题.cpp ├── 2011算法题.cpp ├── 2013算法题.cpp ├── 2014算法题.cpp └── 2018算法题.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build-debug/ 3 | CMakeLists.txt -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(one) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | 6 | add_executable(one 字符串处理/十进制转二进制.cpp 常用算法数据结构/堆.cpp) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 数据结构-Data Structure 2 | 3 | 2020-6-18更新 4 | 5 | ## **🎺写在前面的话** 6 | 7 | 0. **计算机考研的朋友们加油!** 8 | 1. **欢迎Star分享一波, 祝你们都可以上岸!** ✨ 9 | 2. 王道考研数据结构,书籍部分代码及算法题C++语言实现(但大部分使用C的库函数) 10 | 3. 为了方便起见代码编写以**c语言风格为主**,不涉及面向对象程序设计,并仅仅使用了一些简单的c++stl的简单数据结构,**对基础薄弱者友好**👬 11 | 4. 此仓库目的:学习和理解算法题,辅助考研,时间有限,故代码命名及注释未按代码规范,请见谅 12 | 5. 由于此仓库并不是工程文件夹,故代码中可能有一些小的错误,欢迎pull request指正,dalao勿喷 13 | 6. readme中可能部分公式无法解析 推荐使用**Typora** 14 | 7. 欢迎大家一起敲代码! 15 | 8. **有问题可以提出ISSUE 看到了就会回复** 16 | 17 | ## 使用指南 18 | 19 | 本仓库中的文件几乎每个`.cpp`均有main函数,每个文件可以单独运行 20 | 21 | ### 使用方法1(推荐) 22 | 23 | 在线阅读,学习代码思想,手写 24 | 25 | ### 使用方法2(推荐) 26 | 27 | 1. 下载 or clone代码 28 | 2. 挑选需要的代码 29 | 3. 复制出来,在IDE(**推荐Clion、Dev**)运行 30 | 31 | ### 使用方法3 32 | 33 | 导入Clion工程,手动更改Makefile 34 | 35 | ### 使用方法4 36 | 37 | 大佬qing自行研究😊 38 | 39 | ## 线性表 40 | 41 | **本章是考试重点容易出算法大题** 42 | 43 | - 2019 9 14 课后算法题更新到7道,对于2020王道数据结构第18页 44 | 45 | - 链表的直接插入排序 2019 9 18 46 | 47 | ## 栈 48 | 49 | - 待更新 50 | 51 | ## 队列 52 | 53 | - 括号匹配(搞定) 54 | - 用栈实现递归式的非递归代码P90 55 | 56 | ## 树 57 | 58 | **🌲的考察在于各种树的特点,以及树的遍历算法** 59 | 60 | - 先序 61 | - 递归 62 | - 非递归 63 | - 后序 64 | - 递归 65 | - 非递归 66 | - 中序 67 | - 递归 68 | - 非递归 69 | - 层序 70 | - 线索化 71 | - 求二叉树的高度 72 | - 递归 73 | - 非递归 74 | 75 | ### 平衡二叉树 76 | 77 | - 判断一棵树是否为平衡二叉树 (2019-9-6) 78 | 79 | ## 图 80 | 81 | ### 遍历问题 82 | 83 | - 2019 7 28 新增DFS 84 | - 2019 7 31 新增BFS 85 | 86 | ### 最小生成树问题 87 | 88 | - Prim 89 | - kruskal 90 | 91 | ### 最短路径问题 92 | 93 | - Dijkstra 94 | - Floyd-Warshall 95 | 96 | ### 拓扑排序 97 | 98 | 99 | 100 | ## 查找 101 | 102 | ### KMP算法 103 | 104 | - get_next 105 | - next_val 106 | - kmp 107 | 108 | 109 | 110 | ## 排序算法 111 | 112 | ### 快速排序 113 | 114 | - 递归版本已经完成 115 | - 非递归版本待更新 116 | 117 | ### 堆排序 118 | 119 | - 堆排序 120 | - 堆的建立 121 | - 从i/2开始—>1 122 | - 堆的删除 123 | - 堆的删除仅针对于根结点,每次删除时将根结点与最后一个元素交换然后自顶向下调整堆 124 | - 堆的插入 125 | - 插入时查找堆的末尾(即数组最后)然后自上而下的调整堆 126 | - 建立堆的时间复杂度$O(n)$ 127 | - 调整堆的时间复杂度 $O(log_2n)$ 128 | - 判断一个堆是大顶堆的算法 129 | 130 | ### 归并排序 131 | 132 | - 已经更新 133 | 134 | ### 希尔排序 135 | 136 | - 2019 9 18更新完成 137 | 138 | 139 | 140 | ### 课后习题 141 | 142 | - 奇偶顺序排序 ✅ 143 | - 找到第k小的数 ✅ 144 | 145 | 上面两个算法有异曲同工之处 注意结合快排理解 146 | 147 | 148 | 149 | - 双向冒泡排序 ✅ 150 | 151 | 152 | 153 | ## 真题 154 | 155 | ### 2018 156 | 157 | 个人题解,思路和答案一致,由于我的实现可以包含的数据范围更广,故空间复杂度略有不同,本人算法掌握不是很好,如有错误,欢迎指正。 158 | 159 | - 2019 10 12 日更新完毕 160 | 161 | ### 2013 162 | 163 | 个人题解,正常人比较容易想到的算法,思路和2018差不多 164 | 165 | 空间复杂度未达到最优(考试中时间紧迫 不宜猛怼算法题最优解)平时练习可以体会最优解的思路,最优解请参考王道 166 | 167 | - 2019 10 14日更新完毕 168 | - 未学习最优解 169 | 170 | ### 2014 171 | 172 | ### 其余的自己学习算法思想即可,王道书的代码很好 173 | 174 | 个人题解 175 | 176 | 计算WPL使用递归算法,10**行左右解决问题**,特别好理解和记忆,超好用。 177 | 178 | 强烈推荐。王道上的算法我没看(代码看着就长,估计既不容易写对,有不好理解),自认为考试的时候我写不出来那种。 179 | 180 | ## 经典算法练习题 181 | 182 | 习题集为**剑指offer**共67道题 183 | 184 | 练习地址➡️https://www.nowcoder.com/ta/coding-interviews 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /图/BFS_AdjMatrix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-07-27. 3 | // BFS邻接矩阵版本 4 | // 5 | 6 | 7 | #include 8 | #include 9 | 10 | #define MAX_V 100 //邻接矩阵中的最大顶点书目 11 | #define INF 99999 //INF代表顶点不可达 12 | using namespace std; 13 | int n, G[MAX_V][MAX_V] = { 14 | {0, INF, 1}, 15 | {INF, 0, 3}, 16 | {INF, 1, 0}, 17 | 18 | }; //n代表当前图的顶点数目 。G为图的邻接矩阵,最大顶点数100 19 | int isVisited[100] = {0};//记录顶点是否被访问过 1代表是 20 | 21 | //访问 22 | void visit(int i) { 23 | printf("i=%d\n", i); 24 | 25 | } 26 | 27 | void BFS(int u) {//遍历u所在的连通块 28 | queue q;//定义一个辅助的队列 29 | q.push(u); 30 | visit(u); 31 | isVisited[u] = 1;//将u设置为已经访问 32 | while (!q.empty()) {//如果队列非空 33 | int u = q.front();//取出队首元素 34 | q.pop();//将队首元素出队 35 | for (int i = 0; i < n; ++i) {//遍历u的邻接点i 36 | if (isVisited[i] == 0 && G[u][i] != INF) { 37 | q.push(i); 38 | visit(i); 39 | isVisited[i] = true;//设置为已经访问 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | } 47 | 48 | void BFSTrave() { 49 | for (int u = 0; u < n; ++u) {//枚举所有顶点 50 | if (isVisited[u] != 1) {//顶点未访问过 51 | BFS(u);//以BFS方式访问 52 | } 53 | } 54 | } 55 | 56 | int main() { 57 | n = 3; 58 | BFSTrave(); 59 | } -------------------------------------------------------------------------------- /图/BFS_Min_Distance.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-08 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define INF 9999 10 | #define MAX 100 11 | using namespace std; 12 | 13 | int graph[MAX][MAX] = { 14 | //0 1 2 3 4 15 | {0, 1, 1, INF, INF},//0 16 | {INF, 0, INF, 1, INF},//1 17 | {INF, INF, 0, INF, INF},//2 18 | {INF, INF, INF, 0, 1}, //3 19 | {INF, INF, INF, INF, 0} //4 20 | };//图是无权图 INF代表不可达 21 | 22 | int d[MAX] = {0};//初始化距离数组 23 | 24 | //计算无权图的最短距离 25 | void BFSMinDistance(int i, int n) { 26 | queue myQueue;//初始化队列 27 | bool isVisited[MAX] = {false};//记录是否被访问的数组 28 | fill(d, d + MAX, INF);//将距离初始化INF 29 | 30 | myQueue.push(i);//入队列 31 | d[i] = 0;//距离0 32 | isVisited[i] = true;//已经被访问 33 | printf("-->%d\t",i);//打印访问的路径 34 | while (!myQueue.empty()) { 35 | int v = myQueue.front();//取出队首 36 | myQueue.pop();//删除队首 37 | for (int w = 0; w < n; ++w) { 38 | if (!isVisited[w] && graph[v][w] != INF) { 39 | printf("-->%d\t",w);//访问 40 | d[w] = d[v] + 1;//其实就是在这里多加了一个计算长度的语句 41 | isVisited[w] = true; 42 | myQueue.push(w); 43 | } 44 | } 45 | } 46 | 47 | } 48 | 49 | int main() { 50 | BFSMinDistance(0, 5); 51 | printf("\n下面是距离\n"); 52 | for (int i = 0; i < 5; ++i) { 53 | printf("距离--->%d\t", d[i]); 54 | } 55 | } -------------------------------------------------------------------------------- /图/DFS_Matrix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-07-31. 3 | // 4 | // DFS临界矩阵版本 5 | 6 | 7 | 8 | #include 9 | 10 | #define MAX_V 100 //邻接矩阵中的最大顶点书目 11 | #define INF 99999 //INF代表顶点不可达 12 | int n, G[MAX_V][MAX_V] = { 13 | {0, 1, INF, 1}, 14 | {INF, 0, 1, INF}, 15 | {INF, INF, 0, INF}, 16 | {INF, INF, INF, 0}, 17 | }; 18 | int isVisited[100] = {0}; 19 | 20 | int DFS(int u, int deep) {//deep代表深度 此代码中无实际意义 21 | isVisited[u] = 1; 22 | printf("--->%d\t", u); //打印访问的结点 23 | for (int i = 0; i < n; ++i) { 24 | if (G[u][i] != INF && isVisited[i] == 0) { 25 | DFS(i, deep + 1);//递归 26 | } 27 | } 28 | } 29 | 30 | void DFSTraverse() { 31 | //保证非连通的点也被访问到 32 | for (int u = 0; u < n; ++u) { 33 | if (isVisited[u] == 0) { 34 | DFS(u, 1); 35 | 36 | } 37 | 38 | } 39 | } 40 | 41 | int main() { 42 | n = 4; 43 | DFSTraverse(); 44 | } -------------------------------------------------------------------------------- /图/DijkstraAlgorithm.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-08-14. 3 | // 4 | #include 5 | #include 6 | 7 | #define MAX 1000 8 | #define INF 999999 9 | using namespace std; 10 | 11 | int n = 5, G[MAX][MAX] = { 12 | //0 1 2 3 4 13 | {0, 1, 6, INF, 5},//0 14 | {INF, 0, INF, 3, 2},//1 15 | {INF, INF, 0, INF, INF},//2 16 | {INF, INF, INF, 0, 4}, //3 17 | {INF, INF, INF, INF, 0} //4 18 | }; 19 | int d[MAX]; 20 | bool isVisited[MAX] = {false}; 21 | 22 | void dijkstra(int s) { 23 | fill(d, d + MAX, INF);//初始距离为INF 24 | d[s] = 0;//s到自身到距离为0 25 | for (int i = 0; i < n; i++) { 26 | int u = -1, MIN = INF;//u用来记录最小值到下标 27 | 28 | //找到距离当前顶点最小距离到顶点 并记录下标和距离 29 | for (int j = 0; j < n; ++j) { 30 | if (!isVisited[j] && d[j] < MIN) { 31 | u = j; 32 | MIN = d[j]; 33 | } 34 | } 35 | if (u == -1) return;//说明不连通 36 | isVisited[u] = true; 37 | for (int v = 0; v < n; v++) { 38 | if (!isVisited[v] && G[u][v] != INF && d[u] + G[u][v] < d[v]) { 39 | d[v] = d[u] + G[u][v];//松弛操作 40 | } 41 | } 42 | 43 | } 44 | } 45 | 46 | int main() { 47 | dijkstra(0); 48 | for (int i = 0; i < n; ++i) { 49 | printf("距离->%d\t",d[i]); 50 | } 51 | return 0; 52 | } -------------------------------------------------------------------------------- /字符串处理/十进制转二进制.cpp: -------------------------------------------------------------------------------- 1 | //// 2 | //// Created by HappyBing on 2020-03-02. 3 | //// 4 | // 5 | ////递归实现十进制数组转二进制 6 | // 7 | //#include 8 | //void fun(int n){ 9 | // if(n/2) 10 | // fun(n/2); 11 | // printf("%d",n%2); 12 | //} 13 | // 14 | //int main(){ 15 | // fun(128); 16 | //} -------------------------------------------------------------------------------- /常用算法数据结构/堆.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-03-08. 3 | // 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | void buildHeap(int *array); 10 | 11 | void adjustDown(int *array, int k, int len); 12 | 13 | void HeapSort(int *array, int len); 14 | 15 | void buildHeap(int *array, int len) { 16 | // 从第一个非叶子结点调整 17 | for (int i = len / 2; i >= 1; i--) { 18 | adjustDown(array, i, len); 19 | } 20 | } 21 | 22 | void adjustDown(int *array, int k, int len) {// 建立大顶堆 从小到大排序 23 | array[0] = array[k];// 保存第k个元素的值 24 | for (int i = 2 * k; i <= len; i *= 2) { 25 | if (i < len && array[i + 1] > array[i]) { 26 | i++; 27 | } 28 | // 这里一定是用array[0]去比较 因为要确定该元素的位置 29 | // 若用的是array[k] 会因为k是用来暂时记录 array[0] 该放的下标 k会发生变化,导致出错 30 | if (array[0] >= array[i]) { 31 | break; 32 | } else { 33 | array[k] = array[i]; 34 | k = i; 35 | } 36 | } 37 | array[k] = array[0]; //将第k个元素及其子树调整为堆 38 | } 39 | 40 | void swap(int *a, int *b) { 41 | int t = *a; 42 | *a = *b; 43 | *b = t; 44 | } 45 | 46 | void HeapSort(int *array, int len) { 47 | buildHeap(array, len); 48 | for (int i = len; i > 1; i--) { 49 | swap(&array[1], &array[i]); 50 | adjustDown(array, 1, i - 1); 51 | } 52 | 53 | 54 | } 55 | 56 | int main() { 57 | int array[11] = {-1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 58 | buildHeap(array, 10); 59 | HeapSort(array, 10); 60 | for (int x : array) { 61 | cout << x << endl; 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /排序/冒泡排序.cpp: -------------------------------------------------------------------------------- 1 | //// 2 | //// Created by HappyBing on 2019-04-10. 3 | //// 4 | // 5 | //#include 6 | // 7 | //void bubbleSort(int a[], int len) { 8 | // 9 | // 10 | // //趟数 11 | // for (int i = 0; i < len - 1; ++i) { 12 | // 13 | // //比较次数 14 | // for (int j = 0; j < len - i - 1; ++j) { 15 | // 16 | // if (a[j + 1] < a[j]) { 17 | // //交换 18 | // int temp = a[j]; 19 | // a[j] = a[j + 1]; 20 | // a[j + 1] = temp; 21 | // } 22 | // } 23 | // } 24 | //} 25 | // 26 | //int main() { 27 | // int a[10] = {4, 3, 5, 1, 2, 6, 9, 10, 7, 8}; 28 | // 29 | // bubbleSort(a, 10); 30 | // for (int i = 0; i < 10; ++i) { 31 | // printf("%d\t", a[i]); 32 | // } 33 | // return 0; 34 | //} -------------------------------------------------------------------------------- /排序/双向冒泡排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-22. 3 | // 4 | 5 | 6 | #include 7 | 8 | #define ElemType int 9 | 10 | void swap(int *, int *); 11 | 12 | //双向冒泡排序算法 13 | void BubbleSort(ElemType a[], int n) { 14 | int left = 0; 15 | int right = n - 1;//left 和right代表待排序部分的左右边界 16 | int flag = true;//用于优化冒泡排序的flag 17 | while (left < right && flag) { 18 | flag = false;//置标志为 19 | //从左向右边冒泡排序 20 | for (int i = left; i < right; ++i) { 21 | if (a[i] > a[i + 1]) { 22 | swap(&a[i], &a[i + 1]); 23 | flag = true; 24 | } 25 | } 26 | right--;//最高部分每排好一个元素右边界减1 27 | 28 | for (int i = right; i > left; --i) { 29 | if (a[i] < a[i - 1]) { 30 | swap(&a[i], &a[i - 1]); 31 | flag = true; 32 | } 33 | } 34 | left++;//最低部分每排好一个元素左边界加1 35 | 36 | } 37 | } 38 | 39 | //用于交换两个变量的函数 40 | void swap(int *i, int *j) { 41 | int temp = *j; 42 | *j = *i; 43 | *i = temp; 44 | } 45 | 46 | int main() { 47 | int a[10] = {-99, -666, 40000, 000, 2, 1, -1001, 12, -14, 7};//数组有序元素10个下标从1-9 48 | BubbleSort(a, 10); 49 | for (int i = 0; i < 10; ++i) { 50 | printf("%d\t", a[i]); 51 | } 52 | return 0; 53 | } -------------------------------------------------------------------------------- /排序/堆排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-08-19. 3 | // 4 | 5 | #include 6 | 7 | 8 | void swap(int *i, int *j) { 9 | int temp = *j; 10 | *j = *i; 11 | *i = temp; 12 | } 13 | 14 | void AdjustDown(int a[], int k, int len) { 15 | //数组有效果元素的长度从1开始 即第一个数组元素为a[1] 16 | //在将k位置的元素放在正确的位置的时候也会将k的孩子调整 17 | a[0] = a[k];//暂存a[i] 18 | for (int i = 2 * k; i <= len; i *= 2) { 19 | if (i < len && a[i + 1] > a[i]) { 20 | i++; 21 | // 看看孩子谁大 22 | } 23 | if (a[0] >= a[i]) { 24 | break; 25 | } else { 26 | a[k] = a[i];//1 27 | k = i;//2 用k记录位置 以便下次调整 28 | 29 | } 30 | 31 | } 32 | a[k] = a[0]; 33 | 34 | } 35 | 36 | void BuildHeap(int a[], int len) { 37 | for (int i = len / 2; i > 0; i--) { 38 | AdjustDown(a, i, len); 39 | } 40 | } 41 | 42 | void HeapSort(int a[], int len) { 43 | BuildHeap(a, len); 44 | for (int i = len; i > 1; --i) { 45 | //交换首尾元素 46 | swap(&a[i], &a[1]); 47 | //调整堆 48 | AdjustDown(a, 1, i - 1); 49 | } 50 | 51 | } 52 | 53 | //判断一个堆是否为大顶堆的算法(小顶堆只需要将所有if中的大于号改为小于号即可) 54 | bool IsMaxHeap(int a[], int len) { 55 | if (len % 2 == 0) {//len为偶数的时候所对应的完全二叉树又一个单独的分支结点需要独立判断 56 | if (a[len / 2] < a[len]) { 57 | return false; 58 | } 59 | //判断所有成双入对的结点 60 | for (int i = len / 2 - 1; i >= 1; --i) { 61 | if (a[i] < a[2 * i] || a[i] < a[2 * i + 1]) { 62 | return false; 63 | } 64 | } 65 | } else {//奇数的时候即每个非叶子结点都有两个孩子 直接判断即可 66 | for (int i = len / 2; i >= 1; --i) {// 67 | if (a[i] < a[2 * i] || a[i] < a[2 * i + 1]) { 68 | return false; 69 | } 70 | } 71 | } 72 | 73 | 74 | return true; 75 | 76 | } 77 | 78 | int main() { 79 | int a[101] = {0, -4, 3, 5, 1, 2, 6, 9, 10, 7, -8}; 80 | 81 | for (int i = 1; i <= 10; ++i) { 82 | printf("%d\t", a[i]); 83 | } 84 | printf("\n"); 85 | HeapSort(a, 10); 86 | for (int i = 1; i <= 10; ++i) { 87 | printf("%d\t", a[i]); 88 | } 89 | 90 | //测试是否为大顶堆 91 | printf("\n是否为大顶堆?%d", IsMaxHeap(a, 10));//递增的有序序列当然不是 92 | BuildHeap(a, 10);//建立大顶堆 93 | printf("\n是否为大顶堆?%d", IsMaxHeap(a, 10));//递增的有序序列当然不是 94 | 95 | return 0; 96 | } -------------------------------------------------------------------------------- /排序/希尔排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-18. 3 | // 4 | 5 | #include 6 | 7 | //希尔排序:数组下标从1开始,a[0]存放的元素无效,默认升序 8 | // 1 1 1 1 1 1 1 1 1 1 9 | void shellSort(int a[], int len) { 10 | int j, i, dk; 11 | for (dk = len / 2; dk >= 1; dk /= 2) {//dk表示步长 12 | for (i = dk + 1; i <= len; ++i) {//从dk+1处开始对步长为dk的所有元素进行排序,表示进行直接插入排序的次数 13 | if (a[i] < a[i - dk]) {//后边的元素大于前面的 14 | int temp = a[i];//保存a[i]元素的值 15 | for (j = i - dk; j > 0 && temp < a[j]; j -= dk) { //进行移动位置 注意从-1变味了-dk 16 | a[j + dk] = a[j];//后移元素 直接将j位置的元素 移动到j+dk的位置上 17 | } 18 | a[j + dk] = temp;//将a[i]元素放到正确的位置上 19 | } 20 | } 21 | } 22 | } 23 | 24 | int main() { 25 | int a[10] = {-99999, 2, -10, 100, -3, 4, 7, 9, -4445, 4123};//-99999元素无效 26 | for (int x:a) { 27 | printf("%d\t", x); 28 | 29 | } 30 | printf("\n"); 31 | shellSort(a, 9);//对下标为1-9的元素进行排序 32 | for (int x:a) { 33 | printf("%d\t", x); 34 | 35 | } 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /排序/归并2.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-04-16. 3 | // 4 | 5 | #include 6 | 7 | #define MAX 100 8 | 9 | void merge(int a[], int L1, int R1, int L2, int R2) { 10 | int temp[MAX]; 11 | int i = L1; 12 | int j = L2; 13 | int k = 0; 14 | 15 | while (i <= R1 && j <= R2) { 16 | if (a[i] > a[j]) { 17 | temp[k++] = a[j++]; 18 | } 19 | if (a[i] <= a[j]) { 20 | temp[k++] = a[i++]; 21 | } 22 | } 23 | 24 | while (i <= R1) temp[k++] = a[i++]; 25 | while (j <= R2) temp[k++] = a[j++]; 26 | 27 | for(int q = L1;q <= R2;++q){ 28 | a[q] = temp[q-L1]; 29 | } 30 | } 31 | 32 | void sort(int a[],int start,int end){ 33 | if(start < end){ 34 | int mid = (start+end)/2; 35 | sort(a,start,mid); 36 | sort(a,mid+1,end); 37 | merge(a, start,mid,mid+1,end); 38 | } 39 | } 40 | 41 | int main() { 42 | int a[11] = {1,4, 3, 5, 1, 2, 6, 9, 10, 7, 8}; 43 | //归并排序:时间复杂度O(nlogn) 空间复杂度O(n) 是一种基于分治的稳定排序算法 44 | sort(a, 0, 10); 45 | for (int i = 0; i < 11; ++i) { 46 | printf("%d\t", a[i]); 47 | } 48 | return 0; 49 | } -------------------------------------------------------------------------------- /排序/归并排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-04-11. 3 | // 4 | 5 | #include 6 | 7 | void merge(int a[], int L, int M, int R); 8 | 9 | void mergeSort(int a[], int L, int R) { 10 | if (L == R) { 11 | return; 12 | } else { 13 | 14 | //取中间的数,进行拆分 15 | int M = (L + R) / 2; 16 | 17 | //左边的数不断进行拆分 18 | mergeSort(a, L, M); 19 | 20 | //右边的数不断进行拆分 21 | mergeSort(a, M + 1, R); 22 | 23 | //合并 24 | merge(a, L, M + 1, R); 25 | 26 | 27 | } 28 | 29 | 30 | } 31 | 32 | void merge(int a[], int L, int M, int R) { 33 | // a:数组 34 | // L:数组第一个 35 | // R:数组最后一个 36 | // M: 分割点 37 | 38 | //新建两个数组 39 | // [L,M) [M,R] 40 | int leftArray[M - L]; 41 | int rightArray[R - M + 1]; 42 | 43 | //将M左边的全装入第一个数组 44 | for (int i = 0; i < M - L; ++i) { 45 | //0 1 2 3 4 5 = L + 0 1 2 3 4 5 6 46 | leftArray[i] = a[L+i]; 47 | } 48 | //将 M右边的全装入第二个 数组 49 | for (int j = 0; j < (R - M + 1); ++j) { 50 | rightArray[j] = a[M + j]; 51 | } 52 | //合并两个数组 53 | int i = 0; 54 | int j = 0; 55 | int k = L; 56 | while (i < (M - L) && j < (R - M + 1)) { 57 | if (leftArray[i] < rightArray[j]) { 58 | a[k] = leftArray[i]; 59 | i++; 60 | k++; 61 | } 62 | if (leftArray[i] >= rightArray[j]) { 63 | a[k] = rightArray[j]; 64 | j++; 65 | k++; 66 | } 67 | } 68 | //如果任何一个数组还有剩余则全都插到后面️ 69 | while (i < (M - L)) { 70 | a[k] = leftArray[i]; 71 | i++; 72 | k++; 73 | } 74 | while (j < (R - M + 1)) { 75 | a[k] = rightArray[j]; 76 | k++; 77 | j++; 78 | } 79 | 80 | 81 | } 82 | 83 | int main() { 84 | int a[11] = {1,4, 3, 5, 1, 2, 6, 9, 10, 7, 8}; 85 | mergeSort(a, 0, 10); 86 | for (int i = 0; i < 11; ++i) { 87 | printf("%d\t", a[i]); 88 | } 89 | return 0; 90 | } -------------------------------------------------------------------------------- /排序/快速排序-非递归版.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-18. 3 | // 4 | #include 5 | 6 | int Partition(int a[], int p, int r) { 7 | 8 | int temp = a[p]; 9 | while (p < r) { 10 | //若以第一个元素为划分对时候 先右后左!!!!! 11 | while (p < r && temp <= a[r]) { 12 | r--; 13 | } 14 | a[p] = a[r]; 15 | 16 | while (p < r && temp >= a[p]) 17 | p++; 18 | a[r] = a[p]; 19 | 20 | } 21 | a[p] = temp; 22 | return p; 23 | 24 | } 25 | 26 | void quickSortNonRecrusion(int a[], int p, int r) { 27 | // stack boundStack; 28 | 29 | //使用数组模拟一个栈 30 | int boundStack[100] = {0}; 31 | int top = -1; 32 | 33 | 34 | int low = p; 35 | int high = r; 36 | //完成初始划分 37 | int q = Partition(a, p, r); 38 | 39 | //入栈 40 | if (q > low + 1) { 41 | boundStack[++top] = low; 42 | boundStack[++top] = q - 1; 43 | } 44 | if (q < high - 1) { 45 | boundStack[++top] = q + 1; 46 | boundStack[++top] = high; 47 | } 48 | 49 | while (top >= 0) { 50 | high = boundStack[top--]; 51 | low = boundStack[top--]; 52 | int par = Partition(a, low, high); 53 | if (par > low + 1) { 54 | boundStack[++top] = low; 55 | boundStack[++top] = par - 1; 56 | } 57 | if (par < high - 1) { 58 | boundStack[++top] = par + 1; 59 | boundStack[++top] = high; 60 | 61 | } 62 | } 63 | } 64 | 65 | 66 | int main() { 67 | int a[10] = {-9999, -666, 4, 3000, 2, 1, -1001, 12, -14, 7};//数组有序元素从下标为1的元素开始 68 | 69 | quickSortNonRecrusion(a, 1, 9); 70 | for (int i = 1; i <= 9; ++i) { 71 | printf("%d\t", a[i]); 72 | } 73 | } -------------------------------------------------------------------------------- /排序/快速排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-04-11. 3 | // 4 | 5 | #include 6 | 7 | int findPosition(int *a, int left, int right); 8 | 9 | void quickSort(int *a, int left, int right) { 10 | //递归出口 11 | if(left >= right){ 12 | return; 13 | } 14 | int pos = findPosition(a, left, right); 15 | //递归进行排序 16 | quickSort(a, left, pos - 1); 17 | quickSort(a, pos + 1, right); 18 | 19 | } 20 | 21 | int findPosition(int *a, int left, int right) { 22 | int temp = a[left]; 23 | 24 | while (left < right) { 25 | while (left < right && a[right] >= temp) { 26 | right--; 27 | } 28 | a[left] = a[right]; 29 | 30 | while (left < right && a[left] <= temp) { 31 | left++; 32 | } 33 | a[right] = a[left]; 34 | } 35 | a[left] = temp; 36 | 37 | return left; 38 | } 39 | 40 | int main() { 41 | printf("待排序序列:\t"); 42 | int a[10] = {4, 3, 5, 2, 2, 6, 9, -10, 7, 8}; 43 | for (int i : a) { 44 | printf("%d\t", i); 45 | } 46 | printf("\n"); 47 | quickSort(a, 0, 9); 48 | printf("排序序列:\t"); 49 | 50 | for (int i : a) { 51 | printf("%d\t", i); 52 | } 53 | return 0; 54 | } -------------------------------------------------------------------------------- /排序/所有奇数移动到偶数前的算法.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-22. 3 | // 4 | 5 | #include 6 | 7 | #define ElemType int 8 | 9 | //用于交换两个变量的函数 10 | void swap(int *i, int *j) { 11 | int temp = *j; 12 | *j = *i; 13 | *i = temp; 14 | } 15 | 16 | void moveFigure(ElemType a[], int len) { 17 | //采用快速排序的partition的思想 18 | //从两端分别选取变量若是奇数则放到前面若是偶数则放到后面 19 | int left = 0; 20 | int right = len - 1; 21 | while (left < right) { 22 | //将right指向从右 往左数第一个奇数 23 | while (left < right && a[right] % 2 == 0) { 24 | right--; 25 | } 26 | //将left指向从左 往右数第一个偶数 27 | while (left < right && a[left] % 2 == 1) { 28 | left++; 29 | } 30 | if (left < right) { 31 | //交换left和right所指的元素 32 | swap(&a[left], &a[right]); 33 | } 34 | } 35 | } 36 | 37 | int main() { 38 | int a[10] = {1, 2, 4, 6, 7, 8, 9, 10, 5, 3}; 39 | moveFigure(a, 10); 40 | 41 | //c++11推荐的遍历数据的方式 for in 42 | for (int x:a) { 43 | printf("%d\t", x); 44 | } 45 | return 0; 46 | } -------------------------------------------------------------------------------- /排序/插入排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-04-11. 3 | // 4 | #include 5 | void insertSort(int *a,int len){ 6 | 7 | for(int i = 1; i <= len - 1; ++i){ 8 | int temp = a[i]; 9 | //移出空位 10 | while(i > 0 && temp < a[i - 1]){ 11 | a[i] = a[i - 1]; 12 | i --; 13 | } 14 | a[i] = temp; 15 | } 16 | } 17 | int main() { 18 | int a[10] = {4, 3, 5, 1, 2, 6, 9, 10, 7, 8}; 19 | 20 | insertSort(a, 10); 21 | for (int i : a) { 22 | printf("%d\t", i); 23 | } 24 | return 0; 25 | } -------------------------------------------------------------------------------- /排序/第k小的数字.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-22. 3 | // 4 | 5 | 6 | 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | //找到第k小的数字 规定最小的数字是第0小 13 | int findKMin(int a[], int left, int right, int k) { 14 | int temp = a[left]; 15 | int low = left; 16 | int high = right; 17 | 18 | while (left < right) { 19 | while (left < right && a[right] >= temp) { 20 | right--; 21 | } 22 | a[left] = a[right]; 23 | 24 | while (left < right && a[left] <= temp) { 25 | left++; 26 | } 27 | a[right] = a[left]; 28 | } 29 | a[left] = temp; 30 | printf("\n"); 31 | 32 | for (int i = low; i <= high; ++i) { 33 | printf("%d\t", a[i]); 34 | } 35 | printf("\n"); 36 | 37 | //上面内容除了不能使用形参之外和快排的分割一模一样 38 | if (left == k) { 39 | return a[left]; 40 | } else if (left > k) { 41 | //从zuo边找 42 | return findKMin(a, low, left - 1, k); 43 | } else { 44 | //从you找 45 | return findKMin(a, left + 1, high, k);//王道这里写错了⚠️ 46 | } 47 | 48 | 49 | } 50 | 51 | 52 | //方法二:建立堆并输出第k个 53 | 54 | //方法三:快速排序 然后输出第k个 55 | int main() { 56 | printf("待排序序列:\t"); 57 | int a[5] = {3, 1, 2, 6, 4}; 58 | for (int i : a) { 59 | printf("%d\t", i); 60 | } 61 | 62 | int k = 5; 63 | printf("\n%d\n", findKMin(a, 0, 4, k - 1));//k-1就可以得到第k小 从 1开始的 64 | 65 | 66 | printf("排序序列:\t"); 67 | sort(a, a + 5); 68 | for (int i : a) { 69 | printf("%d\t", i); 70 | } 71 | 72 | 73 | } -------------------------------------------------------------------------------- /排序/选择排序.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-04-11. 3 | // 4 | 5 | #include 6 | 7 | void selectSort(int *a, int len) { 8 | 9 | for (int i = 0; i < len - 1; ++i) { 10 | //选出最小的下标 11 | int minIndex = i; 12 | for(int j = i + 1;j < len;++j){ 13 | if(a[minIndex] > a[j]){ 14 | minIndex = j; 15 | } 16 | 17 | //交换元素位置 18 | if(minIndex!= i){ 19 | int temp = a[minIndex]; 20 | a[minIndex] = a[i]; 21 | a[i] = temp; 22 | } 23 | } 24 | } 25 | } 26 | int main() { 27 | int a[10] = {4, 3, 5, 1, 2, 6, 9, 10, 7, 8}; 28 | 29 | selectSort(a, 10); 30 | for (int i : a) { 31 | printf("%d\t", i); 32 | } 33 | return 0; 34 | } -------------------------------------------------------------------------------- /数据结构公式总结.md: -------------------------------------------------------------------------------- 1 | # 数据结构公式总结 2 | 3 | ## 树 4 | 5 | 1. 树中的结点数 = 所有结点的度数之和 + 1 = 总分支数 + 1 6 | 7 | 二叉树中 $n_0 + n_1 + n_2 = n_1+2*n_2+1$ —> $n_0 = n_2+1$ 8 | 9 | ​ $ n = 2*n_0 + n_1 -1$ 10 | 11 | 2. 度为m的树中第i层至多有 $m^{i-1}$ 12 | 3. 具有n个结点的m叉树的最小高度: $\lceil$$log_m (n*(m-1)+1)$$\rceil$ 13 | 14 | 4. n个结点的二叉链中,含有n+1个空链域(线索二叉树的时候很有用的结论) -------------------------------------------------------------------------------- /查找/KMP.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-07-19. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | void get_next(string s, int next[]) { 12 | int i = 0, j = 0; 13 | next[0] = 0; 14 | while (i < s.length() - 1) { 15 | if (j == 0 || s[i] == s[j]) { 16 | i++; 17 | j++; 18 | next[i] = j; 19 | } else { 20 | j = next[j]; 21 | } 22 | } 23 | } 24 | 25 | int Index_KMP(string s, string t, int next[], int pos) { 26 | int i = pos, j = 1; 27 | while (i <= s.length() && j <= t.length()) { 28 | if (j == 0 || s[i] == t[j]) {//j == 0 是kmp算法设计的巧妙之处 29 | ++i; 30 | ++j; 31 | } else { 32 | j = next[j]; 33 | } 34 | 35 | 36 | } 37 | if (j > t.length()) { 38 | return i - t.length();//返回位主串的起点下标 39 | } else { 40 | return 0; 41 | } 42 | 43 | } 44 | 45 | int main() { 46 | 47 | 48 | int next[100] = {0}; 49 | string s = "aaacaaaba"; 50 | string t = "aaaab"; 51 | cout << t.length() << endl; 52 | 53 | get_next(t, next); 54 | for (int i = 0; i <= 10; ++i) { 55 | printf("%d\t", next[i]); 56 | } 57 | printf("\n"); 58 | 59 | 60 | int i = Index_KMP(s, t, next, 1); 61 | printf("%d\n", i); 62 | 63 | 64 | } -------------------------------------------------------------------------------- /查找/折半查找.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-10-14. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | typedef struct SeqList { 9 | int len; 10 | int *elem; 11 | } SqList; 12 | 13 | //数组版本 14 | int BinarySearch(int A[], int left, int right, int k) { 15 | while (left <= right) { 16 | int mid = (left + right) / 2; 17 | if (A[mid] == k) { 18 | return mid; 19 | } else if (A[mid] < k) { 20 | left = mid + 1; 21 | } else { 22 | right = mid - 1; 23 | } 24 | } 25 | return -1; 26 | } 27 | 28 | //顺序表版本 29 | int BinarySearch2(SqList *sqList, int k) { 30 | int left = 0; 31 | int right = sqList->len - 1; 32 | while (left <= right) { 33 | int mid = (left + right) / 2; 34 | if (sqList->elem[mid] == k) { 35 | return mid; 36 | } else if (sqList->elem[mid] < k) { 37 | left = mid + 1; 38 | } else { 39 | right = mid - 1; 40 | } 41 | } 42 | return -1; 43 | } 44 | 45 | 46 | int main() { 47 | //算法二测试 48 | // SqList *sqList = (SqList *) malloc(sizeof(SqList)); 49 | // sqList->len = 10; 50 | // sqList->elem = (int *) malloc(sizeof(int) * sqList->len); 51 | // for (int i = 0; i < 10; ++i) { 52 | // sqList->elem[i] = i; 53 | // } 54 | // for (int i = 0; i < 10; ++i) { 55 | // printf("%d\t", sqList->elem[i]); 56 | // } 57 | // printf("下标为->%d\n", BinarySearch2(sqList,5)); 58 | 59 | //算法一测试 60 | int A[10] = {-100, 1, 3, 6, 7, 9, 10, 100, 1000, 10000}; 61 | printf("下标为->%d", BinarySearch(A, 0, 9, 10000)); 62 | return 0; 63 | } -------------------------------------------------------------------------------- /查找/折半查找递归版.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-10-14. 3 | // 4 | 5 | #include 6 | 7 | int BinarySearchRecursion(int A[], int left, int right, int k) { 8 | if (left < right) { 9 | int mid = (left + right) / 2; 10 | if (A[mid] == k) { 11 | return mid; 12 | } else if (A[mid] < k) { 13 | return BinarySearchRecursion(A, mid + 1, right, k); 14 | } else { 15 | return BinarySearchRecursion(A, left, mid - 1, k); 16 | } 17 | } 18 | return -1; 19 | } 20 | 21 | int main() { 22 | int A[10] = {-100,1,3,6,7,9,10,100,1000,10000}; 23 | printf("下标为->%d",BinarySearchRecursion(A,0,9,100)); 24 | return 0; 25 | } -------------------------------------------------------------------------------- /树/TreeTraverse.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-08-07. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #define ElemType int 10 | 11 | using namespace std; 12 | //定义树的链式存储结构 13 | typedef struct BiTNode { 14 | struct BiTNode *lchild; 15 | struct BiTNode *rchild; 16 | ElemType data; 17 | 18 | } BiTNode, *BiTree; 19 | 20 | //用于初始化一棵树的算法 21 | void initTree(BiTree *T) { 22 | *T = (BiTNode *) malloc(sizeof(BiTNode)); 23 | (*T)->data = 1; 24 | (*T)->lchild = (BiTNode *) malloc(sizeof(BiTNode)); 25 | (*T)->rchild = (BiTNode *) malloc(sizeof(BiTNode)); 26 | (*T)->lchild->data = 2; 27 | (*T)->lchild->lchild = (BiTNode *) malloc(sizeof(BiTNode)); 28 | (*T)->lchild->rchild = (BiTNode *) malloc(sizeof(BiTNode)); 29 | (*T)->lchild->rchild->data = 5; 30 | (*T)->lchild->rchild->lchild = NULL; 31 | (*T)->lchild->rchild->rchild = NULL; 32 | (*T)->rchild->data = 3; 33 | (*T)->rchild->lchild = (BiTNode *) malloc(sizeof(BiTNode)); 34 | (*T)->rchild->lchild->data = 6; 35 | (*T)->rchild->lchild->lchild = NULL; 36 | (*T)->rchild->lchild->rchild = NULL; 37 | (*T)->rchild->rchild = (BiTNode *) malloc(sizeof(BiTNode)); 38 | (*T)->rchild->rchild->data = 7; 39 | (*T)->rchild->rchild->lchild = NULL; 40 | (*T)->rchild->rchild->rchild = NULL; 41 | (*T)->lchild->lchild->data = 4; 42 | (*T)->lchild->lchild->lchild = NULL; 43 | (*T)->lchild->lchild->rchild = NULL; 44 | } 45 | 46 | //访问函数 用于输出结点的数据 47 | void visit(BiTNode *node) { 48 | printf("-->%d\t", node->data); 49 | } 50 | 51 | //先序遍历递归版本 52 | void preOrderTraverse(BiTree Tree) { 53 | if (Tree) { 54 | visit(Tree); 55 | preOrderTraverse(Tree->lchild); 56 | preOrderTraverse(Tree->rchild); 57 | } 58 | } 59 | 60 | //先序遍历非递归版本 61 | void preOrderTraverseNonrecursion(BiTree Tree) { 62 | if(Tree == nullptr){ 63 | return; 64 | } 65 | if (Tree) { 66 | BiTNode *stack[100]; 67 | int top = -1; 68 | BiTNode *p = Tree; 69 | stack[++top] = p;//根结点入栈 70 | while (top != -1) { 71 | p = stack[top--];//出栈访问 72 | visit(p); 73 | 74 | //!!!先右后左 因为后入栈的先出栈 而先序遍历 通常先访问左孩子 75 | if (p->rchild) { 76 | stack[++top] = p->rchild; 77 | } 78 | 79 | if (p->lchild) { 80 | stack[++top] = p->lchild; 81 | } 82 | 83 | } 84 | } 85 | } 86 | 87 | //中序遍历递归版本 88 | void inOrderTraverse(BiTree Tree) { 89 | if (Tree) { 90 | inOrderTraverse(Tree->lchild); 91 | visit(Tree); 92 | inOrderTraverse(Tree->rchild); 93 | } 94 | } 95 | 96 | //中序遍历非递归版本 97 | void inOrderTraverseNonrecursion(BiTree Tree) { 98 | if(Tree == nullptr){ 99 | return; 100 | } 101 | BiTNode *stack[100];//初始化一个数组栈 102 | int top = -1;//栈顶指针指向-1 103 | BiTNode *p = Tree;//辅助指针p 指向当前要操作的结点 初始为root 104 | while (p != nullptr || top != -1) { 105 | if (p) { 106 | stack[++top] = p;//入栈 107 | p = p->lchild;//指向其左孩子 108 | } else { 109 | p = stack[top--];//出栈 110 | visit(p);//访问 111 | p = p->rchild;//指向其右孩子 112 | } 113 | } 114 | } 115 | 116 | //后序遍历递归算法 117 | void postOrderTraverse(BiTree Tree) { 118 | if (Tree) { 119 | postOrderTraverse(Tree->lchild); 120 | postOrderTraverse(Tree->rchild); 121 | visit(Tree); 122 | } 123 | } 124 | 125 | //后序遍历的递归算法 126 | void postOrderTraverseNonrecursion(BiTree Tree) { 127 | if(Tree == nullptr){ 128 | return; 129 | } 130 | BiTNode *stack1[100]; 131 | BiTNode *stack2[100];//后序遍历的非递归算法 通常需要双栈 ,但是也有单栈的算法. 132 | //栈一用来辅助遍历,栈二存放遍历的顺序。 133 | int top1 = -1, top2 = -1; 134 | BiTNode *p = Tree; 135 | stack1[++top1] = p;//先将根结点入栈1 136 | while (top1 != -1) { 137 | p = stack1[top1--];//出栈1 138 | stack2[top2++] = p;//进入栈2 ,栈二是为了保存每遍历顺序的逆序的栈 139 | 140 | //先左后右的目的是 右先弹出栈1 然后先进栈2 后出栈2 所以是左 右 根的顺序 141 | if (p->lchild) {//先入左 142 | stack1[++top1] = p->lchild; 143 | } 144 | if (p->rchild) {//后入右 145 | stack1[++top1] = p->rchild; 146 | } 147 | } 148 | //遍历栈二 即访问顺序 149 | while (top2 != -1) { 150 | p = stack2[--top2]; 151 | visit(p); 152 | } 153 | } 154 | 155 | //层序遍历算法 借助c++ stl的queue实现 156 | void LevelOrderTraverse(BiTree Tree) { 157 | queue myQueue; 158 | if (Tree) { 159 | myQueue.push(Tree);//根结点入队列 160 | } 161 | while (!myQueue.empty()) { 162 | BiTNode *pNode = myQueue.front();//取得队首 163 | myQueue.pop();//删除队列首个元素 164 | visit(pNode); 165 | if (pNode->lchild) {//左孩子入队列 166 | myQueue.push(pNode->lchild); 167 | 168 | } 169 | if (pNode->rchild) {//右孩子入队列 170 | myQueue.push(pNode->rchild); 171 | 172 | } 173 | } 174 | } 175 | 176 | int main() { 177 | BiTree tree; 178 | initTree(&tree); 179 | 180 | preOrderTraverse(tree); 181 | printf("\n-----先序递归/非递归------\n"); 182 | preOrderTraverseNonrecursion(tree); 183 | 184 | printf("\n"); 185 | printf("\n-------------------------------------------\n"); 186 | printf("\n"); 187 | 188 | inOrderTraverse(tree); 189 | printf("\n-----中序递归/非递归------\n"); 190 | inOrderTraverseNonrecursion(tree); 191 | 192 | 193 | printf("\n"); 194 | printf("\n-------------------------------------------\n"); 195 | printf("\n"); 196 | 197 | postOrderTraverse(tree); 198 | printf("\n-----后序递归/非递归------\n"); 199 | postOrderTraverseNonrecursion(tree); 200 | 201 | printf("\n"); 202 | printf("\n-------------------------------------------\n"); 203 | printf("\n"); 204 | 205 | printf("层序遍历\n"); 206 | LevelOrderTraverse(tree); 207 | 208 | return 0; 209 | } -------------------------------------------------------------------------------- /树/判断是否为平衡二叉树的算法.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-09. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | #define ElemType int 13 | 14 | typedef struct BSTNode { 15 | struct BSTNode *left, *right; 16 | ElemType data; 17 | } *BiTree; 18 | 19 | int getDepth(BiTree tree); 20 | 21 | int heightSimple(BiTree tree) { 22 | return tree == NULL ? 0 : (max(heightSimple(tree->left), heightSimple(tree->right)) + 1); 23 | } 24 | 25 | //递归算法:自上而下的算法 增加了许多不必要的开销 需要剪枝 26 | bool judge_AVL(BiTree tree) { 27 | if (tree == NULL) 28 | return true; 29 | return (abs(heightSimple(tree->left) - heightSimple(tree->right)) <= 1) 30 | && judge_AVL(tree->left) && judge_AVL(tree->right); 31 | } 32 | 33 | //剪枝后算法:自下而上而上 发现不是直接终止 34 | bool judge_AVL_Opt(BiTree tree) { 35 | return getDepth(tree) != -1; 36 | } 37 | 38 | //如果子树是平衡二叉树则返回高度 如果不是平衡二叉树则返回-1 39 | int getDepth(BiTree tree) { 40 | if (tree == NULL) 41 | return 0; 42 | 43 | int left = getDepth(tree->left); 44 | if (left == -1)//-1代表不平衡了 45 | return -1; 46 | 47 | int right = getDepth(tree->right); 48 | if (right == 1) 49 | return 1; 50 | 51 | return abs(left - right) > 1 ? -1 : 1 + max(left, right); 52 | 53 | } 54 | 55 | int BST_insert(BiTree &T, ElemType val) { 56 | if (T == NULL) { 57 | T = (BSTNode *) malloc(sizeof(BSTNode)); 58 | T->data = val; 59 | T->left = NULL; 60 | T->right = NULL; 61 | return 1; 62 | } else if (T->data == val) { 63 | return -1;//相等报错 64 | } else if (T->data > val) {//小于根结点则插在左子树 65 | return BST_insert(T->left, val); 66 | } else { 67 | return BST_insert(T->right, val); 68 | } 69 | 70 | } 71 | 72 | void Create_BST(BiTree &tree, ElemType *array, int length) { 73 | tree = NULL; 74 | for (int i = 0; i < length; ++i) { 75 | BST_insert(tree, array[i]); 76 | } 77 | } 78 | 79 | int main() { 80 | int a[10] = {9, 8, 100, 11, 120, 4, 3, 2, 1, -10}; 81 | int length = 6; 82 | BiTree Tree; 83 | Create_BST(Tree, a, length); 84 | 85 | 86 | printf("是否为平衡二叉树?%d\n", judge_AVL(Tree)); 87 | printf("是否为平衡二叉树?%d\n", judge_AVL_Opt(Tree)); 88 | return 0; 89 | } -------------------------------------------------------------------------------- /树/平衡二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-06. 3 | // 4 | 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | #define ElemType int 14 | typedef struct BSTNode { 15 | struct BSTNode *left, *right; 16 | ElemType data; 17 | } *BiTree; 18 | 19 | 20 | BSTNode *BST_search(BiTree T, ElemType val, BSTNode *&p) { 21 | while (T != NULL && T->data != val) { 22 | p = T; 23 | if (val < T->data) { 24 | T = T->left; 25 | } else { 26 | T = T->right; 27 | } 28 | } 29 | return T; 30 | } 31 | 32 | int BST_insert(BiTree &T, ElemType val) { 33 | if (T == NULL) { 34 | T = (BSTNode *) malloc(sizeof(BSTNode)); 35 | T->data = val; 36 | T->left = NULL; 37 | T->right = NULL; 38 | return 1; 39 | } else if (T->data == val) { 40 | return -1;//相等报错 41 | } else if (T->data > val) {//小于根结点则插在左子树 42 | return BST_insert(T->left, val); 43 | } else { 44 | return BST_insert(T->right, val); 45 | } 46 | 47 | } 48 | 49 | void Create_BST(BiTree &tree, ElemType *array, int length) { 50 | tree = NULL; 51 | for (int i = 0; i < length; ++i) { 52 | BST_insert(tree, array[i]); 53 | } 54 | } 55 | 56 | void inOrderTraverseNonRecur(BiTree tree) { 57 | if (tree == NULL) { 58 | return; 59 | } 60 | inOrderTraverseNonRecur(tree->left); 61 | printf("->%d\n", tree->data); 62 | inOrderTraverseNonRecur(tree->right); 63 | } 64 | 65 | void layerTraverse(BiTree tree) { 66 | if (tree == nullptr) { 67 | return; 68 | } 69 | queue < BSTNode * > q; 70 | q.push(tree); 71 | while (!q.empty()) { 72 | BSTNode *p = q.front(); 73 | q.pop(); 74 | printf("->%d\n", p->data); 75 | if (p->left != nullptr) { 76 | q.push(p->left); 77 | } 78 | if (p->right != nullptr) { 79 | q.push(p->right); 80 | } 81 | } 82 | 83 | } 84 | 85 | int main() { 86 | int a[10] = {9, 8, 7, 6, 5, 4, 3, 2, 1, -10}; 87 | int length = 10; 88 | BiTree Tree; 89 | Create_BST(Tree, a, length); 90 | printf("中序遍历\n"); 91 | inOrderTraverseNonRecur(Tree); 92 | printf("层序遍历\n"); 93 | layerTraverse(Tree); 94 | return 0; 95 | } -------------------------------------------------------------------------------- /树/求二叉树的高度.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-09-09. 3 | // 4 | 5 | 6 | #include 7 | #include 8 | 9 | #define ElemType int 10 | 11 | using namespace std; 12 | 13 | typedef struct BTNode { 14 | struct BTNode *lchild, *rchild; 15 | ElemType data; 16 | } BTNode, *BiTree; 17 | 18 | 19 | //非递归算法求树的高度 20 | int height(BiTree tree) { 21 | if (tree == nullptr) { 22 | return 0; 23 | } 24 | int high = 0; 25 | queue < BTNode * > q; 26 | q.push(tree); 27 | 28 | while (!q.empty()) { 29 | int size = q.size(); 30 | high++; 31 | //和层序遍历的不同之处 需要将队列中的所有本层元素处理完在处理下一层的 32 | for (int i = 0; i < size; ++i) { 33 | BTNode *p = q.front(); 34 | q.pop(); 35 | if (p->lchild != nullptr) { 36 | q.push(p->lchild); 37 | } 38 | if (p->rchild != nullptr) { 39 | q.push(p->rchild); 40 | } 41 | } 42 | 43 | 44 | } 45 | return high; 46 | 47 | } 48 | 49 | //递归版求树的高度 50 | int heightRecur(BiTree tree) { 51 | if (tree == NULL) 52 | return 0; 53 | int lheight = height(tree->lchild); 54 | int rheight = height(tree->rchild); 55 | return lheight > rheight ? lheight + 1 : rheight + 1; 56 | 57 | } 58 | 59 | //超级精简 一行代码 60 | int heightSimple(BiTree tree) { 61 | return tree == NULL ? 0 : (max(heightSimple(tree->lchild), heightSimple(tree->rchild)) + 1); 62 | } 63 | 64 | int main() { 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /树/给定高度求平衡二叉树结点个数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-11-27. 3 | // 4 | 5 | #include 6 | 7 | int f(int height){ 8 | if(height == 0){ 9 | return 0; 10 | } 11 | if(height == 1){ 12 | return 1; 13 | } 14 | if(height==2){ 15 | return 2; 16 | } 17 | return f(height-1)+f(height-2)+1; 18 | } 19 | int main(){ 20 | printf("-->%d\n",f(6)); 21 | } -------------------------------------------------------------------------------- /线性表/课后算法习题.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-08-21. 3 | // 4 | 5 | #include 6 | 7 | #define ElemType int 8 | #define MAX_SIZE 50 9 | //定义顺序表的结构体 10 | typedef struct { 11 | ElemType data[MAX_SIZE]; 12 | int length; 13 | } SqList; 14 | 15 | //题目一:从顺序表中删除最小值的元素并返回删除的值 出错则退出运行 16 | bool deleteMinElem(SqList &list, int &value) { 17 | //返回值为value 18 | if (list.length == 0) { 19 | return false; 20 | } 21 | value = list.data[0]; 22 | int index = 0; 23 | for (int i = 1; i < list.length; ++i) { 24 | if (list.data[i] < value) { 25 | index = i; 26 | value = list.data[i]; 27 | } 28 | } 29 | 30 | //将最后一个元素放入 i位置的 31 | list.data[index] = list.data[list.length - 1]; 32 | //线性表的长度减1 33 | list.length--; 34 | return true; 35 | } 36 | 37 | //题目二:将顺序表L的所有元素逆置 38 | void reverseList(SqList &l) { 39 | //空表和长度为一的表不需要逆置 40 | if (l.length == 0 || l.length == 1) { 41 | return; 42 | } 43 | for (int i = 0, j = l.length - 1; i < j; i++, j--) { 44 | //交换两个元素 45 | int temp = l.data[i]; 46 | l.data[i] = l.data[j]; 47 | l.data[j] = temp; 48 | } 49 | 50 | } 51 | 52 | //题目三:删除所有值为x的元素 53 | //方法1:虚拟构造一个新的数组 利用数组的随机访问 根据不等于X的元素 在原来数组的基础上构造新的数组 54 | void deleteX_1(SqList &list, int value) { 55 | if (list.length == 0) { 56 | return; 57 | } 58 | int k = 0;//用于记录不等于x的元素个数 同时也是删除x后线性表的下标 59 | for (int i = 0; i < list.length; ++i) { 60 | if (list.data[i] != value) { 61 | list.data[k] = list.data[i];//将数据赋予 第k个位置的元素 62 | k++;//伪新数组的下标+1 63 | } 64 | } 65 | list.length = k; 66 | } 67 | 68 | //法二:有几个等于X的元素 当前元素就向前移动几个 69 | void deleteX_2(SqList &list, int value) { 70 | if (list.length == 0) { 71 | return; 72 | }; 73 | int k = 0; 74 | int i = 0; 75 | while (i < list.length) { 76 | if (list.data[i] == value) { 77 | k++;//等于value元素的个数 78 | } else { 79 | list.data[i - k] = list.data[i];//当前元素迁移k个元素 80 | } 81 | i++; 82 | } 83 | list.length = list.length - k; 84 | } 85 | 86 | //题目四:删除有序的顺序表的值【s,t】的元素 87 | bool deleteS_T(SqList &l, int s, int t) { 88 | if (s >= t) { 89 | return false; 90 | } 91 | if (l.length == 0) { 92 | return false; 93 | } 94 | if ((s >= l.data[0] && s <= l.data[l.length - 1]) && (t >= l.data[0] && t <= l.data[l.length - 1])) { 95 | //如果s和t都在数组值的范围内 时候删除元素 96 | //利用上面的方法 有种伪造数组的感觉 97 | int k = 0; 98 | for (int i = 0; i < l.length; ++i) { 99 | if (l.data[i] < s || l.data[i] > t) { 100 | l.data[k] = l.data[i]; 101 | k++; 102 | } 103 | } 104 | l.length = k; 105 | } 106 | return true; 107 | } 108 | 109 | 110 | // 题目五:同4 四的方法可以删除有序的顺序表 111 | 112 | // 题目六:方法和3异曲同工 113 | bool delete_Same(SqList &list) { 114 | if (list.length == 0 || list.length == 1) {//长度为0或者1的时候 无重复元素 115 | return false; 116 | } 117 | int i, j;//i用于记录上一个不一样的元素的下标, j用于循环遍历 从数组的第二个元素(下标为1开始) 118 | for (i = 0, j = 1; j < list.length; ++j) { 119 | if (list.data[i] != list.data[j]) { 120 | list.data[++i] = list.data[j];//原理同3 121 | } 122 | 123 | } 124 | list.length = i + 1;//调整表长度 表长度至少为1个因为第一个元素肯定不同 125 | return true; 126 | } 127 | 128 | //题目七:合并两个有序顺序表(合并步骤归并排序的思想差不多) 129 | bool mergeTwoList(SqList &list1, SqList &list2, SqList &list) { 130 | if (list1.length == 0 || list2.length == 0) { 131 | return false; 132 | } 133 | if (list1.length + list2.length > MAX_SIZE) { 134 | return false; 135 | } 136 | int index1 = 0; 137 | int index2 = 0; 138 | int index = 0; 139 | //将等长部分合并 140 | while (index1 < list1.length && index2 < list2.length) { 141 | if (list1.data[index1] <= list2.data[index2]) { 142 | list.data[index++] = list1.data[index1++]; 143 | } else { 144 | list.data[index++] = list2.data[index2++]; 145 | } 146 | } 147 | //将剩余部分合并 148 | while (index1 < list1.length) { 149 | list.data[index++] = list1.data[index1++]; 150 | } 151 | while (index2 < list2.length) { 152 | list.data[index++] = list2.data[index2++]; 153 | } 154 | list.length = index; 155 | return true; 156 | } 157 | 158 | int main() { 159 | /*题目1测试*/ 160 | // SqList l; 161 | // l.length = 4; 162 | // l.data[0] = 11; 163 | // l.data[1] = 41; 164 | // l.data[2] = 2; 165 | // l.data[3] = 31; 166 | // int value = -1; 167 | // 168 | // for (int i = 0; i < l.length; ++i) { 169 | // printf("%d\t", l.data[i]); 170 | // } 171 | // printf("\n"); 172 | // deleteMinElem(l, value); 173 | // for (int i = 0; i < l.length; ++i) { 174 | // printf("%d\t", l.data[i]); 175 | // } 176 | // printf("\nvalue:-->%d", value); 177 | 178 | 179 | // /*题目2测试*/ 180 | // SqList l; 181 | // l.length = 1; 182 | // l.data[0] = 11; 183 | // l.data[1] = 41; 184 | // l.data[2] = 2; 185 | // l.data[3] = 31; 186 | // l.data[4] = 311; 187 | // 188 | // 189 | // for (int i = 0; i < l.length; ++i) { 190 | // printf("%d\t", l.data[i]); 191 | // } 192 | // printf("\n"); 193 | // reverseList(l); 194 | // for (int i = 0; i < l.length; ++i) { 195 | // printf("%d\t", l.data[i]); 196 | // } 197 | 198 | 199 | // /*题目3测试*/ 200 | // SqList l; 201 | // l.length = 5; 202 | // l.data[0] = 11; 203 | // l.data[1] = 11; 204 | // l.data[2] = 2; 205 | // l.data[3] = 11; 206 | // l.data[4] = 111; 207 | // 208 | // 209 | // for (int i = 0; i < l.length; ++i) { 210 | // printf("%d\t", l.data[i]); 211 | // } 212 | // printf("\n"); 213 | // deleteX_2(l, 11); 214 | // for (int i = 0; i < l.length; ++i) { 215 | // printf("%d\t", l.data[i]); 216 | // } 217 | 218 | // /*题目4测试*/ 219 | // SqList l; 220 | // l.length = 5; 221 | // l.data[0] = 1; 222 | // l.data[1] = 2; 223 | // l.data[2] = 31; 224 | // l.data[3] = 4; 225 | // l.data[4] = 5; 226 | // 227 | // 228 | // for (int i = 0; i < l.length; ++i) { 229 | // printf("%d\t", l.data[i]); 230 | // } 231 | // printf("\n"); 232 | // deleteS_T(l, 31, 31); 233 | // for (int i = 0; i < l.length; ++i) { 234 | // printf("%d\t", l.data[i]); 235 | // } 236 | 237 | // /*题目6测试*/ 238 | // SqList l; 239 | // l.length = 7; 240 | // l.data[0] = 1; 241 | // l.data[1] = 2; 242 | // l.data[2] = 2; 243 | // l.data[3] = 3; 244 | // l.data[4] = 5; 245 | // l.data[5] = 5; 246 | // l.data[6] = 5; 247 | // 248 | // 249 | // for (int i = 0; i < l.length; ++i) { 250 | // printf("%d\t", l.data[i]); 251 | // } 252 | // printf("\n"); 253 | // delete_Same(l); 254 | // for (int i = 0; i < l.length; ++i) { 255 | // printf("%d\t", l.data[i]); 256 | // } 257 | // return 0; 258 | 259 | /*题目7测试*/ 260 | SqList l; 261 | SqList l1; 262 | SqList l2; 263 | l1.length = 3; 264 | l2.length = 2; 265 | l1.data[0] = 1; 266 | l1.data[1] = 10; 267 | l1.data[2] = 1100; 268 | l2.data[0] = 4; 269 | l2.data[1] = 100; 270 | mergeTwoList(l1, l2, l); 271 | 272 | 273 | printf("\n"); 274 | for (int i = 0; i < l.length; ++i) { 275 | printf("%d\t", l.data[i]); 276 | } 277 | return 0; 278 | } -------------------------------------------------------------------------------- /经典算法练习题/L01二维数组中的查找.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-12-28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | bool Find(int target, vector> array) { 11 | int i = array.size();//i为行数 12 | int j = array[0].size();//j为列数 13 | int startI = i - 1; 14 | int startJ = 0; 15 | while (startI >= 0 && startJ >= 0 && startJ <= j) { 16 | if (target > array[startI][startJ]) { 17 | startJ++; 18 | } else if (target < array[startI][startJ]) { 19 | startI--; 20 | } else { 21 | return true; 22 | } 23 | } 24 | return false; 25 | 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /经典算法练习题/L02替换空格.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-12-28. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void replaceSpace(char *str, int length) { 11 | string s(str);//char数组转为字符串 12 | int i = 0; 13 | //查找空格并且替换 14 | while ((i = s.find(' ', i)) > -1) { 15 | s.erase(i, 1); 16 | s.insert(i, "%20"); 17 | } 18 | //将string转会char数组 19 | auto ret = s.c_str(); 20 | strcpy(str, ret); 21 | } -------------------------------------------------------------------------------- /经典算法练习题/L03从尾到头打印链表.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-12-28. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | struct ListNode { 12 | int val; 13 | struct ListNode *next; 14 | 15 | ListNode(int x) : 16 | val(x), next(NULL) { 17 | } 18 | }; 19 | 20 | vector printListFromTailToHead(ListNode *head) { 21 | stack s;//创建一个栈 22 | vector result; 23 | while (head != nullptr) { 24 | s.push(head->val); 25 | head = head->next; 26 | } 27 | while (!s.empty()) { 28 | result.push_back(s.top()); 29 | s.pop(); 30 | } 31 | return result; 32 | } 33 | 34 | //int main() { 35 | // ListNode *head = new ListNode(1); 36 | // head->next = new ListNode(2); 37 | // vector a = printListFromTailToHead(head); 38 | // for (int x : a) { 39 | // cout << x << endl; 40 | // } 41 | //} -------------------------------------------------------------------------------- /经典算法练习题/L04重建二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-05. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct TreeNode { 11 | int val; 12 | TreeNode *left; 13 | TreeNode *right; 14 | 15 | TreeNode(int x) : val(x), left(NULL), right(NULL) {} 16 | }; 17 | 18 | 19 | TreeNode *reConstructBinaryTree(vector pre, vector vin) { 20 | 21 | //围绕中序遍历序列展开代码 22 | int vinLen = vin.size(); 23 | if (vinLen == 0) { 24 | return nullptr; 25 | } 26 | 27 | //在中序序列中找到根节点 28 | int rootIndex = 0; 29 | for (int i = 0; i < vinLen; ++i) { 30 | if (vin[i] == pre[0]) { 31 | rootIndex = i; 32 | break; 33 | } 34 | } 35 | //创建根节点 36 | TreeNode *root = new TreeNode(pre[0]); 37 | 38 | vector left_p, right_p, left_i, right_i; 39 | 40 | //左子树数组 41 | for (int i = 0; i < rootIndex; ++i) { 42 | left_p.push_back(pre[i + 1]); 43 | left_i.push_back(vin[i]); 44 | 45 | } 46 | //右子树数组 47 | for (int j = rootIndex + 1; j < vinLen; ++j) { 48 | right_p.push_back(pre[j]); 49 | right_i.push_back(vin[j]); 50 | } 51 | //递归左右子树 52 | root->left = reConstructBinaryTree(left_p, left_i); 53 | root->right = reConstructBinaryTree(right_p, right_i); 54 | 55 | return root; 56 | } 57 | 58 | void inOrderTraverse(TreeNode *root) { 59 | if (root != nullptr) { 60 | inOrderTraverse(root->left); 61 | cout << root->val << endl; 62 | inOrderTraverse(root->right); 63 | } 64 | } 65 | 66 | //int main() { 67 | // vector pre; 68 | // vector vin; 69 | // pre = {1, 2, 4, 7, 3, 5, 6, 8}; 70 | // vin = {4, 7, 2, 1, 5, 3, 8, 6}; 71 | // 72 | // TreeNode *root = reConstructBinaryTree(pre, vin); 73 | // inOrderTraverse(root); 74 | //} -------------------------------------------------------------------------------- /经典算法练习题/L05两个栈实现一个队列.cpp: -------------------------------------------------------------------------------- 1 | //// 2 | //// Created by HappyBing on 2020-01-05. 3 | //// 4 | // 5 | //#include 6 | //#include 7 | // 8 | //using namespace std; 9 | // 10 | //stack stack1; 11 | //stack stack2; 12 | // 13 | //void push(int node) { 14 | // stack1.push(node); 15 | //} 16 | // 17 | //int pop() { 18 | // if (stack2.empty()) { 19 | // while (!stack1.empty()) { 20 | // stack2.push(stack1.top()); 21 | // stack1.pop(); 22 | // } 23 | // 24 | // } 25 | // int temp = stack2.top(); 26 | // stack2.pop(); 27 | // return temp; 28 | //} -------------------------------------------------------------------------------- /经典算法练习题/L06旋转数组中最小的元素.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-05. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | int minNumberInRotateArray(vector rotateArray) { 10 | if(rotateArray.size()==0){ 11 | return 0; 12 | } 13 | int i = 0; 14 | int j = (i+1)%rotateArray.size(); 15 | int count = 0; 16 | while(rotateArray[j]>=rotateArray[i]&&count a = {1,0,1,1,1}; 26 | // cout< 6 | #include 7 | 8 | using namespace std; 9 | // 10 | //int Fibonacci(int n) { 11 | // if(n == 0){ 12 | // return 0; 13 | // } 14 | // if(n == 1){ 15 | // return 1; 16 | // } 17 | // return Fibonacci(n-1) + Fibonacci(n-2); 18 | //} 19 | 20 | 21 | int Fibonacci(int n) { 22 | if (n == 0) { 23 | return 0; 24 | } 25 | if (n == 1) { 26 | return 1; 27 | } 28 | int ii = 0; 29 | int jj = 1; 30 | int res = 0; 31 | for (int i = 0; i < n - 1; ++i) { 32 | res = ii + jj; 33 | ii = jj; 34 | jj = res; 35 | } 36 | return res; 37 | } 38 | 39 | //int main() { 40 | // cout << Fibonacci(6); 41 | //} -------------------------------------------------------------------------------- /经典算法练习题/L08跳台阶.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-06. 3 | // 4 | 5 | int jumpFloor(int number) { 6 | if(number == 1){ 7 | return 1; 8 | } 9 | if( number == 2){ 10 | return 2; 11 | } 12 | int pre = 1; 13 | int next = 2; 14 | int temp = 0; 15 | for(int i = 0; i < number - 2;i++){ 16 | temp = pre + next; 17 | pre = next; 18 | next = temp; 19 | } 20 | return temp; 21 | } -------------------------------------------------------------------------------- /经典算法练习题/L09变态跳台阶.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-06. 3 | // 4 | 5 | int JumpFloorII(int target) { 6 | return target <= 0 ? 0 : 1 << (target - 1); 7 | } -------------------------------------------------------------------------------- /经典算法练习题/L10矩形覆盖.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-12. 3 | // 4 | 5 | int rectCover(int number) { 6 | if (number <= 0) { 7 | return 0; 8 | } 9 | if (number == 1) { 10 | return 1; 11 | } 12 | if (number == 2) { 13 | return 2; 14 | } 15 | return rectCover(number - 1) + rectCover(number - 2); 16 | } -------------------------------------------------------------------------------- /经典算法练习题/L11二进制中1的个数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-12. 3 | // 4 | 5 | #include 6 | #define MAX 0x7FFFFFFF 7 | #define MIN 0x10000000 8 | using namespace std; 9 | 10 | int NumberOf1(int n) { 11 | int count = 0; 12 | int flag = 1; 13 | while (flag) {//最多只会移动32次 左移是逻辑左移 (去掉最高位 右侧补0) 14 | if (flag & n) { 15 | ++count; 16 | } 17 | flag = flag << 1; 18 | } 19 | 20 | return count; 21 | } 22 | // 23 | //int main() { 24 | // printf("%d\n",MIN); 25 | // printf("-->%d", NumberOf1(MIN)); 26 | //} -------------------------------------------------------------------------------- /经典算法练习题/L12数值的整数次方.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-12. 3 | // 4 | #include 5 | #include 6 | double Power(double base, int exponent) { 7 | //递归出口 8 | if (exponent == 0) {//特殊情况1 9 | return 1; 10 | } 11 | if (exponent == 1) {//特殊情况2 12 | return base; 13 | } 14 | //递归函数 15 | double result = Power(base, exponent >> 1); 16 | result *= result;//乘方递归体 17 | if (exponent & 0x1 == 1) {//判断奇偶次方 18 | result *= base; 19 | } 20 | return result; 21 | } 22 | //int main(){ 23 | // printf("%lf",pow(2.0,-1.0)); 24 | //} -------------------------------------------------------------------------------- /经典算法练习题/L13调整数组顺序使得奇数在偶数前面.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-13. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | void reOrderArray(vector &array) { 11 | //算法本质:插入排序 --> 将奇数插入到偶数前面 12 | for (int i = 1; i < array.size(); ++i) { 13 | //从第二个元素开始比较 若是奇数则向前移动 14 | int temp = array[i];//保存第i个位置应该插入到数 15 | int j = i;//使用临时遍历j用于确定第i个元素的下标j(若不使用i的复制j 则会造成i向前回溯 影响算法的效率) 16 | if (temp % 2 == 1) {//是奇数 17 | while (j > 0 && array[j - 1] % 2 == 0) {//若前面是偶数则移动 18 | array[j] = array[j - 1]; 19 | j--; 20 | } 21 | array[j] = temp; 22 | } 23 | } 24 | } 25 | 26 | //int main() { 27 | // 28 | // vector a = {1, 2, 3, 4}; 29 | // reOrderArray(a); 30 | // for (int aa:a) { 31 | // cout << aa << endl; 32 | // } 33 | //} -------------------------------------------------------------------------------- /经典算法练习题/L14链表中倒数第k个结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-13. 3 | // 4 | 5 | #include 6 | 7 | struct ListNode { 8 | int val; 9 | struct ListNode *next; 10 | 11 | ListNode(int x) : 12 | val(x), next(NULL) { 13 | } 14 | }; 15 | 16 | 17 | ListNode *FindKthToTail(ListNode *pListHead, unsigned int k) { 18 | if (pListHead == NULL || k <= 0) { 19 | return NULL; 20 | } 21 | if (pListHead->next == NULL) { 22 | return pListHead; 23 | } 24 | //双指针法 25 | ListNode *p1, *p2; 26 | p1 = pListHead; 27 | p2 = pListHead; 28 | //将第一个指针移动k-1次 29 | for (int i = 1; i < k; ++i) { 30 | if (p1->next != NULL) { 31 | p1 = p1->next; 32 | } else { 33 | return NULL; 34 | } 35 | } 36 | //移动第二个指针 直到第一个指针指向最后一个元素(即next == NULL) 37 | while (p1->next != NULL) { 38 | p2 = p2->next; 39 | p1 = p1->next; 40 | } 41 | return p2; 42 | } -------------------------------------------------------------------------------- /经典算法练习题/L15反转链表.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-13. 3 | // 4 | 5 | #include 6 | 7 | struct ListNode { 8 | int val; 9 | struct ListNode *next; 10 | 11 | ListNode(int x) : 12 | val(x), next(NULL) { 13 | } 14 | }; 15 | 16 | ListNode *ReverseList(ListNode *pHead) { 17 | ListNode *pre = NULL, *next = NULL; 18 | if (pHead == NULL) { 19 | return NULL; 20 | } 21 | while (pHead->next != NULL) { 22 | next = pHead->next; 23 | pHead->next = pre; 24 | pre = pHead; 25 | pHead = next; 26 | } 27 | return pre; 28 | } 29 | 30 | 31 | ListNode *ReverseList2(ListNode *pHead) { 32 | if (pHead == NULL) { 33 | return NULL; 34 | } 35 | if (pHead->next == NULL) { 36 | return pHead; 37 | } 38 | //递归到最后一个结点 同时保存前一个结点的信息 39 | ListNode *p = ReverseList2(pHead->next); 40 | //反转 41 | pHead->next->next = pHead; 42 | pHead->next = NULL; 43 | return p; 44 | } 45 | -------------------------------------------------------------------------------- /经典算法练习题/L16合并两个排序的链表.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-14. 3 | // 4 | #include 5 | 6 | struct ListNode { 7 | int val; 8 | struct ListNode *next; 9 | 10 | ListNode(int x) : 11 | val(x), next(NULL) { 12 | } 13 | }; 14 | 15 | ListNode *Merge(ListNode *pHead1, ListNode *pHead2) { 16 | if (pHead1 == NULL) { 17 | return pHead2; 18 | } 19 | if (pHead2 == NULL) { 20 | return pHead1; 21 | } 22 | //新建头结点 一定要新建头结点 保证接下来的循环两个链表地位是平等的 否则需要挑选较小的结点作为头结点 23 | ListNode *head = new ListNode(-1); 24 | ListNode *tempP = head; 25 | while (pHead1 != NULL && pHead2 != NULL) { 26 | if (pHead1->val < pHead2->val) { 27 | tempP->next = pHead1; 28 | pHead1 = pHead1->next; 29 | } else { 30 | tempP->next = pHead2; 31 | pHead2 = pHead2->next; 32 | } 33 | tempP = tempP->next; 34 | 35 | } 36 | if (pHead1 != NULL) { 37 | tempP->next = pHead1; 38 | } 39 | if (pHead2 != NULL) { 40 | tempP->next = pHead2; 41 | } 42 | return head->next; 43 | 44 | } -------------------------------------------------------------------------------- /经典算法练习题/L17树的子结构.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-14. 3 | // 4 | #include 5 | 6 | struct TreeNode { 7 | int val; 8 | struct TreeNode *left; 9 | struct TreeNode *right; 10 | 11 | TreeNode(int x) : 12 | val(x), left(NULL), right(NULL) { 13 | } 14 | }; 15 | 16 | bool isSubtree(TreeNode *pRoot1, TreeNode *pRoot2) { 17 | //用于判断两棵树是否从根结点开始就长得一样 18 | if (pRoot2 == NULL) { 19 | return true; 20 | } 21 | if (pRoot1 == NULL) { 22 | return false; 23 | } 24 | if (pRoot1->val == pRoot2->val) { 25 | //判断子树的值是否相等 26 | return isSubtree(pRoot1->left, pRoot2->left) && 27 | isSubtree(pRoot1->right, pRoot2->right); 28 | } else { 29 | return false; 30 | } 31 | } 32 | 33 | bool HasSubtree(TreeNode *pRoot1, TreeNode *pRoot2) { 34 | //递归出口1 即某一个子树的根结点为空的时候 35 | if (pRoot1 == NULL || pRoot2 == NULL) { 36 | return false; 37 | } 38 | //一共右三种 B是A的子树的情况 1.根结点开始相同 2.左子树开始相同 3.右子树开始相同 39 | return isSubtree(pRoot1, pRoot2) || 40 | HasSubtree(pRoot1->left, pRoot2) || 41 | HasSubtree(pRoot1->right, pRoot2); 42 | 43 | } -------------------------------------------------------------------------------- /经典算法练习题/L18二叉树的镜像.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-14. 3 | // 4 | 5 | /* 6 | *操作给定的二叉树,将其变换为源二叉树的镜像。 7 | * */ 8 | 9 | #include 10 | 11 | struct TreeNode { 12 | int val; 13 | struct TreeNode *left; 14 | struct TreeNode *right; 15 | 16 | TreeNode(int x) : 17 | val(x), left(NULL), right(NULL) { 18 | } 19 | }; 20 | 21 | void Mirror(TreeNode *pRoot) { 22 | if (pRoot == NULL) { 23 | return; 24 | } 25 | TreeNode *temp = NULL; 26 | temp = pRoot->left; 27 | pRoot->left = pRoot->right; 28 | pRoot->right = temp; 29 | Mirror(pRoot->left); 30 | Mirror(pRoot->right); 31 | } -------------------------------------------------------------------------------- /经典算法练习题/L19顺时针打印矩阵.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-16. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | vector printMatrix(vector > matrix) { 11 | vector res; 12 | int row = matrix.size(); 13 | int col = matrix[0].size(); 14 | 15 | if (row == 0 || col == 0) { 16 | return res; 17 | } 18 | /* 19 | * left right 20 | * 21 | * 1 2 3 4 top 22 | * 5 6 7 8 top+1 23 | * 9 10 11 12 bottom 24 | * 25 | * 26 | * 27 | * */ 28 | int top = 0,bottom = row - 1,left = 0,right = col-1; 29 | while(top <= bottom && left<= right){ 30 | for(int i = left ; i <= right ;++i){ 31 | res.push_back(matrix[top][i]); 32 | } 33 | for(int i = top + 1;i <= bottom ;++i){ 34 | res.push_back(matrix[i][right]); 35 | } 36 | for(int i = right - 1;i >= left && top < bottom ;--i){ 37 | res.push_back(matrix[bottom][i]); 38 | } 39 | for(int i = bottom -1;i > top && left < right;--i){ 40 | res.push_back(matrix[i][left]); 41 | } 42 | ++top; 43 | ++left; 44 | --bottom; 45 | --right; 46 | 47 | } 48 | return res; 49 | } -------------------------------------------------------------------------------- /经典算法练习题/L20包含min函数的栈.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-16. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | stack dataS, minS; 9 | int minV = 0x7fffffff; 10 | 11 | void push(int value) { 12 | if (value < minV) { 13 | minV = value; 14 | } 15 | dataS.push(value); 16 | minS.push(minV); 17 | 18 | 19 | } 20 | 21 | void pop() { 22 | dataS.pop(); 23 | minS.pop(); 24 | 25 | } 26 | 27 | int top() { 28 | return dataS.top(); 29 | } 30 | 31 | int min() { 32 | return minS.top(); 33 | } 34 | 35 | 36 | //int main() { 37 | // push(5); 38 | // push(3); 39 | // push(11); 40 | // push(1); 41 | // while (!dataS.empty()) { 42 | // printf("-->%d\t", dataS.top()); 43 | // dataS.pop(); 44 | // 45 | // } 46 | // while (!minS.empty()) { 47 | // printf("-->%d\t", minS.top()); 48 | // minS.pop(); 49 | // } 50 | // 51 | //} -------------------------------------------------------------------------------- /经典算法练习题/L21栈的压入弹出序列.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-16. 3 | // 4 | /*输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)*/ 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | bool IsPopOrder(vector pushV, vector popV) { 12 | if (popV.size() == 0 || popV.size() == 0 || popV.size() != pushV.size()) { 13 | return false; 14 | } 15 | stack s;//用一个栈模拟入栈过程 16 | int j = 0;//记录模拟入栈过程中popV中的元素的下标 17 | for (int i = 0; i < pushV.size(); ++i) { 18 | s.push(pushV[i]);//将入栈序列的元素入栈 19 | while (!s.empty() && s.top() == popV[j]) { 20 | s.pop(); 21 | j++; 22 | } 23 | } 24 | return s.empty(); 25 | } 26 | 27 | //int main(){ 28 | // vector push = {1,2,3,4,5}; 29 | // vector pop = {4,5,3,2,1}; 30 | // cout << IsPopOrder(push,pop)<< endl; 31 | // 32 | //} 33 | 34 | -------------------------------------------------------------------------------- /经典算法练习题/L22从上往下打印二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-25. 3 | // 4 | 5 | 6 | //题目:从上往下打印出二叉树的每个节点,同层节点从左至右打印。 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | struct TreeNode { 13 | int val; 14 | struct TreeNode *left; 15 | struct TreeNode *right; 16 | 17 | TreeNode(int x) : 18 | val(x), left(NULL), right(NULL) { 19 | } 20 | }; 21 | 22 | //解法:二叉树的层序遍历 23 | vector PrintFromTopToBottom(TreeNode *root) { 24 | vector res; 25 | queue queue; 26 | if (root == NULL) { 27 | return res; 28 | } 29 | queue.push(root);//根节点入队列 30 | while (!queue.empty()) { 31 | TreeNode *tempNode = queue.front();//弹出一个打印 32 | queue.pop(); 33 | res.push_back(tempNode->val); 34 | if (tempNode->left != NULL) { 35 | queue.push(tempNode->left); 36 | } 37 | if (tempNode->right != NULL) { 38 | queue.push(tempNode->right); 39 | } 40 | } 41 | return res; 42 | } -------------------------------------------------------------------------------- /经典算法练习题/L23二叉搜索树的后续遍历序列.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-25. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct TreeNode { 10 | int val; 11 | struct TreeNode *left; 12 | struct TreeNode *right; 13 | 14 | TreeNode(int x) : 15 | val(x), left(NULL), right(NULL) { 16 | } 17 | }; 18 | 19 | bool judge(vector &s, int left, int right) { 20 | if (left >= right) {//为什么大于等于有点问题 21 | return true; 22 | } 23 | int rootValue = s[right]; 24 | int i = left; 25 | //找到第一个比根结点大的元素下标i 26 | while (s[i] < rootValue) { 27 | i++; 28 | } 29 | int j = i; 30 | //从该处开始看是否都大于根节点 31 | while (j < right) { 32 | if (s[j] < rootValue) { 33 | return false; 34 | } 35 | j++; 36 | } 37 | //看左\右子树是否满足要求 38 | return judge(s, left, i - 1) && judge(s, i, right - 1); 39 | } 40 | 41 | bool VerifySquenceOfBST(vector sequence) { 42 | if (sequence.size() == 0) { 43 | return false; 44 | } 45 | return judge(sequence, 0, sequence.size() - 1); 46 | 47 | } -------------------------------------------------------------------------------- /经典算法练习题/L24二叉树中和为某一值的路径.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2020-01-25. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct TreeNode { 11 | int val; 12 | struct TreeNode *left; 13 | struct TreeNode *right; 14 | 15 | TreeNode(int x) : 16 | val(x), left(NULL), right(NULL) { 17 | } 18 | }; 19 | 20 | vector> res; 21 | vector path; 22 | 23 | //表面是find 其实是DFS 24 | void find(TreeNode *root, int sum) { 25 | if (root == NULL) {//递归出口 26 | return; 27 | } 28 | 29 | path.push_back(root->val);//根节点 入 集合 30 | 31 | if (!root->left && !root->right && sum == root->val) {//仅有根节点且根结点等于和的特殊情况or到达叶子节点 32 | res.push_back(path); 33 | 34 | } else { 35 | if (root->left) { 36 | //看左子树的是否可以凑成 sum - 根结点的值 37 | find(root->left, sum - root->val); 38 | } 39 | if (root->right) { 40 | //看右子树的是否可以凑成 sum - 根结点的值 41 | find(root->right, sum - root->val); 42 | } 43 | } 44 | path.pop_back();//若上述都不满足则回溯到上一个结点 45 | } 46 | 47 | vector> FindPath(TreeNode *root, int expectNumber) { 48 | find(root, expectNumber); 49 | return res; 50 | } -------------------------------------------------------------------------------- /经典算法练习题/L25复杂链表的复制.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-26. 3 | // 4 | 5 | /*输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)*/ 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | struct RandomListNode { 12 | int label; 13 | struct RandomListNode *next, *random; 14 | 15 | RandomListNode(int x) : 16 | label(x), next(NULL), random(NULL) { 17 | } 18 | }; 19 | 20 | RandomListNode *Clone(RandomListNode *pHead) { 21 | if (pHead == NULL) { 22 | return NULL; 23 | } 24 | //第一步: 在当前链表中复制每一个结点(仅复制值 不复制random指针) 25 | RandomListNode *cp = pHead;//临时指针 26 | while (cp) { 27 | RandomListNode *newNode = new RandomListNode(cp->label);//复制一个当前结点 28 | //链接到当前结点的后面 29 | newNode->next = cp->next; 30 | cp->next = newNode; 31 | 32 | cp = newNode->next;//移动到下一个要复制的结点 33 | } 34 | //第二步 :为新加入的结点的random指针复制 35 | cp = pHead; 36 | while (cp) { 37 | RandomListNode *copyNodePoint = cp->next; 38 | if (cp->random) { 39 | copyNodePoint->random = cp->random->next;//加next的目的是让复制的结点random指向复制的结点而不是原来的结点 40 | 41 | } 42 | cp = copyNodePoint->next;//移动到下一个要复制的结点 43 | } 44 | //第三步: 拆分成两个链表 45 | RandomListNode *pCloneHead = pHead->next;//保存表头 46 | RandomListNode *tmp; 47 | cp = pHead; 48 | while (cp->next) { 49 | tmp = cp->next; 50 | cp->next = tmp->next; 51 | cp = tmp;//移动到下一个结点 52 | } 53 | return pCloneHead; 54 | } -------------------------------------------------------------------------------- /经典算法练习题/L26二叉搜索树与双向链表.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-26. 3 | // 4 | 5 | 6 | /*输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。*/ 7 | 8 | #include 9 | 10 | struct TreeNode { 11 | int val; 12 | struct TreeNode *left; 13 | struct TreeNode *right; 14 | 15 | TreeNode(int x) : 16 | val(x), left(NULL), right(NULL) { 17 | } 18 | }; 19 | 20 | TreeNode *head = NULL; 21 | TreeNode *point = NULL; 22 | 23 | TreeNode *Convert(TreeNode *pRootOfTree) { 24 | if (pRootOfTree == NULL) { 25 | return NULL; 26 | } 27 | Convert(pRootOfTree->left); 28 | if (head == NULL) {//到达最左子树可以确定头结点 29 | head = pRootOfTree; 30 | point = pRootOfTree; 31 | } else {//链接中序列 32 | point->right = pRootOfTree; 33 | pRootOfTree->left = point; 34 | point = point->right; 35 | } 36 | Convert(pRootOfTree->right); 37 | return head; 38 | } -------------------------------------------------------------------------------- /经典算法练习题/L27字符串的排列.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-26. 3 | // 4 | 5 | //输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | 12 | void swap(char &fir, char &sec) { 13 | char temp = fir; 14 | fir = sec; 15 | sec = temp; 16 | } 17 | 18 | void Permutation(string str, vector &result, int begin) { 19 | if (begin == str.size() - 1) { 20 | if (find(result.begin(), result.end(), str) == result.end()) { 21 | // 如果result中不存在str,才添加;避免aa和aa重复添加的情况 22 | result.push_back(str); 23 | } 24 | } else { 25 | for (int i = begin; i < str.size(); ++i) { 26 | swap(str[i], str[begin]); 27 | Permutation(str, result, begin + 1); 28 | swap(str[i], str[begin]); // 复位,用以恢复之前字符串顺序,达到第一位依次跟其他位交换的目的 29 | } 30 | } 31 | } 32 | 33 | vector Permutation(string str) { 34 | vector res; 35 | if (str.empty()) { 36 | return res; 37 | } 38 | Permutation(str, res, 0); 39 | sort(res.begin(), res.end()); 40 | return res; 41 | } -------------------------------------------------------------------------------- /经典算法练习题/L28数组中出现次数超过一半的数字.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-26. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | int MoreThanHalfNum_Solution(vector numbers) { 11 | 12 | 13 | int size = numbers.size() / 2; 14 | sort(numbers.begin(), numbers.end());//排序 15 | for (int i = 0; i + size < numbers.size(); i++) { 16 | if (numbers[i] == numbers[i + size]) 17 | return numbers[i]; 18 | } 19 | return 0; 20 | } 21 | 22 | 23 | //或者使用map 24 | 25 | 26 | 27 | int MoreThanHalfNum_Solution2(vector numbers) { 28 | map numbersMap; 29 | for(int i=0;i::iterator it = numbersMap.begin(); it != numbersMap.end(); it++) { 36 | if(max<(it->second)){ 37 | number=it->first; 38 | } 39 | } 40 | return number; 41 | } -------------------------------------------------------------------------------- /经典算法练习题/L29最小的K个数.cpp: -------------------------------------------------------------------------------- 1 | //// 2 | //// Created by HappyBing on 2020-01-26. 3 | //// 4 | // 5 | ////输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 6 | // 7 | // 8 | //#include 9 | //#include 10 | //#include 11 | //#include 12 | // 13 | //using namespace std; 14 | // 15 | // 16 | //vector GetLeastNumbers_Solution(vector input, int k) { 17 | // priority_queue Q;//当成堆来用 18 | // vector res; 19 | // if (input.size() < k || k <= 0) {//特殊情况 20 | // return res; 21 | // } 22 | // 23 | // for (int i = 0; i < input.size(); ++i) { 24 | // //将最小堆k个元素进入堆 25 | // if (Q.size() < k) { 26 | // Q.push(input[i]); 27 | // } else if (input[i] < Q.top()) { 28 | // Q.pop(); 29 | // Q.push(input[i]); 30 | // } 31 | // } 32 | // while (!Q.empty()) { 33 | // res.push_back(Q.top()); 34 | // Q.pop(); 35 | // } 36 | // return res; 37 | // 38 | //} 39 | // 40 | //int main() { 41 | // vector input = {4, 5, 1, 6, 2, 7, 3, 8}; 42 | // for (int x : input) { 43 | // cout << x << endl; 44 | // } 45 | // return 0; 46 | //} -------------------------------------------------------------------------------- /经典算法练习题/L30连续数组的最大和.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-01-26. 3 | // 4 | 5 | /* 6 | * 7 | *HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。 8 | * 今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。 9 | * 但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2}, 10 | * 连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) 11 | * */ 12 | 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace std; 21 | 22 | int FindGreatestSumOfSubArray1(vector array) { 23 | if (array.size() == 0) { 24 | return 0; 25 | } 26 | int total = array[0]; 27 | int maxSum = array[0];//记录最大值 28 | for (int i = 1; i < array.size(); ++i) {//遍历整个数组 29 | if (total >= 0) { 30 | total += array[i]; 31 | } else { 32 | total = array[i]; 33 | } 34 | 35 | if (total > maxSum) { 36 | maxSum = total; 37 | } 38 | 39 | } 40 | return maxSum; 41 | 42 | } 43 | 44 | 45 | 46 | // 解法2 动态规划 47 | 48 | 49 | int getMax(int a, int b) //得到两个数的最大值 50 | { 51 | return (a) > (b) ? (a) : (b); 52 | } 53 | 54 | int FindGreatestSumOfSubArray(vector array) { 55 | if (array.size() == 0) { 56 | return 0; 57 | } 58 | 59 | int res = array[0]; 60 | int max = array[0]; 61 | for (int i = 1; i < array.size(); ++i) { 62 | max = getMax(max + array[i], array[i]);//核心 看加上之后变大 若还不如加的数字大则取加的数组作为遍历到i的和 63 | res = getMax(max, res);//取较大的作为最终结果 64 | } 65 | return res; 66 | } -------------------------------------------------------------------------------- /经典算法练习题/L31从1到n中1出现的次数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-29. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int NumberOf1Between1AndN_Solution(int n) { 10 | if (!n) return 0; 11 | //n >= 1 12 | vector num; 13 | while (n) { 14 | num.push_back(n % 10); 15 | n /= 10; 16 | } 17 | 18 | int res = 0; 19 | for (int i = num.size() - 1; i >= 0; i--) { 20 | int left = 0, right = 0, x = 1; 21 | //高位到低位 left 22 | for (int j = num.size() - 1; j > i; j--) 23 | //计算低位 right 24 | for (int k = i - 1; k >= 0; k--) { 25 | right = right * 10 + num[k]; 26 | x *= 10; 27 | } 28 | 29 | //计算位数 30 | res = res + left * x; 31 | if (num[i] == 1) res += right + 1; //若第i位出现了1 ,则因为第i位为1 1的个数增加了right + 1个 32 | else if (num[i] > 1) res += x;// 若第i为出现2-9 ,则第i位对1个数的影响是前面个数 33 | 34 | } 35 | return res; 36 | } -------------------------------------------------------------------------------- /经典算法练习题/L32把数组排列成最小的数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-07. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | string PrintMinNumber(vector nums) { 12 | vector str; 13 | for (int val : nums) 14 | str.push_back(to_string(val)); 15 | sort(str.begin(), str.end(), [](string a, string b) { 16 | return a + b < b + a; 17 | }); 18 | string ret = ""; 19 | for (string s : str) ret += s; 20 | return ret; 21 | } -------------------------------------------------------------------------------- /经典算法练习题/L33丑数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-01. 3 | // 4 | //把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。 5 | 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | int GetUglyNumber_Solution(int index) { 12 | if (index < 7) 13 | return index; 14 | 15 | vector array; 16 | int p2 = 0, p3 = 0, p5 = 0; 17 | int num = 1; 18 | array.push_back(num); 19 | while (array.size() < index) { 20 | num = min(min(array[p2]*2, array[p3]*3), array[p5]*5); 21 | if (array[p2] * 2 == num) 22 | p2++; 23 | if (array[p3] * 3 == num) 24 | p3++; 25 | if (array[p5] * 5 == num) 26 | p5++; 27 | array.push_back(num); 28 | } 29 | return num; 30 | } -------------------------------------------------------------------------------- /经典算法练习题/L34第一个只出现一次的字符.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-30. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | 10 | 11 | int FirstNotRepeatingChar(string str) { 12 | map mp; 13 | for(int i = 0; i < str.size(); ++i) 14 | mp[str[i]]++; 15 | for(int i = 0; i < str.size(); ++i){ 16 | if(mp[str[i]]==1) 17 | return i; 18 | } 19 | return -1; 20 | } -------------------------------------------------------------------------------- /经典算法练习题/L35数组中的逆序对.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-08. 3 | // 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Solution { 10 | private: 11 | const int kmod = 1000000007; 12 | public: 13 | int InversePairs(vector data) { 14 | int ret = 0; 15 | merge_sort__(data, 0, data.size() - 1, ret); 16 | return ret; 17 | } 18 | 19 | 20 | void merge_sort__(vector &arr, int l, int r, int &ret) { 21 | if (l >= r) { 22 | return; 23 | } 24 | 25 | int mid = l + ((r - l) >> 1); 26 | merge_sort__(arr, l, mid, ret); 27 | merge_sort__(arr, mid + 1, r, ret); 28 | merge__(arr, l, mid, r, ret); 29 | } 30 | 31 | void merge__(vector &arr, int l, int mid, int r, int &ret) { 32 | vector tmp(r - l + 1); 33 | int i = l, j = mid + 1, k = 0; 34 | 35 | while (i <= mid && j <= r) { 36 | if (arr[i] > arr[j]) { 37 | tmp[k++] = arr[j++]; 38 | // 奥妙之处 39 | ret += (mid - i + 1); 40 | ret %= kmod; 41 | } else { 42 | tmp[k++] = arr[i++]; 43 | } 44 | } 45 | 46 | while (i <= mid) { //左边有剩余的 47 | tmp[k++] = arr[i++]; 48 | } 49 | while (j <= r) { //右边有剩余的 50 | tmp[k++] = arr[j++]; 51 | } 52 | 53 | for (k = 0, i = l; i <= r; ++i, ++k) { //还原 54 | arr[i] = tmp[k]; 55 | } 56 | } 57 | }; -------------------------------------------------------------------------------- /经典算法练习题/两个链表的第一个公共结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-29. 3 | // 4 | #include 5 | struct ListNode { 6 | int val; 7 | struct ListNode *next; 8 | ListNode(int x) : 9 | val(x), next(NULL) { 10 | } 11 | }; 12 | 13 | ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { 14 | 15 | ListNode* p1 = pHead1; 16 | ListNode* p2 = pHead2; 17 | while(p1 != p2) { 18 | if(p1 != NULL) p1 = p1->next; 19 | if(p2 != NULL) p2 = p2->next; 20 | if(p1 != p2) { 21 | if(p1 == NULL) p1 = pHead2; 22 | if(p2 == NULL) p2 = pHead1; 23 | } 24 | } 25 | return p1; 26 | 27 | } -------------------------------------------------------------------------------- /经典算法练习题/二叉搜索树的第k个结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-01. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | struct TreeNode { 9 | int val; 10 | struct TreeNode *left; 11 | struct TreeNode *right; 12 | TreeNode(int x) : 13 | val(x), left(NULL), right(NULL) { 14 | } 15 | }; 16 | void Inorder(TreeNode *pRoot, vector &vec); 17 | 18 | TreeNode *KthNode(TreeNode *pRoot, unsigned int k) { 19 | if (pRoot == NULL || k <= 0) return NULL; 20 | vector < TreeNode * > vec; 21 | Inorder(pRoot, vec); 22 | if (k > vec.size()) 23 | return NULL; 24 | return vec[k - 1]; 25 | } 26 | 27 | //中序遍历,将节点依次压入vector中 28 | void Inorder(TreeNode *pRoot, vector &vec) { 29 | if (pRoot == NULL) return; 30 | Inorder(pRoot->left, vec); 31 | vec.push_back(pRoot); 32 | Inorder(pRoot->right, vec); 33 | } -------------------------------------------------------------------------------- /经典算法练习题/二叉树的下一个结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-19. 3 | // 4 | 5 | /* 6 | * 7 | * 给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。 8 | * */ 9 | #include 10 | #include 11 | 12 | using namespace std; 13 | 14 | struct TreeLinkNode { 15 | int val; 16 | struct TreeLinkNode *left; 17 | struct TreeLinkNode *right; 18 | struct TreeLinkNode *next; 19 | 20 | TreeLinkNode(int x) : val(x), left(NULL), right(NULL), next(NULL) { 21 | 22 | } 23 | }; 24 | 25 | TreeLinkNode *firstInRightTree(TreeLinkNode *p) { 26 | // 找到某棵树最左孩子的办法 27 | TreeLinkNode *temp = p->right; 28 | while (temp->left != nullptr) 29 | temp = temp->left; 30 | return temp; 31 | 32 | } 33 | 34 | TreeLinkNode *GetNext(TreeLinkNode *pNode) { 35 | if (pNode == nullptr) 36 | return nullptr; 37 | if (pNode->right != nullptr) { 38 | return firstInRightTree(pNode); 39 | } else { 40 | // 若某结点为根的某棵子树的左孩子是pNode那么该结点就是pNode的下一个结点(即pNode->next)。 41 | while (pNode->next != nullptr && pNode->next->left != pNode) { 42 | pNode = pNode->next; 43 | } 44 | return pNode->next; 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /经典算法练习题/二叉树的深度.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-12. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | struct TreeNode { 9 | int val; 10 | struct TreeNode *left; 11 | struct TreeNode *right; 12 | TreeNode(int x) : 13 | val(x), left(NULL), right(NULL) { 14 | } 15 | }; 16 | int TreeDepth(TreeNode* pRoot) 17 | { 18 | if(pRoot == NULL){//根结点为空深度为0返回 19 | return 0; 20 | } 21 | return 1+max(TreeDepth(pRoot->right),TreeDepth(pRoot->left)); //此时根结点一定不为空,故深度至少为1,然后计算左子树和右字数的深度,选择最大的加起来则为整个树的深度 22 | } -------------------------------------------------------------------------------- /经典算法练习题/删除链表中重复的结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-06. 3 | // 4 | 5 | #include 6 | 7 | struct ListNode { 8 | int val; 9 | struct ListNode *next; 10 | ListNode(int x) : 11 | val(x), next(NULL) { 12 | } 13 | }; 14 | ListNode *deleteDuplication(ListNode *pHead) { 15 | ListNode *vhead = new ListNode(-1); // 新建头结点(为了方便得到新的链表头结点 16 | vhead->next = pHead; 17 | ListNode *pre = vhead, *cur = pHead; 18 | while (cur) { 19 | if (cur->next && cur->val == cur->next->val) { 20 | // cur = cur->next; 21 | while (cur->next && cur->val == cur->next->val) { 22 | cur = cur->next; 23 | } 24 | cur = cur->next; // 重复的一个都不保留 25 | pre->next = cur; 26 | } else { 27 | pre = cur; 28 | cur = cur->next; 29 | } 30 | } 31 | return vhead->next; 32 | } -------------------------------------------------------------------------------- /经典算法练习题/判断是否是平衡二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-28. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | struct TreeNode { 13 | int val; 14 | struct TreeNode *left; 15 | struct TreeNode *right; 16 | 17 | TreeNode(int x) : 18 | val(x), left(NULL), right(NULL) { 19 | } 20 | }; 21 | 22 | int TreeDepth(TreeNode *pRoot) { 23 | if (pRoot == NULL) {//根结点为空深度为0返回 24 | return 0; 25 | } 26 | return 1 + 27 | max(TreeDepth(pRoot->right), TreeDepth(pRoot->left)); //此时根结点一定不为空,故深度至少为1,然后计算左子树和右字数的深度,选择最大的加起来则为整个树的深度 28 | } 29 | 30 | bool IsBalanced_Solution(TreeNode *pRoot) { 31 | if (pRoot == nullptr) 32 | return true; 33 | return abs(TreeDepth(pRoot->left) - TreeDepth(pRoot->right)) <= 1; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /经典算法练习题/和为S的两个数字.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-01. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | // 输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。 11 | vector FindNumbersWithSum(vector array, int sum) { 12 | vector res; 13 | if (array.size() == 0) 14 | return res; 15 | int left = 0; 16 | int right = array.size() - 1; 17 | while (left < right) { 18 | if (array[left] + array[right] == sum) { 19 | res.push_back(array[left]); 20 | res.push_back(array[right]); 21 | break; 22 | } else if (array[left] + array[right] < sum) { 23 | left++; 24 | } else { 25 | right--; 26 | } 27 | } 28 | return res; 29 | } -------------------------------------------------------------------------------- /经典算法练习题/和为S的连续正数序列.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-01. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | vector > FindContinuousSequence(int sum) { 10 | int first = 1; 11 | int second = 2; 12 | vector > allRes; 13 | while (first < second) { 14 | int currSum = (first + second) * (second - first + 1) / 2; 15 | if (currSum < sum) { 16 | ++second; 17 | } else if (currSum > sum) 18 | { 19 | ++first; 20 | } else{ 21 | vector oneRes; 22 | for(int i = first;i<=second;++i){ 23 | oneRes.push_back(i); 24 | } 25 | ++first; 26 | 27 | allRes.push_back(oneRes); 28 | } 29 | } 30 | return allRes; 31 | 32 | 33 | } -------------------------------------------------------------------------------- /经典算法练习题/字符流中第一个不重复的字符.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-02. 3 | // 4 | 5 | // 请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | 13 | class Solution { 14 | public: 15 | //Insert one char from stringstream 16 | string s; 17 | char hash[256] = {0}; 18 | 19 | void Insert(char ch) { 20 | s += ch; 21 | hash[ch]++; 22 | } 23 | 24 | //return the first appearence once char in current stringstream 25 | char FirstAppearingOnce() { 26 | 27 | int size = s.size(); 28 | for (int i = 0; i < size; ++i) { 29 | if (hash[s[i]] == 1) 30 | return s[i]; 31 | } 32 | return '#'; 33 | } 34 | 35 | }; -------------------------------------------------------------------------------- /经典算法练习题/孩子们的游戏.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-09. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Solution { 10 | public: 11 | int LastRemaining_Solution(int n, int m) { 12 | if (n <= 0) return -1; 13 | list kids; 14 | for (int i = 0; i < n; ++i) { 15 | kids.push_back(i); 16 | } 17 | int index = -1; //初始化为-1 18 | while (kids.size() > 1) { 19 | int count = 0; 20 | while (count < m) { 21 | count++; //数数 从0开始数到m-1 22 | index++; //记录当前数到的位置 23 | if (index == kids.size()) { 24 | index = 0; //已经数完一圈重新开始 25 | } 26 | } 27 | auto it = kids.begin(); 28 | std::advance(it, index); // 让it向后移动index个位置 29 | kids.erase(it); 30 | index--; 31 | } 32 | return kids.back(); 33 | } 34 | 35 | // 递归 36 | int LastRemaining_Solution2(int n, int m) { 37 | 38 | { 39 | if (n == 0) 40 | return -1; 41 | if (n == 1) 42 | return 0; 43 | else 44 | return (LastRemaining_Solution(n - 1, m) + m) % n; 45 | } 46 | } 47 | 48 | // 迭代 49 | int LastRemaining_Solution3(int n, int m) { 50 | if (n <= 0) return -1; 51 | int index = 0; 52 | for (int i = 2; i <= n; ++i) { 53 | index = (index + m) % i; 54 | } 55 | return index; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /经典算法练习题/对称的二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-15. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | struct TreeNode { 11 | int val; 12 | struct TreeNode *left; 13 | struct TreeNode *right; 14 | 15 | TreeNode(int x) : 16 | val(x), left(NULL), right(NULL) { 17 | } 18 | }; 19 | 20 | /* 21 | * 22 | * 递归算法,不是很完美 23 | * 24 | * 25 | * */ 26 | //bool isSame(TreeNode *left, TreeNode *right); 27 | //bool isSymmetrical(TreeNode *pRoot) { 28 | // if (pRoot == nullptr) 29 | // return true; 30 | // 31 | // return isSame(pRoot->left, pRoot->right); 32 | //} 33 | // 34 | //bool isSame(TreeNode *p1, TreeNode *p2) { 35 | // if (p1 == nullptr && p2 == nullptr) { 36 | // return true; 37 | // } 38 | // if (p1 == nullptr || p2 == nullptr) { 39 | // return false; 40 | // } 41 | // if(p1->val != p2->val) 42 | // return false; 43 | // return isSame(p1->left, p2->right) && 44 | // isSame(p2->left, p1->right); 45 | // 46 | // 47 | //} 48 | 49 | /* 50 | * 51 | * DFS 和 BFS遍历树 52 | * 栈 和 队列 53 | * 54 | * 55 | */ 56 | bool isSymmetrical(TreeNode *pRoot) { 57 | if (pRoot == nullptr) 58 | return true; 59 | queue q; 60 | q.push(pRoot->left); 61 | q.push(pRoot->right); 62 | while (!q.empty()) { 63 | TreeNode *p1 = q.front(); 64 | q.pop(); 65 | TreeNode *p2 = q.front(); 66 | q.pop(); 67 | if (p1 == nullptr && p2 == nullptr) { 68 | continue; 69 | } 70 | if (p1 == nullptr || p2 == nullptr) { 71 | return false; 72 | } 73 | if (p1->val != p2->val) { 74 | return false; 75 | } 76 | q.push(p1->left); 77 | q.push(p2->right); 78 | q.push(p1->right); 79 | q.push(p2->left); 80 | } 81 | return true; 82 | 83 | 84 | } 85 | // DFS仅仅是把队列换成了栈 86 | bool isSymmetrical2(TreeNode *pRoot) { 87 | if (pRoot == nullptr) 88 | return true; 89 | stack q; 90 | q.push(pRoot->left); 91 | q.push(pRoot->right); 92 | while (!q.empty()) { 93 | TreeNode *p1 = q.top(); 94 | q.pop(); 95 | TreeNode *p2 = q.top(); 96 | q.pop(); 97 | if (p1 == nullptr && p2 == nullptr) { 98 | continue; 99 | } 100 | if (p1 == nullptr || p2 == nullptr) { 101 | return false; 102 | } 103 | if (p1->val != p2->val) { 104 | return false; 105 | } 106 | q.push(p1->left); 107 | q.push(p2->right); 108 | q.push(p1->right); 109 | q.push(p2->left); 110 | } 111 | return true; 112 | 113 | 114 | } -------------------------------------------------------------------------------- /经典算法练习题/左旋转字符串.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-30. 3 | // 4 | 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | string LeftRotateString(string str, int n) { 11 | reverse(str.begin(), str.end()); // 1 2 3 a b c c b a 3 2 1 12 | reverse(str.begin(), str.begin() + str.size() - n); // abc321 13 | reverse(str.begin() + str.size() - n, str.end());// abc123 14 | return str; 15 | } -------------------------------------------------------------------------------- /经典算法练习题/巧妙两数相加.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-16. 3 | // 4 | /* 5 | * 两个二进制的相加结果是用一个异或门实现的; 6 | 两个二进制的进位结果是用一个与门来实现的。 7 | * 8 | * */ 9 | 10 | 11 | #include 12 | 13 | int Add(int num1, int num2) { 14 | int result, ans; 15 | do { 16 | result = num1 ^ num2; // 每一位相加 17 | ans = (num1 & num2) << 1; // 进位 18 | num1 = result; // 记录几位相加的结果 19 | num2 = ans; // 记录还剩几位 20 | } while (ans != 0); 21 | return result; 22 | } -------------------------------------------------------------------------------- /经典算法练习题/巧妙计算1加到n.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-13. 3 | // 4 | /* 求1+2+3+...+n 5 | * 要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。 6 | */ 7 | 8 | 9 | #include 10 | 11 | int Sum_Solution(int n) { 12 | int sum = n; 13 | sum && (sum += Sum_Solution(--n)); 14 | return sum; 15 | } 16 | 17 | // 算法思想:递归+短路&&计算.思路和下面的代码一样。利用逻辑与运算符的短路实现if0 return0 18 | int f(int n) { 19 | if (n == 0) { 20 | return 0; 21 | } 22 | return n + f(n - 1); 23 | } -------------------------------------------------------------------------------- /经典算法练习题/序列化二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-10. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | struct TreeNode { 10 | int val; 11 | struct TreeNode *left; 12 | struct TreeNode *right; 13 | 14 | TreeNode(int x) : 15 | val(x), left(NULL), right(NULL) { 16 | } 17 | }; 18 | 19 | // 基于先序遍历 20 | char *Serialize(TreeNode *root) { 21 | if (!root) { 22 | return "#"; 23 | } 24 | string res = to_string(root->val); //根结点添加到结果中 25 | res.push_back(','); // 添加分隔符 26 | char *left = Serialize(root->left); //递归左子树 27 | char *right = Serialize(root->right);//递归右子树 28 | // 拼接结果 29 | char *ret = new char[strlen(left) + strlen(right) + res.size()]; 30 | strcpy(ret, res.c_str()); 31 | strcat(ret, left); 32 | strcat(ret, right); 33 | return ret; 34 | 35 | } 36 | 37 | // 参数使用引用&, 以实现全局变量的目的 38 | TreeNode* deseri(char *&s) { 39 | if (*s == '#') { 40 | ++s; 41 | return nullptr; 42 | } 43 | 44 | // 构造根节点值 45 | int num = 0; 46 | while (*s != ',') { //字符串转为数字 47 | num = num * 10 + (*s - '0'); 48 | ++s; 49 | } 50 | ++s; 51 | // 递归构造树 52 | TreeNode *root = new TreeNode(num); 53 | root->left = deseri(s); 54 | root->right = deseri(s); 55 | 56 | return root; 57 | } 58 | 59 | TreeNode* Deserialize(char *str) { 60 | return deseri(str); 61 | } 62 | -------------------------------------------------------------------------------- /经典算法练习题/按层打印二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-17. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | using namespace std; 10 | struct TreeNode { 11 | int val; 12 | struct TreeNode *left; 13 | struct TreeNode *right; 14 | TreeNode(int x) : 15 | val(x), left(NULL), right(NULL) { 16 | } 17 | }; 18 | 19 | vector > Print(TreeNode *pRoot) { 20 | vector > res; 21 | if (pRoot == nullptr) 22 | return res; 23 | queue q; 24 | q.push(pRoot); 25 | while (!q.empty()) { 26 | long len = q.size(); 27 | vector lay; 28 | // 将每层的打印出来 29 | for (long i = 0; i < len; ++i) { 30 | // 弹出结点并打印 31 | TreeNode *pNode = q.front(); 32 | q.pop(); 33 | lay.push_back(pNode->val); 34 | //将后续的加进去 35 | if (pNode->left != nullptr) 36 | q.push(pNode->left); 37 | if (pNode->right != nullptr) 38 | q.push(pNode->right); 39 | } 40 | res.push_back(lay); 41 | } 42 | return res; 43 | 44 | } -------------------------------------------------------------------------------- /经典算法练习题/按照之字型打印二叉树.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-28. 3 | // 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | struct TreeNode { 11 | int val; 12 | struct TreeNode *left; 13 | struct TreeNode *right; 14 | 15 | TreeNode(int x) : 16 | val(x), left(NULL), right(NULL) { 17 | } 18 | }; 19 | 20 | vector > Print(TreeNode *pRoot) { 21 | vector > res; 22 | if (pRoot == nullptr) 23 | return res; 24 | queue q; 25 | int flag = 1; 26 | q.push(pRoot); 27 | while (!q.empty()) { 28 | unsigned long sizeOfQueue = q.size(); 29 | vector layer; 30 | for (int i = 0; i < sizeOfQueue; ++i) { 31 | TreeNode *temp = q.front(); 32 | q.pop(); 33 | layer.push_back(temp->val); 34 | if (temp->left) { 35 | q.push(temp->left); 36 | } 37 | if (temp->right) { 38 | q.push(temp->right); 39 | } 40 | } 41 | if (flag == 1) { 42 | res.push_back(layer); 43 | flag = 0; 44 | } else { 45 | reverse(layer.begin(),layer.end()); 46 | res.push_back(layer); 47 | flag = 1; 48 | } 49 | } 50 | return res; 51 | } -------------------------------------------------------------------------------- /经典算法练习题/数据流中的中位数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-05. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | 12 | priority_queue, less > p; //大顶堆 13 | priority_queue, greater > q; //小顶堆 14 | 15 | void Insert(int num) { 16 | //每次插入小顶堆的是当前大顶堆中最大的数 17 | //每次插入大顶堆的是当前小顶堆中最小的数 18 | //这样保证小顶堆中的数永远大于等于大顶堆中的数 19 | //中位数就可以方便地从两者的根结点中获取了 20 | 21 | if (p.empty() || num <= p.top()) 22 | p.push(num); 23 | else 24 | q.push(num); 25 | if (p.size() == q.size() + 2) { 26 | q.push(p.top()); 27 | p.pop(); 28 | } 29 | 30 | if (p.size() + 1 == q.size()) { 31 | p.push(q.top()); 32 | q.pop(); 33 | } 34 | 35 | } 36 | 37 | double GetMedian() { 38 | //当前为偶数个,则取小顶堆和大顶堆的堆顶元素求平均 当前为奇数个,则直接从小顶堆中取元素即可 39 | return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top(); 40 | } -------------------------------------------------------------------------------- /经典算法练习题/数组中只出现一次的数字.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-08. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | void FindNumsAppearOnce(vector data,int* num1,int *num2) { 10 | unordered_map mp; 11 | for (const int k : data) 12 | ++mp[k]; 13 | vector ret; 14 | for (const int k : data) { 15 | if (mp[k] == 1) { 16 | ret.push_back(k); 17 | } 18 | } 19 | *num1 = ret[0]; 20 | *num2 = ret[1]; 21 | } -------------------------------------------------------------------------------- /经典算法练习题/机器人的运动范围.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-06. 3 | // 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | class Solution { 10 | public: 11 | int digit_sum(int n) { 12 | int res = 0; 13 | while (n > 0) { 14 | res += n % 10; 15 | n /= 10; 16 | } 17 | return res; 18 | } 19 | 20 | int movingCount(int threshold, int rows, int cols) { 21 | vector> flag(rows, vector(cols)); 22 | int b = dfs(threshold, rows, cols, 0, 0, flag); 23 | return b; 24 | 25 | } 26 | 27 | int dfs(int threshold, int rows, int cols, int i, int j, vector> &flag) { 28 | if (i < 0 || j < 0 || i >= rows || j >= cols || (digit_sum(i) + digit_sum(j)) > threshold || 29 | flag[i][j]) {//访问越界 30 | return 0; 31 | } 32 | flag[i][j] = true; 33 | return 1 + dfs(threshold, rows, cols, i - 1, j, flag) + 34 | dfs(threshold, rows, cols, i + 1, j, flag) + 35 | dfs(threshold, rows, cols, i, j - 1, flag) + 36 | dfs(threshold, rows, cols, i, j + 1, flag); 37 | } 38 | }; -------------------------------------------------------------------------------- /经典算法练习题/构建数组乘积.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-06-02. 3 | // 4 | 5 | #include 6 | using namespace std; 7 | class Solution { 8 | public: 9 | vector multiply(const vector& A) { 10 | vector B(A.size(), 1); 11 | for (int i=1; i=0; --j) {// 上三角 16 | tmp *= A[j+1]; // right[i]用tmp代替 17 | B[j] *= tmp; 18 | } 19 | return B; 20 | } 21 | }; -------------------------------------------------------------------------------- /经典算法练习题/矩阵中的路径.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-05. 3 | // 4 | 5 | #include > 6 | bool dfs(char *matrix, int rows, int cols, int i, int j, bool *flag, char *str); 7 | bool hasPath(char *matrix, int rows, int cols, char *str) { 8 | bool res = 0; 9 | bool *flag = new bool[rows * cols]; 10 | memset(flag, 0, rows * cols); 11 | for (int i = 0; i < rows; ++i) { 12 | for (int j = 0; j < cols; ++j) { 13 | //bool *flag = (bool *)calloc(rows*cols, 1); 14 | res = dfs(matrix, rows, cols, i, j, flag, str);//1 15 | if (res) 16 | return res; 17 | } 18 | } 19 | delete[] flag; 20 | return res; 21 | } 22 | 23 | bool dfs(char *matrix, int rows, int cols, int i, int j, bool *flag, char *str) { 24 | if (*str == '\0') 25 | return true; 26 | if (i < 0 || i >= rows || j < 0 || j >= cols) // 越界了 27 | return false; 28 | if (*(flag + i * cols + j) == 1 || (*(flag + i * cols + j) == 0 && *(matrix + i * cols + j) != *str)) 29 | return false; 30 | else { 31 | *(flag + i * cols + j) = 1; //已访问 32 | bool res = dfs(matrix, rows, cols, i, j - 1, flag, str + 1)//左 33 | || dfs(matrix, rows, cols, i, j + 1, flag, str + 1)//右 34 | || dfs(matrix, rows, cols, i - 1, j, flag, str + 1)//上 35 | || dfs(matrix, rows, cols, i + 1, j, flag, str + 1);//下 36 | if (res == 0) 37 | *(flag + i * cols + j) = 0;//这样从1处开始进入的DFS即使没找到路径,但是flag最后全部置为0 38 | return res; 39 | } 40 | } -------------------------------------------------------------------------------- /经典算法练习题/统计一个数字在排序数组中出现的次数.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-20. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | using namespace std; 9 | // 时间复杂度O(n) 10 | int GetNumberOfK(vector data, int k) { 11 | int num = 0; 12 | for (int i = 0; i < data.size(); ++i) { 13 | if (data[i] == k) 14 | num++; 15 | if (data[i] > k) 16 | break; 17 | } 18 | return num; 19 | } 20 | // 时间复杂度O(logn) 21 | int GetNumberOfK1(vector data, int k) { 22 | 23 | auto l = lower_bound(data.begin(), data.end(), k); 24 | auto r = upper_bound(data.begin(), data.end(), k); 25 | return r - l; 26 | } -------------------------------------------------------------------------------- /经典算法练习题/翻转单词顺序序列.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by newLion on 2020-06-10. 3 | // 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | string ReverseSentence(string str) { 10 | if (str.empty()) 11 | return str; 12 | int i = 0, sz = str.size(); 13 | while (i < sz && str[i] == ' ') ++i; 14 | if (i == sz) 15 | return str; 16 | 17 | 18 | string ret = ""; //结果数组 19 | string tmp = ""; //临时结果 20 | bool hasstr = false; 21 | for (int i = sz - 1; i >= 0; --i) { 22 | // 合并一个单词 23 | if (str[i] != ' ') { 24 | tmp = str[i] + tmp;; 25 | hasstr = true; 26 | } 27 | // 找到一个单词,将单词合并到结果串中 28 | else if (str[i] == ' ' && hasstr) { 29 | ret = ret + tmp + " "; 30 | tmp = ""; 31 | hasstr = false; 32 | } 33 | } 34 | if (tmp != "") 35 | ret += tmp; 36 | return ret; 37 | 38 | } -------------------------------------------------------------------------------- /经典算法练习题/链表中环的入口结点.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2020-05-19. 3 | // 4 | 5 | #include 6 | #include 7 | using namespace std; 8 | struct ListNode { 9 | int val; 10 | struct ListNode *next; 11 | 12 | ListNode(int x) : 13 | val(x), next(NULL) { 14 | } 15 | }; 16 | 17 | // 快慢指针 时间复杂度O(n) 空间复杂度O(1) 18 | ListNode *EntryNodeOfLoop(ListNode *pHead) { 19 | if (pHead == nullptr) 20 | return nullptr; 21 | ListNode *slow = pHead; 22 | ListNode *fast = pHead; 23 | // 判断快指针是否能走两步 ,若不能走两步则一定无环,同时快的能走两步慢的一定可以走一步 24 | while(fast != nullptr && fast->next != nullptr){ 25 | fast = fast->next->next; 26 | slow = slow->next; 27 | // 定理:快慢相等了 则一定存在环 28 | if(fast == slow){ 29 | fast = pHead; // 将随便一个指针重置到头结点 30 | while(fast != slow){// 每次走一步 只要相等了那么此处就是交汇点 31 | fast = fast->next; 32 | slow = slow->next; 33 | } 34 | return fast; 35 | } 36 | } 37 | return nullptr; 38 | } 39 | 40 | // 利用set的特性~时间复杂度O(nlogn) 空间复杂度O(n) 41 | ListNode *EntryNodeOfLoop1(ListNode *pHead) { 42 | set < ListNode * > s; 43 | ListNode *node = pHead; 44 | while (node != NULL) { 45 | if (s.insert(node).second) 46 | node = node->next; 47 | else 48 | return node; 49 | } 50 | return node; 51 | 52 | } -------------------------------------------------------------------------------- /经典算法练习题/默写-快速排序.cpp: -------------------------------------------------------------------------------- 1 | //// 2 | //// Created by HappyBing on 2020-02-14. 3 | //// 4 | // 5 | // 6 | // 7 | //#include 8 | // 9 | //// 5 1 2 3 4 5 5 9 8 10 | //int partition(int arr[], int left, int right) { 11 | // int temp = arr[left]; 12 | // while (left < right) { 13 | // while (left < right && temp <= arr[right]) { 14 | // right--; 15 | // } 16 | // arr[left] = arr[right]; 17 | // while (left < right && temp >= arr[left]) { 18 | // left++; 19 | // } 20 | // arr[right] = arr[left]; 21 | // } 22 | // arr[left] = temp; 23 | // return left; 24 | //} 25 | // 26 | //void quickSort(int arr[], int left, int right) { 27 | // if (left < right) { 28 | // int pos = partition(arr, left, right); 29 | // quickSort(arr, left, pos - 1); 30 | // quickSort(arr, pos + 1, right); 31 | // } 32 | //} 33 | // 34 | //int main(){ 35 | // int arr[10] = {1,11,-1,30,88,111,-11,1,2,3}; 36 | // quickSort(arr,0,9); 37 | // for(int x:arr){ 38 | // printf("%d\t",x); 39 | // } 40 | //} -------------------------------------------------------------------------------- /考研算法真题/2010算法题.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-10-23. 3 | // 4 | 5 | 6 | #include 7 | 8 | /* 9 | * 此问题相当于将数组的元素逆序问题的升级版 10 | * 11 | * 解法1:最优解 12 | * 思想:若循环左移动p位,则在p的位置将数组分为两部分 13 | * 将左边的一部分逆序 14 | * 将有边的一部分逆序 15 | * 最后将整个数组逆序 16 | * 时间复杂度:O(n) 17 | * 空间复杂度:O(1) 18 | * 19 | * 20 | * 解法2:暴力算法 21 | * 复制出一个数组,直接分成两部分,将左边的部分放到右边。右边的部分放到左边 22 | * 时间复杂度:O(n) 23 | * 空间复杂度:O(n) 24 | * */ 25 | 26 | void reverse(int a[], int left, int right) { 27 | int i, j; 28 | for (i = left, j = right; i <= j; ++i, --j) { 29 | int temp = a[i]; 30 | a[i] = a[j]; 31 | a[j] = temp; 32 | } 33 | } 34 | 35 | void moveP(int a[], int n, int p) { 36 | reverse(a, 0, p - 1); 37 | reverse(a, p, n - 1); 38 | reverse(a, 0, n - 1); 39 | } 40 | 41 | int main() { 42 | int a[5] = {0, 1, 2, 3, 4}; 43 | moveP(a, 5, 2); 44 | 45 | //我偷懒六用的for-in遍历 c不支持 请使用下标遍历 46 | for (int x : a) { 47 | printf("%d\t", x); 48 | } 49 | 50 | return 0; 51 | } -------------------------------------------------------------------------------- /考研算法真题/2011算法题.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-10-18. 3 | // 4 | 5 | /* 6 | * 7 | *2011年算法题: 8 | * 9 | * 最优解好难想啊😢 10 | * 提供一个O(n)的简单思路,双指针问题。将两个元素比较大小,谁小移动谁的指针 11 | * 同时记录移动次数,根据情况返回当前指针所指向的位置的数值。 12 | * 13 | * O(logN)的算法是王道上的答案,这道题也是《算法导论》上的一道题 14 | * 15 | * */ 16 | #include 17 | 18 | //该算法可以写成递归版的更加简洁 但不好理解 所以还是抄王道的吧 😂 19 | bool findMidOlogN(int A[], int B[], int len, int &mid) { 20 | int a_left = 0, a_right = len - 1, a_m, b_left = 0, b_right = len - 1, b_m; 21 | 22 | while (a_left != a_right || b_left != b_right) { 23 | a_m = (a_left + a_right) / 2; 24 | b_m = (b_left + b_right) / 2; 25 | if (A[a_m] == B[b_m]) { 26 | mid = A[a_m]; 27 | return true; 28 | } else if (A[a_m] < B[b_m]) {//A数组的中为谁%d", mid); 93 | return 0; 94 | } -------------------------------------------------------------------------------- /考研算法真题/2013算法题.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-10-14. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* 11 | * 12 | * 2013年算法题 13 | * 14 | * 15 | * 理解题意:统计数组重复元素个数,若有元素出现的次数>n/2则返回它,否则返回-1 16 | * 17 | * 个人思路:和2018年有些类似,种树法,与王道解答不同 18 | * 19 | * 1。新建一个长度为n的辅助数组assist,用于每个记录元素出现的个数 20 | * 2。遍历A数组,每出现一个元素则在assist数组中把以该数组元素值为下标的记录+1 21 | * 3。遍历assist数组,找到出现元素次数最多的元素,返回 22 | * 4。若出现次数>n/2,则返回该元素位于assist数组中的下标,否则返回-1 23 | * 24 | * 时间复杂度:O(n) 空间复杂度O(n) (王道的算法空间复杂度较好但是紧张时候可能想不到。 25 | * */ 26 | 27 | //寻找主元素,若找到则返回之,否则返回-1 28 | int findMainElem(int A[], int n) { 29 | 30 | //建立一个数组长度岁n动态变化的初始值为0的辅助数组 31 | int *assist;//建立辅助数组的指针 32 | assist = (int *) malloc(sizeof(int) * n);//动态分配内存空间 33 | memset(assist, 0, sizeof(int) * n);//赋予初值0 34 | 35 | //遍历A 统计出现频率 36 | for (int i = 0; i < n; ++i) { 37 | assist[A[i]] += 1;//出现次数+1 38 | } 39 | int max = 0;//记录assist最大值 40 | int max_index = -1;//记录assist最大值的下标 41 | //遍历assist数组寻找最大值 42 | for (int i = 0; i < n; ++i) { 43 | if (assist[i] > max) { 44 | max = assist[i]; 45 | max_index = i; 46 | } 47 | } 48 | //比较最大值是否>n/2 (这里隐含了向上取整) 49 | if (max > ceil(n / 2)) { 50 | return max_index; 51 | } 52 | 53 | return -1; 54 | } 55 | 56 | int main() { 57 | int A[8] = {0, 5, 5, 3, 5, 1, 5, 5}; 58 | printf("主元素-->%d", findMainElem(A, 8)); 59 | return 0; 60 | } -------------------------------------------------------------------------------- /考研算法真题/2014算法题.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by HappyBing on 2019-11-03. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | typedef struct TreeNode { 11 | struct TreeNode *left, *right; 12 | int weight; 13 | } *Tree; 14 | 15 | 16 | //王道上给的答案繁琐至极 考试中估计肯定写不出来 17 | //提高一种利用递归计算wpl的算法,十分好理解,并且好写 18 | int WPL(Tree tree, int depth) { 19 | if (tree == NULL) { 20 | return 0; 21 | } 22 | if (tree->left == NULL && tree->right == NULL) { 23 | return (tree->weight * depth);//已经到叶子结点了:返回本层的wpl 24 | } else { 25 | return (tree->weight * depth) + 26 | (WPL(tree->left, depth + 1) + WPL(tree->right, depth + 1));//返回本层wpl+左右子树的wpl 27 | } 28 | } 29 | 30 | 31 | 32 | 33 | 34 | 35 | int main() { 36 | //暴力建立一棵简单的🌲 (一般闲的蛋疼才这样建树 37 | 38 | Tree tree; 39 | tree = (TreeNode *) malloc(sizeof(TreeNode)); 40 | TreeNode *t1 = (Tree) malloc(sizeof(TreeNode)); 41 | TreeNode *t2 = (Tree) malloc(sizeof(TreeNode)); 42 | TreeNode *t3 = (Tree) malloc(sizeof(TreeNode)); 43 | tree->weight = 1; 44 | t1->weight = 2; 45 | t2->weight = 3; 46 | t3->weight = 4; 47 | tree->left = t1; 48 | tree->right = t2; 49 | t1->left = t3; 50 | t1->right = NULL; 51 | t2->left = NULL; 52 | t2->right = NULL; 53 | t3->left = NULL; 54 | t3->right = NULL; 55 | 56 | 57 | 58 | /* 59 | * 60 | * 61 | * 树涨这样 62 | * 1 63 | * 2 3 64 | * 4 65 | * 66 | * 67 | * */ 68 | 69 | //计算WPL的算法 70 | printf("\nWPL:%d\n", WPL(tree, 1)); 71 | return 0; 72 | } -------------------------------------------------------------------------------- /考研算法真题/2018算法题.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Newmor on 2019-10-12. 3 | // 4 | 5 | /* 6 | * 7 | * 2018年算法题 8 | * 9 | * 此题和leetcode某道题思想类似,采用 "种树法" 10 | * 此题怎么思路最重要,实现的话若给定数组数值范围不确定,则空间复杂度与具体算法实现有关,我的算法 11 | * 只能适用于给定的数在整数范围内。 12 | * 13 | * 思路: 14 | * 15 | * 1.新建一个辅助数组assist 长度为int的最大值2^31-1 16 | * 2。遍历整数数组,将得到值作为操作assist数组的下标,若该值大于0,则将对应下标元素赋值为1 17 | * 3。从1遍历assist数组 找到第一个为0的数组下标 18 | * 4。返回该下标 19 | * 20 | * 时间复杂度O(n) 空间复杂度为定值与n无关。 21 | * 22 | * */ 23 | #include 24 | #include 25 | #include 26 | 27 | #define INT_MAX 0x7fffffff 28 | 29 | int findMinPosInt(int array[], int n) { 30 | //返回值为未出现的正整数 31 | //若返回-1 则代表无法找到 32 | 33 | int *assist = (int *) malloc(sizeof(int) * INT_MAX);//建立辅助数组 34 | memset(assist, 0, sizeof(int) * n);//将其初始化为0 35 | 36 | //遍历题目所给数组 37 | for (int i = 0; i < n; ++i) { 38 | if (array[i] > 0) {//保证数据是正整数的同时避免下标越界 39 | assist[array[i]] = 1; 40 | } 41 | } 42 | //遍历辅助数组 43 | for (int i = 1; i <= INT_MAX; ++i) { 44 | if (assist[i] == 0) {//找到第一个数值为0的下标 45 | return i;//返回 46 | } 47 | } 48 | return -1;//若不存在则返回-1 49 | } 50 | 51 | int main() { 52 | int array[3] = {1, -2, 13}; 53 | printf("答案-->%d", findMinPosInt(array, 3)); 54 | } --------------------------------------------------------------------------------