├── .gitignore ├── .idea ├── copyright │ └── profiles_settings.xml ├── go-algorithms.iml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml └── workspace.xml ├── README.md ├── compression └── README.md ├── concurrence └── README.md ├── datastructure └── README.md ├── dp-problems.md ├── encrypt └── README.md ├── machinelearning └── README.md ├── optimization ├── README.md └── dp │ ├── README.md │ └── zero-onebag │ ├── bag_test.go │ └── zero-onebag.go ├── search └── README.md ├── sort ├── README.md ├── bubble │ ├── bubble.go │ └── bubble_test.go ├── bucket │ ├── bucket.go │ └── bucket_test.go ├── heap │ ├── heap.go │ └── heap_test.go ├── insertion │ ├── insertion.go │ └── insertion_test.go ├── main.go ├── merge │ ├── merge.go │ └── merge_test.go ├── quick │ ├── quick.go │ └── quick_test.go ├── selection │ ├── selection.go │ └── selection_test.go ├── shell │ ├── shell.go │ └── shell_test.go └── utils │ ├── IntegerArray.txt │ ├── RandIntGen.go │ └── helper.go └── utils ├── generator.go └── module ├── module.go └── module_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/go-algorithms.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 47 | 48 | true 49 | DEFINITION_ORDER 50 | 51 | 52 | 53 | 54 | 55 | 56 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | AngularJS 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 112 | 113 | 114 | 117 | 118 | 121 | 122 | 125 | 126 | 129 | 130 | 131 | 132 | 135 | 136 | 139 | 140 | 143 | 144 | 145 | 146 | 149 | 150 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 1487054897467 171 | 176 | 177 | 178 | 179 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 199 | 202 | 203 | 204 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 算法学习 Golang 版 - 探索算法始末 2 | ===================================== 3 | 4 | - [认识](#zero) 5 | - [算法](#four) 6 | - [结构](#three) 7 | - [数学原理](#one) 8 | - [其他常见问题](#two) 9 | 10 | ## 认识 11 | 1.数学研究最抽象的数与结构的量、量变及其关系,算法用它与逻辑来发现从具象的问题空间到解空间的逻辑映射。算法的思想就来自于数学、逻辑及求解的工具、方法与规律中。 12 | 13 | 2.算法本身与程序无关(更与编程语言无关),程序代码是算法的一种表示方式。 14 | 15 | 3.算法通过数据结构来封装数据及对数据的操作,并基于数据结构来实现算法过程(最简单例子就是算法过程中操作数组-别拿数组不当数据结构!)。有时数据结构本身的性质也能用于设计算法,如最大堆用于堆排序。 16 | 17 | 4.算法是基于问题的,每种算法有它自己的问题背景。但是有时一种算法的思想能借鉴应用到另一个问题的解决方式中。算法的设计过程即是一个如何解题的过程。 18 | 19 | ## 算法 20 | 按问题目标的类型划分 21 | 22 | - 排序 23 | - 插入排序 24 | - 直接插入排序(Insert Sort) O(n^2) 25 | - 折半插入排序(Binary Insert Sort) 26 | - 希尔排序(Shell Sort) 27 | 28 | - 交换排序 29 | - 冒泡排序(Bubble Sort) O(n^2) 30 | - 快速排序(Quick Sort)?? O(nlogn) 31 | 32 | - 选择排序 33 | - 直接选择排序(Select Sort) O(n^2) 34 | - 锦标赛排序(Tournament Sort) O(nlogn) 35 | - 堆排序(Heap Sort) O(nlogn) 36 | 37 | - 归并排序(Merge Sort) O(nlogn) 38 | 39 | - 基数排序(Radix Sort) O(d(n+radix)) 40 | 41 | - 桶排序(Bucket Sort) O(nlogn) 42 | 43 | - 查找/搜索 44 | 45 | - 二分查找(Binary Search) 46 | 47 | - 树型 48 | - 二叉搜索树(Binary Search Tree) 49 | - 平衡搜索树(AVL Tree) 50 | - 并查集(Union-Find Set) 51 | 52 | - 哈希(Hashing) 53 | 54 | - 最优化剪枝 55 | 56 | - 可行性剪枝 57 | 58 | - 记忆化搜索 59 | 60 | - 枚举搜索(Enumeration) 61 | 62 | - 深度优先(Depth First Search) 63 | 64 | - 广度优先(Breadth First Search) 65 | 66 | - 启发式搜索(Heuristic Search) 67 | 68 | - 压缩 69 | - 哈夫曼编码 70 | 71 | - 加密 72 | - 对称加密 73 | - AES 74 | - DES 75 | - RC4 76 | - 非对称加密 77 | - RSA 78 | - IDEA 79 | 80 | - 最优解 81 | - 递推 82 | - 递归(Recursion) 83 | - 贪心算法(Greedy) 84 | - 动态规划(DynamicProgram) 85 | - 随机搜索 86 | - 爬山法 87 | - 模拟退火法 88 | - 遗传算法 89 | 90 | - 并行 91 | 92 | 93 | - 机器学习 94 | - 回归算法 95 | - 最小二乘法(Ordinary Least Square) 96 | - 逻辑回归(Logistic Regression) 97 | - 逐步式回归(Stepwise Regression) 98 | - 多元自适应回归样条(Multivariate Adaptive Regression Splines) 99 | - 本地散点平滑估计(Locally Estimated Scatterplot Smoothing) 100 | - 基于实例的算法 101 | - k-Nearest Neighbor(KNN) 102 | - 学习矢量量化(Learning Vector Quantization, LVQ) 103 | - 自组织映射算法(Self-Organizing Map , SOM) 104 | - 正则化方法 105 | - Ridge Regression 106 | - Least Absolute Shrinkage and Selection Operator(LASSO) 107 | - 弹性网络(Elastic Net) 108 | - 决策树学习 109 | - 分类及回归树(Classification And Regression Tree, CART) 110 | - ID3 (Iterative Dichotomiser 3) 111 | - C4.5 112 | - Chi-squared Automatic Interaction Detection(CHAID) 113 | - Decision Stump 114 | - 随机森林(Random Forest) 115 | - 多元自适应回归样条(MARS) 116 | - 梯度推进机(Gradient Boosting Machine, GBM) 117 | - 贝叶斯方法 118 | - 朴素贝叶斯算法 119 | - 平均单依赖估计(Averaged One-Dependence Estimators, AODE) 120 | - Bayesian Belief Network(BBN) 121 | - 基于核的算法 122 | - 支持向量机(Support Vector Machine, SVM) 123 | - 径向基函数(Radial Basis Function ,RBF) 124 | - 线性判别分析(Linear Discriminate Analysis ,LDA) 125 | - 聚类算法 126 | - k-Means算法 127 | - 期望最大化算法(Expectation Maximization, EM) 128 | - 关联规则学习 129 | - Apriori算法 130 | - Eclat算法 131 | - 人工神经网络 132 | - 感知器神经网络(Perceptron Neural Network) 133 | - 反向传递(Back Propagation) 134 | - Hopfield网络 135 | - 学习矢量量化(Learning Vector Quantization, LVQ) 136 | - 深度学习 137 | - 受限波尔兹曼机(Restricted Boltzmann Machine, RBN) 138 | - Deep Belief Networks(DBN) 139 | - 卷积网络(Convolutional Network) 140 | - 堆栈式自动编码器(Stacked Auto-encoders) 141 | - 降低维度算法 142 | - 主成份分析(Principle Component Analysis, PCA) 143 | - 偏最小二乘回归(Partial Least Square Regression,PLS) 144 | - Sammon映射 145 | - 多维尺度(Multi-Dimensional Scaling, MDS) 146 | - 投影追踪(Projection Pursuit) 147 | - 集成算法 148 | - Boosting 149 | - Bootstrapped Aggregation(Bagging) 150 | - AdaBoost 151 | - 堆叠泛化(Stacked Generalization, Blending) 152 | 153 | ## 结构 154 | - 组织结构 155 | - 集合结构 156 | - 线性结构 157 | - 线性表(Linear List) 158 | - 栈(Stack) 159 | - 队列(Queue) 160 | - 数组(Array) 161 | - 串(String) 162 | - 广义表(General List) 163 | - 跳跃表 164 | - 树型结构 165 | - 树(Tree) 166 | - 胜者树 167 | - 左偏树 168 | - 二项树 169 | - 线段树 170 | - 后缀树 171 | - 哈夫曼树 172 | - trie树(静态建树、动态建树) 173 | - 静态二叉检索树 174 | - RMQ 175 | - 堆(Heap) 176 | 二叉堆 177 | 斜堆 178 | - 图型结构 179 | - 图(Graph) 180 | - trie图 181 | - 有限状态自动机 182 | - 统计结构 183 | - 树状数组 184 | - 虚二叉树 185 | - 线段树 186 | - 矩形面积并 187 | - 圆形面积并 188 | - 关系结构 189 | - Hash表 190 | - 并查集 191 | - 路径压缩思想 192 | 193 | ## 数学原理 194 | 195 | - 组合数学 196 | - 加法原理和乘法原理. 197 | - 排列组合 198 | - 容斥原理 199 | - 抽屉原理 200 | - 置换群与Polya定理 201 | - 递推关系和母函数 202 | - MoBius反演 203 | - 偏序关系理论 204 | - 数论 205 | - 素数与整除问题 206 | - 进制位 207 | - 同余模运算 208 | - 博奕论 209 | - 极大极小过程 210 | - Nim问题 211 | - 概率论 212 | - 数理统计 213 | - 运筹学 214 | - 计算几何学 215 | - 几何公式 216 | - 叉积和点积的运用(如线段相交的判定,点到线段的距离等) 217 | - 凸包 218 | - 坐标离散化. 219 | - 扫描线算法(例如求矩形的面积和周长并,常和线段树或堆一起使用). 220 | - 多边形的内核(半平面交) 221 | - 几何工具的综合应用 222 | - 半平面求交 223 | - 可视图的建立 224 | - 点集最小圆覆盖. 225 | - 对踵点 226 | 227 | ## 其他常见问题 228 | 按数学领域划分 229 | 230 | - 图论 231 | - 图的深度优先遍历和广度优先遍历. 232 | - 最短路径算法(dijkstra,bellman-ford,floyd,heap+dijkstra) 233 | - 最小生成树算法(prim,kruskal) 234 | - 拓扑排序 235 | - 二分图的最大匹配 (匈牙利算法) 236 | - 最大流的增广路算法(KM算法) 237 | - 度限制最小生成树和第K最短路. 238 | - 最优比率生成树. 239 | - 次小生成树. 240 | - 无向图、有向图的最小环 241 | - 差分约束系统的建立和求解 242 | - 最小费用最大流 243 | - 双连通分量 244 | - 强连通分支及其缩点 245 | - 图的割边和割点 246 | - 最小割模型、网络流规约 247 | 248 | - 动态规划 249 | - 四边形不等式理论 250 | - 函数的凸凹性 251 | - 规划方向 252 | - 旅行商问题 253 | - 最优二分检索树 254 | - 树型动态规划 255 | - 状态动态规划 256 | - 记录状态的动态规划 257 | - LCA(Least Common Ancestors),即最近公共祖先 258 | - RMQ(Range Minimum/Maximum Query),即区间最值查询 259 | - 最长子序列系列问题 260 | - 最长不下降子序列 261 | - 最长公共子序列 262 | - 最长公共不下降子序列 263 | - 不完全状态记录 264 | - 青蛙过河问题 265 | - 利用区间dp 266 | - 背包类问题 267 | - 0-1背包,经典问题 268 | - 无限背包,经典问题 269 | - 判定性背包问题 270 | - 带附属关系的背包问题 271 | - +-1背包问题 272 | - 双背包求最优值 273 | - 构造三角形问题 274 | - 带上下界限制的背包问题(012背包) 275 | - 线性的动态规划问题 276 | - 积木游戏问题 277 | - 决斗(判定性问题) 278 | - 圆的最大多边形问题 279 | - 统计单词个数问题 280 | - 棋盘分割 281 | - 日程安排问题 282 | - 最小逼近问题(求出两数之比最接近某数/两数之和等于某数等等) 283 | - 方块消除游戏(某区间可以连续消去求最大效益) 284 | - 资源分配问题 285 | - 数字三角形问题 286 | - 邮局问题与构造答案 287 | - 最高积木问题 288 | - 两段连续和最大 289 | - 2次幂和问题 290 | - N个数的最大M段子段和 291 | - 交叉最大数问题 292 | - 判定性问题的dp(如判定整除、判定可达性等) 293 | - 模K问题的dp 294 | - 特殊的模K问题,求最大(最小)模K的数 295 | - 变换数问题 296 | - 单调性优化的动态规划 297 | - 1-SUM问题 298 | - 2-SUM问题 299 | - 序列划分问题(单调队列优化) 300 | - 剖分问题(多边形剖分/石子合并/圆的剖分/乘积最大) 301 | - 凸多边形的三角剖分问题 302 | - 乘积最大问题 303 | - 多边形游戏(多边形边上是操作符,顶点有权值) 304 | - 石子合并(N^3/N^2/NLogN各种优化) 305 | - 贪心的动态规划 306 | - 最优装载问题 307 | - 部分背包问题 308 | - 乘船问题 309 | - 贪心策略 310 | - 双机调度问题Johnson算法 311 | - 状态dp 312 | - 牛仔射击问题(博弈类) 313 | - 哈密顿路径的状态dp 314 | - 两支点天平平衡问题 315 | - 一个有向图的最接近二部图 316 | - 树型dp 317 | - 完美服务器问题(每个节点有3种状态) 318 | - 小胖守皇宫问题 319 | - 网络收费问题 320 | - 树中漫游问题 321 | - 树上的博弈 322 | - 树的最大独立集问题 323 | - 树的最大平衡值问题 324 | - 构造树的最小环 325 | 326 | -------------------------------------------------------------------------------- /compression/README.md: -------------------------------------------------------------------------------- 1 | #压缩算法 -------------------------------------------------------------------------------- /concurrence/README.md: -------------------------------------------------------------------------------- 1 | #并行算法 -------------------------------------------------------------------------------- /datastructure/README.md: -------------------------------------------------------------------------------- 1 | #数据结构 -------------------------------------------------------------------------------- /dp-problems.md: -------------------------------------------------------------------------------- 1 | - 不完全状态记录 2 | - 青蛙过河问题 3 | - 利用区间dp 4 | - 背包类问题 5 | - 0-1背包,经典问题 6 | - 无限背包,经典问题 7 | - 判定性背包问题 8 | - 带附属关系的背包问题 9 | - +-1背包问题 10 | - 双背包求最优值 11 | - 构造三角形问题 12 | - 带上下界限制的背包问题(012背包) 13 | - 线性的动态规划问题 14 | - 积木游戏问题 15 | - 决斗(判定性问题) 16 | - 圆的最大多边形问题 17 | - 统计单词个数问题 18 | - 棋盘分割 19 | - 日程安排问题 20 | - 最小逼近问题(求出两数之比最接近某数/两数之和等于某数等等) 21 | - 方块消除游戏(某区间可以连续消去求最大效益) 22 | - 资源分配问题 23 | - 数字三角形问题 24 | - 漂亮的打印 25 | - 邮局问题与构造答案 26 | - 最高积木问题 27 | - 两段连续和最大 28 | - 2次幂和问题 29 | - N个数的最大M段子段和 30 | - 交叉最大数问题 31 | - 判定性问题的dp(如判定整除、判定可达性等) 32 | - 模K问题的dp 33 | - 特殊的模K问题,求最大(最小)模K的数 34 | - 变换数问题 35 | - 单调性优化的动态规划 36 | - 1-SUM问题 37 | - 2-SUM问题 38 | - 序列划分问题(单调队列优化) 39 | - 剖分问题(多边形剖分/石子合并/圆的剖分/乘积最大) 40 | - 凸多边形的三角剖分问题 41 | - 乘积最大问题 42 | - 多边形游戏(多边形边上是操作符,顶点有权值) 43 | - 石子合并(N^3/N^2/NLogN各种优化) 44 | - 贪心的动态规划 45 | - 最优装载问题 46 | - 部分背包问题 47 | - 乘船问题 48 | - 贪心策略 49 | - 双机调度问题Johnson算法 50 | - 状态dp 51 | - 牛仔射击问题(博弈类) 52 | - 哈密顿路径的状态dp 53 | - 两支点天平平衡问题 54 | - 一个有向图的最接近二部图 55 | - 树型dp 56 | - 完美服务器问题(每个节点有3种状态) 57 | - 小胖守皇宫问题 58 | - 网络收费问题 59 | - 树中漫游问题 60 | - 树上的博弈 61 | - 树的最大独立集问题 62 | - 树的最大平衡值问题 63 | - 构造树的最小环 64 | -------------------------------------------------------------------------------- /encrypt/README.md: -------------------------------------------------------------------------------- 1 | #加密算法 2 | 3 | - 定义: 4 | 数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 5 | 6 | - 数学表示: 7 | 一个加密系统S可以用数学符号描述如下: 8 | >S={P, C, K, E, D} 9 | 10 | 其中 11 | ``` 12 | P——明文空间,表示全体可能出现的明文集合, 13 | C——密文空间,表示全体可能出现的密文集合, 14 | K——密钥空间,密钥是加密算法中的可变参数, 15 | E——加密算法,由一些公式、法则或程序构成, 16 | D——解密算法,它是E的逆。 17 | ``` -------------------------------------------------------------------------------- /machinelearning/README.md: -------------------------------------------------------------------------------- 1 | #机器学习算法 -------------------------------------------------------------------------------- /optimization/README.md: -------------------------------------------------------------------------------- 1 | # 优化算法 2 | 3 | 其中`递推`、`递归(Recursion)`、`贪心算法(Greedy)`、`动态规划(DynamicProgram)`是以“相似或相同子问题”为核心的算法。 4 | 5 | # 递归通用模型 6 | 7 | ``` 8 | //通用模型 9 | func recurse() 10 | { 11 | 12 | //1递归的出口(隐含了递归的返回) 13 | 14 | //2递归的传递 15 | 16 | //3递归的处理 17 | 18 | } 19 | ``` 20 | 21 | 递归出口、递归处理、递归传递三者的顺序关系: 22 | 23 | - 递归的传递:保证递归分治思想,即把大问题划分为同等结构的子问题; 24 | 25 | - 递归出口: 26 | 确保递归传递的可穷尽性,所以肯定在递归传递之前;有返回型出口和逻辑型出口两种,返回型出口一定要注意返回值不要丢失,要谁调用返给谁。 27 | 28 | - 递归处理: 29 | 分而治之的“治”。递归的使用场景一般是上一层的结果的计算需要依赖下一层的结果,所以递归的处理一般在递归的传递之后(传递下去再返回才能进行这层的计算); -------------------------------------------------------------------------------- /optimization/dp/README.md: -------------------------------------------------------------------------------- 1 | #动态规划 2 | ##说明 3 | 动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度,因此它比回溯法、暴力法等要快许多。“递推公式”即“状态转移方程”——就是描述状态是怎么转移的方程,“状态”用来描述该问题的子问题的解。 4 | 5 | 动态规划一般由两种方法来实现,一种为自顶向下的备忘录方式,用递归实现,一种为自底向上的方式,用迭代实现。 6 | 7 | ##步骤 8 | 9 | 1、刻画一个最优解的结构特征。 10 | 11 | 2、递归地定义最优解的值。 12 | 13 | 3、计算最优解的值,通常采用自底向上的方法。 14 | 15 | 4、利用计算出的信息构造一个最优解。 16 | 17 | ##背包问题 18 | 19 | - `01背包`: 有N件物品和一个重量为M的背包。(每种物品均只有一件)第i件物品的重量是w[i],价值是p[i]。求解将哪些物品装入背包可使价值总和最大。 20 | 21 | - `完全背包`: 有N种物品和一个重量为M的背包,每种物品都有无限件可用。第i种物品的重量是w[i],价值是p[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包重量,且价值总和最大。 22 | 23 | - `多重背包`: 有N种物品和一个重量为M的背包。第i种物品最多有n[i]件可用,每件重量是w[i],价值是p[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包重量,且价值总和最大。 24 | 25 | -------------------------------------------------------------------------------- /optimization/dp/zero-onebag/bag_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | 测试数据: 3 | 5 10 4 | 4 9 5 | 3 6 6 | 5 1 7 | 2 4 8 | 5 1 9 | 4 9 10 | 4 20 11 | 3 6 12 | 4 20 13 | 2 4 14 | 5 10 15 | 2 6 16 | 2 3 17 | 6 5 18 | 5 4 19 | 4 6 20 | */ 21 | 22 | package zeroonebag 23 | 24 | import ( 25 | "fmt" 26 | "testing" 27 | ) 28 | 29 | func getTestArr() []map[string]int{ 30 | 31 | return []map[string]int{ 32 | map[string]int{"value":5,"weight":10}, 33 | map[string]int{"value":4,"weight":9}, 34 | map[string]int{"value":3,"weight":6}, 35 | map[string]int{"value":5,"weight":1}, 36 | map[string]int{"value":2,"weight":3}, 37 | map[string]int{"value":5,"weight":1}, 38 | map[string]int{"value":6,"weight":1}, 39 | map[string]int{"value":4,"weight":9}, 40 | map[string]int{"value":4,"weight":20}, 41 | map[string]int{"value":2,"weight":4}, 42 | map[string]int{"value":5,"weight":10}, 43 | map[string]int{"value":2,"weight":6}, 44 | map[string]int{"value":2,"weight":3}, 45 | map[string]int{"value":6,"weight":2}, 46 | map[string]int{"value":5,"weight":4}, 47 | map[string]int{"value":4,"weight":6}, 48 | } 49 | } 50 | func TestOneZeroBag(t *testing.T) { 51 | data := getTestArr() 52 | maxValue := run(data, 6) 53 | 54 | if maxValue != 22{ 55 | fmt.Printf("得到最大值%d,应为%d \n",maxValue,22) 56 | t.Error() 57 | } 58 | } -------------------------------------------------------------------------------- /optimization/dp/zero-onebag/zero-onebag.go: -------------------------------------------------------------------------------- 1 | /* 2 | zero-one bag 0-1背包问题 3 | 4 | 状态转移方程为d(i, j)=max{ d(i-1, j), d(i-1, j-V[i-1]) + W[i-1] }。 5 | 其中状态d(i-1, j)表示前i个宝石装到体积为j的背包里能达到的最大价值,V[i]和w[i]分别表示第i个宝石对应的体积和的价值。 6 | 7 | 迭代实现过程中的状态转移方程是运算过程的抽象,是种数学表示,故实现过程中的逻辑有时会不太显然。 8 | 但只要数学过程是正确的,则可保证运算过程的正确性 9 | */ 10 | package zeroonebag 11 | 12 | func max(first , second int) int{ 13 | if first > second {return first} 14 | 15 | return second 16 | } 17 | func run(stones []map[string]int, capacity int) int{ 18 | 19 | return recurse(stones, capacity) 20 | // return iterate(stones, capacity) 21 | } 22 | /* 23 | 迭代法 24 | */ 25 | func iterate(stones []map[string]int, capacity int) int{ 26 | bagCValues := []int{} 27 | //初始化状态,注意足够容量!——i <= capacity 28 | for i:=0;i<=capacity;i++{ 29 | bagCValues = append(bagCValues, 0) 30 | } 31 | 32 | for _,mapitem := range stones{//遍历宝石 33 | /* 34 | * 遍历容量空间,要注意的是capacityLast初始化值时capacity而非capacity-1 35 | * capacityLast语义是剩余容量,剩余容量可能为零也可能为最大容量! 36 | */ 37 | for capacityLast := capacity; capacityLast >= mapitem["weight"]; capacityLast--{ 38 | 39 | CurrentValue := bagCValues[capacityLast - mapitem["weight"]] + mapitem["value"] 40 | 41 | bagCValues[capacityLast] = max(bagCValues[capacityLast], CurrentValue) 42 | } 43 | } 44 | return bagCValues[len(bagCValues)-1] 45 | } 46 | /* 47 | 递归法 48 | */ 49 | func recurse(stones []map[string]int, capacity int) int{ 50 | length := len(stones) 51 | if length==0 || capacity==0 { 52 | return 0 53 | }else{ 54 | for stoneIndex := length-1;stoneIndex>=0;stoneIndex-- { 55 | if stones[stoneIndex]["weight"] > capacity{ 56 | return recurse(stones[:length-1],capacity) 57 | }else{ 58 | temp1:=recurse(stones[:length-1],capacity) 59 | temp2:=recurse(stones[:length-1],capacity-stones[stoneIndex]["weight"])+stones[stoneIndex]["value"] 60 | return max(temp2, temp1) 61 | } 62 | } 63 | } 64 | return 0 65 | } -------------------------------------------------------------------------------- /search/README.md: -------------------------------------------------------------------------------- 1 | # 查找/搜索 -------------------------------------------------------------------------------- /sort/README.md: -------------------------------------------------------------------------------- 1 | 排序: 2 | 将多个元素按照一定规则的顺序进行排列。 3 | 4 | 如: 5 | 数值排序 6 | 字母排序 7 | 优先级排序 8 | 9 | 分析: 10 | 排序则必有先后大小高低,基本操作是:将元素通过比较来调整位置。 11 | 12 | 排序本质是消除逆序。采用“交换相邻元素”的办法来消除逆序,每次正好只消除一个,因此必须执行O(N^2)的交换次数。 13 | 基于交换元素的排序要想突破这个下界,必须执行一些比较,交换相隔比较远的元素,使得一次交换能消除一个以上的逆序。这样才能降低时间复杂度。 -------------------------------------------------------------------------------- /sort/bubble/bubble.go: -------------------------------------------------------------------------------- 1 | /* 2 | # Bubble Sort 3 | 4 | Bubble sort is a sorting algorithm that is implemented by starting in the beginning of the array and swapping the first two elements only if the first element is greater than the second element. This comparison is then moved onto the next pair and so on and so forth. This is done until the array is completely sorted. The smaller items slowly “bubble” up to the beginning of the array. 5 | 6 | # Runtime: 7 | - Average: O(N^2) 8 | - Worst: O(N^2) 9 | 10 | # Memory: 11 | - O(1) 12 | */ 13 | package bubble 14 | 15 | // 冒泡排序 16 | func Sort(arr []int) { 17 | 18 | for first := len(arr) - 1; ; first-- { 19 | //终止条件,也可通过外层循环来控制 20 | continued := false 21 | 22 | for second := first - 1; second >= 0; second-- { 23 | continued = true 24 | if arr[first] < arr[second] { 25 | arr[second], arr[first] = arr[first], arr[second] 26 | } 27 | } 28 | if continued == false { 29 | break 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /sort/bubble/bubble_test.go: -------------------------------------------------------------------------------- 1 | package bubble 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestBubbleSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(100) 13 | 14 | Sort(list) 15 | 16 | for i := 0; i < len(list)-2; i++ { 17 | if list[i] > list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkBubbleSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkBubbleSort100(b *testing.B) { benchmarkBubbleSort(100, b) } 33 | func BenchmarkBubbleSort1000(b *testing.B) { benchmarkBubbleSort(1000, b) } 34 | func BenchmarkBubbleSort10000(b *testing.B) { benchmarkBubbleSort(10000, b) } 35 | func BenchmarkBubbleSort100000(b *testing.B) { benchmarkBubbleSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/bucket/bucket.go: -------------------------------------------------------------------------------- 1 | /* 2 | # bucket sort 桶排序 3 | 4 | 桶排序的基本思路是将数据根据计算规则来分组,并将数据依次分配到对应分组中。 5 | 分配时可能出现某分组里有多个数据,那么再进行分组内排序。 6 | 然后得到了有序分组,最后把它们依次取出来放到数组中即实现了整体排序。 7 | 8 | 此处分类即是桶,计算规则是 index = value * (n-1) /k, 9 | (n为数据个数即桶个数,k为使全部数据分布在k*[0,1]空间中的正整数,k可取数据最大值)。 10 | 桶本身等价于一个二维数组。 11 | 12 | 注意点:是在插入桶的时候还是在插入桶之后进行桶内排序呢?我觉得入桶后比较好, 13 | 因为入桶后可以从桶内整体出发进行桶内排序,而不用挨个比较 14 | 15 | 动画演示 https://www.cs.usfca.edu/~galles/visualization/BucketSort.html 16 | 17 | # runtime:k为桶数 18 | -Worst:O(n^2) 19 | -Best:Omega(n + k) 20 | -Average:Theta(n + k) 21 | 22 | # 稳定性 23 | 24 | */ 25 | package bucket 26 | 27 | // import "log" 28 | /* 29 | 桶内排序 30 | */ 31 | func sortInBucket(bucket []int) {//此处实现插入排序方式,其实可以用任意其他排序方式 32 | length := len(bucket) 33 | if length == 1 {return} 34 | 35 | for i := 1; i < length; i++ { 36 | backup := bucket[i] 37 | j := i -1; 38 | //将选出的被排数比较后插入左边有序区 39 | for j >= 0 && backup < bucket[j] {//注意j >= 0必须在前边,否则会数组越界 40 | bucket[j+1] = bucket[j]//移动有序数组 41 | j -- //反向移动下标 42 | } 43 | bucket[j + 1] = backup //插队插入移动后的空位 44 | } 45 | } 46 | /* 47 | 获取数组最大值 48 | */ 49 | func getMaxInArr(arr []int) int{ 50 | max := arr[0] 51 | for i := 1; i < len(arr); i++ { 52 | if arr[i] > max{ max = arr[i]} 53 | } 54 | return max 55 | } 56 | /* 57 | 桶排序 58 | */ 59 | func Sort(arr []int) []int { 60 | //桶数 61 | num := len(arr) 62 | //k(数组最大值) 63 | max := getMaxInArr(arr) 64 | //二维切片 65 | buckets := make([][]int, num) 66 | 67 | //分配入桶 68 | index := 0 69 | for i := 0; i < num; i++ { 70 | index = arr[i] * (num-1) /max//分配桶index = value * (n-1) /k 71 | 72 | buckets[index] = append(buckets[index], arr[i]) 73 | } 74 | //桶内排序 75 | tmpPos := 0 76 | for i := 0; i < num; i++ { 77 | bucketLen := len(buckets[i]) 78 | if bucketLen > 0{ 79 | sortInBucket(buckets[i]) 80 | 81 | copy(arr[tmpPos:], buckets[i]) 82 | 83 | tmpPos += bucketLen 84 | } 85 | } 86 | 87 | return arr 88 | } 89 | -------------------------------------------------------------------------------- /sort/bucket/bucket_test.go: -------------------------------------------------------------------------------- 1 | package bucket 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestBucketSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(100) 13 | 14 | Sort(list) 15 | 16 | for i := 0; i < len(list)-2; i++ { 17 | if list[i] > list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkBucketSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkBucketSort100(b *testing.B) { benchmarkBucketSort(100, b) } 33 | func BenchmarkBucketSort1000(b *testing.B) { benchmarkBucketSort(1000, b) } 34 | func BenchmarkBucketSort10000(b *testing.B) { benchmarkBucketSort(10000, b) } 35 | func BenchmarkBucketSort100000(b *testing.B) { benchmarkBucketSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/heap/heap.go: -------------------------------------------------------------------------------- 1 | /* 2 | # heap Sort 堆排序 3 | 4 | 利用“堆”这种数据结构来排序,分为最大堆、最小堆排序。堆是种完全二叉树,特点是父子有序兄弟无序(可能有序可能乱序)。 5 | 排序过程即循环构建堆并依次排列堆的根节点的过程。 6 | 7 | 关键过程为建堆、堆顶与无序区尾部叶子交换 8 | 9 | # Runtime: 10 | 11 | - Average: O(n lg n) 12 | - Worst: O(n lg n) 13 | - Best: O(n lg n) 14 | */ 15 | package heap 16 | // import "log" 17 | /* 18 | golang 自带 container/heap,此处是对固定类型的一种简单实现最大堆 19 | */ 20 | func BuildHeap(arr []int, length int){ 21 | if length == 1 { 22 | return 23 | } 24 | //最大非叶节点偏移量(序号为length / 2) 25 | maxBranch := length / 2 - 1 26 | //构造全部子树 27 | for i := maxBranch; i >= 0; i-- { 28 | //左孩子偏移量(序号为 2 * (length / 2)) 29 | lChild := 2 * i + 1 30 | //右孩子偏移量(序号为 2 * (length / 2) + 1) 31 | rChild := lChild + 1 32 | //临时最大值偏移量 33 | tmpMax := i 34 | 35 | // if rChild > length { break }//不可以,左孩子要与父结点比较 36 | 37 | //将三个节点构造成堆(父结点最大) 38 | if arr[lChild] > arr[tmpMax] {//左孩子不需判断是否溢出 39 | tmpMax = lChild 40 | } 41 | if rChild <= length -1 && arr[rChild] > arr[tmpMax] { 42 | tmpMax = rChild 43 | } 44 | if tmpMax != i { 45 | arr[i], arr[tmpMax] = arr[tmpMax], arr[i] 46 | } 47 | } 48 | } 49 | func Sort(arr []int) []int { 50 | 51 | length := len(arr) 52 | for i := 0; i < length; i++ { 53 | //将需要重新建堆的长度减短 54 | lastMessLen := length-i 55 | 56 | BuildHeap(arr, lastMessLen) 57 | //将堆顶(根节点)与无序区的最后叶子节点交换 58 | if i < length{ 59 | arr[0], arr[lastMessLen - 1] = arr[lastMessLen - 1],arr[0] 60 | } 61 | } 62 | return arr 63 | } -------------------------------------------------------------------------------- /sort/heap/heap_test.go: -------------------------------------------------------------------------------- 1 | package heap 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestHeapSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(100) 13 | 14 | Sort(list) 15 | 16 | for i := 0; i < len(list)-2; i++ { 17 | if list[i] > list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkHeapSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkHeapSort100(b *testing.B) { benchmarkHeapSort(100, b) } 33 | func BenchmarkHeapSort1000(b *testing.B) { benchmarkHeapSort(1000, b) } 34 | func BenchmarkHeapSort10000(b *testing.B) { benchmarkHeapSort(10000, b) } 35 | func BenchmarkHeapSort100000(b *testing.B) { benchmarkHeapSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/insertion/insertion.go: -------------------------------------------------------------------------------- 1 | /* 2 | # insertion sort 插入排序 3 | 4 | 插入排序可以原地(in-place)也可以非原地(not-in-place),核心步骤是在无序数组中选出被排数, 5 | 然后通过比较来移动有序数组并得到空位,最后将被排数插入空位。 6 | 7 | 插入排序非常适合少量或者已基本有序的数据,数据量变大时 O(n^2) 的复杂度会很恐怖(毕竟有两层循环) 8 | 9 | 非原地方式是申请新的数组然后把被排数插入新数组,原地方式是备份被排数然后从头部(或尾部)比较、移动来建立有序数组 10 | 11 | # runtime 12 | - Worst:O(n^2) 13 | - Best: 14 | - Average:O(n^2) 15 | 16 | */ 17 | package insertion 18 | 19 | /* 20 | in-place 方式 21 | */ 22 | func Sort(arr []int) []int { 23 | length := len(arr) 24 | if length == 1 {return arr} 25 | 26 | for i := 1; i < length; i++ { 27 | backup := arr[i] 28 | j := i -1; 29 | //将选出的被排数比较后插入左边有序区 30 | for j >= 0 && backup < arr[j] {//注意j >= 0必须在前边,否则会数组越界 31 | arr[j+1] = arr[j]//移动有序数组 32 | j -- //反向移动下标 33 | } 34 | arr[j + 1] = backup //插队插入移动后的空位 35 | } 36 | return arr 37 | } -------------------------------------------------------------------------------- /sort/insertion/insertion_test.go: -------------------------------------------------------------------------------- 1 | package insertion 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestInsertionSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(100) 13 | 14 | Sort(list) 15 | 16 | for i := 0; i < len(list)-2; i++ { 17 | if list[i] > list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkInsertionSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkInsertionSort100(b *testing.B) { benchmarkInsertionSort(100, b) } 33 | func BenchmarkInsertionSort1000(b *testing.B) { benchmarkInsertionSort(1000, b) } 34 | func BenchmarkInsertionSort10000(b *testing.B) { benchmarkInsertionSort(10000, b) } 35 | func BenchmarkInsertionSort100000(b *testing.B) { benchmarkInsertionSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "Algorithms-Learning-With-Go/sort/utils" 5 | "log" 6 | 7 | "Algorithms-Learning-With-Go/sort/quick" 8 | // "go-algorithms/sort/bubble" 9 | ) 10 | 11 | func main() { 12 | list := utils.GetArrayOfSize(10) 13 | log.Println(list) 14 | quick.HoareSort(list, 0, len(list)-1) 15 | // quick.LomutoSort(list, 0, len(list)-1) 16 | // quick.Sort(list) 17 | // bubble.Sort(list) 18 | log.Println(list) 19 | } 20 | -------------------------------------------------------------------------------- /sort/merge/merge.go: -------------------------------------------------------------------------------- 1 | /* 2 | # merge sort 归并排序 3 | 4 | 思路就是先分治后合并,这是种非原地(not-in-place)方式。 5 | 实现过程是通过递归来从上到下分割,在最深层实现两数比较, 6 | 然后逐层上升连续将左右分区中最小值写入结果数组,最终实现整体排序。 7 | 8 | #runtime 9 | -Worst:O(n log n) 10 | -Best:O(n log n) 11 | -Average:O(n log n) 12 | 13 | #stability 14 | 稳定 15 | */ 16 | package merge 17 | 18 | /* 19 | 合并 20 | */ 21 | func merge(leftPile, rightPile []int) []int { 22 | // 1 左右偏移量 23 | leftIndex := 0 24 | rightIndex := 0 25 | 26 | // 2 用以存放结果的数组 27 | sortedPile := []int{} 28 | 29 | // 3 递归最深层会是简单的两数比较,然后返回两数的有序数组; 30 | // 逐层上升来比较时则遍历左右两个有序数组,并选择其中最小的数据合并到结果数组中; 31 | // 遍历结束后直接将剩余有序值全部合并到结果数组,最终实现两个有序数组的整体有序 32 | for leftIndex < len(leftPile) && rightIndex < len(rightPile) { 33 | if leftPile[leftIndex] < rightPile[rightIndex] { 34 | sortedPile = append(sortedPile,leftPile[leftIndex]) 35 | leftIndex += 1 36 | } else if leftPile[leftIndex] > rightPile[rightIndex] { 37 | sortedPile = append(sortedPile,rightPile[rightIndex]) 38 | rightIndex += 1 39 | } else { 40 | sortedPile = append(sortedPile,leftPile[leftIndex]) 41 | leftIndex += 1 42 | sortedPile = append(sortedPile,rightPile[rightIndex]) 43 | rightIndex += 1 44 | } 45 | } 46 | 47 | // 4 如果左边剩下高值 48 | for leftIndex < len(leftPile) { 49 | sortedPile = append(sortedPile,leftPile[leftIndex]) 50 | leftIndex += 1 51 | } 52 | // 5 如果右边剩下高值 53 | for rightIndex < len(rightPile) { 54 | sortedPile = append(sortedPile,rightPile[rightIndex]) 55 | rightIndex += 1 56 | } 57 | return sortedPile 58 | } 59 | func Sort(arr []int) []int { 60 | //如果只剩一个元素则直接返回(递归方式最终都会产生最简数据单位,然后再逐层上升来运算) 61 | if len(arr) <= 1 { return arr } 62 | //否则对半分割,递归之后都会触发以上条件并返回,然后调用合并方法进行排序 63 | mid := len(arr) / 2 64 | //分 65 | leftPile := Sort(arr[:mid]) 66 | rightPile := Sort(arr[mid:]) 67 | //合 68 | return merge(leftPile, rightPile) 69 | } -------------------------------------------------------------------------------- /sort/merge/merge_test.go: -------------------------------------------------------------------------------- 1 | package merge 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | "testing" 7 | ) 8 | 9 | 10 | func TestMergeSort(t *testing.T) { 11 | list := utils.GetArrayOfSize(10) 12 | 13 | list = Sort(list) 14 | 15 | for i := 0; i < len(list)-2; i++ { 16 | if list[i] > list[i+1] { 17 | fmt.Println(list) 18 | t.Error() 19 | } 20 | } 21 | } 22 | 23 | 24 | func benchmarkMergeSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | list = Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkMergeSort100(b *testing.B) { benchmarkMergeSort(100, b) } 33 | func BenchmarkMergeSort1000(b *testing.B) { benchmarkMergeSort(1000, b) } 34 | func BenchmarkMergeSort10000(b *testing.B) { benchmarkMergeSort(10000, b) } 35 | func BenchmarkMergeSort100000(b *testing.B) { benchmarkMergeSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/quick/quick.go: -------------------------------------------------------------------------------- 1 | /* 2 | # quick sort 快速排序 3 | 4 | 快速排序有几种实现方式,不过核心操作是选出一个基点比较值,通过一次遍历得出比它小的A和比它大的B无序数组, 5 | 然后通过递归方式分别操作A与B,并将低值A结果放到基点左边,高值B结果放到基点右边。 6 | 7 | 全过程都是为了基准点pivot归位。 8 | 9 | # runtime 10 | -Worst:O(n ^ 2) 11 | -Best:O(n lg n) 12 | -Average:O(n lg n) 13 | */ 14 | package quick 15 | /* 16 | 简单快排: 17 | 递归模板返回小于、等于、大于基点比较元素的三个数组(低值数组、等值数组、高值数组), 18 | 基点元素是数组中间值,递归完后将三个数组合并即是结果。 19 | 20 | 评价—— 21 | 数据量过百后性能就很差。 22 | 23 | 关键点—— 24 | 基点比较元素(pivot) 25 | 低值数组 26 | 等值数组 27 | 高值数组 28 | */ 29 | func Sort(list []int) []int{ 30 | 31 | if len(list) <= 1 { 32 | return list 33 | } 34 | 35 | //[[----递归模板区 36 | 37 | pivot := list[len(list)/2] 38 | 39 | partitionFunc := func (arr []int, pivot int) ([]int, []int, []int){//基点分割函数 40 | lessArr := make([]int, 0) 41 | greaterArr := make([]int, 0) 42 | equalArr := make([]int, 0) 43 | 44 | for _, value := range arr { 45 | switch { 46 | case value < pivot: 47 | lessArr = append(lessArr,value) 48 | case value > pivot: 49 | greaterArr = append(greaterArr,value) 50 | default: 51 | equalArr = append(equalArr,value) 52 | } 53 | } 54 | return lessArr, equalArr, greaterArr 55 | } 56 | less, equal, greater := partitionFunc(list, pivot) 57 | //--------------]] 58 | 59 | copy(list, Sort(less)) 60 | copy(list[len(less):], equal) 61 | copy(list[(len(less)+len(equal)):], Sort(greater)) 62 | 63 | return list 64 | } 65 | 66 | /* 67 | 老毛桃 (Lomuto) 快排: 68 | 以最右位置为基点比较元素,递归模板中不返回排序完的数组,而是返回遍历后基点比较元素应该所在的位置下标p, 69 | 左边分区(包含小于等于基点元素的元素)是相对p值的低值数组,右边分区(包含大于基点元素的元素) 70 | 是相对p值的高值数组。 71 | 72 | 评价—— 73 | 比霍尔快排简单但是性能稍差。 74 | 75 | 关键点—— 76 | 基点比较元素(pivot) 77 | 遍历索引 78 | 低值数组锚点 79 | */ 80 | func LomutoSort(list []int, low int, high int){ 81 | if low >= high {return} 82 | 83 | //[[----递归模板区 84 | pivot := list[high] 85 | i := low 86 | for j := low+1; j < high; j++ { 87 | if list[j] <= pivot { 88 | list[i], list[j] = list[j], list[i] 89 | i ++ 90 | } 91 | } 92 | 93 | list[i], list[high] = list[high], list[i] 94 | //--------------]] 95 | 96 | LomutoSort(list, low, i-1) 97 | LomutoSort(list, i+1, high) 98 | } 99 | 100 | /* 101 | 霍尔快排: 102 | 递归模板同老毛桃快排,返回低值区的锚点下标。不同的是霍尔快排以最左为基点比较元素, 103 | 并从两端同时进行比较双向排序, 将双方都需调整位置的两个元素相互交换直到双方相交, 104 | 然后将最左元素与右端当前锚点交换,最终实现基准点归位。 105 | 106 | 评价—— 107 | 108 | 关键点—— 109 | 110 | */ 111 | func HoareSort(list []int, low int, high int) { 112 | if low >= high {return} 113 | 114 | //[[----递归模板区 115 | 116 | pivot := list[low] 117 | right := high 118 | left := low 119 | for { 120 | for list[right] >= pivot && right > low{ 121 | right -- 122 | } 123 | for list[left] <= pivot && left < high{ 124 | left ++ 125 | } 126 | 127 | 128 | if left < right { 129 | list[left], list[right] = list[right], list[left] 130 | } else { 131 | break 132 | } 133 | } 134 | list[low], list[right] = list[right], list[low] 135 | //--------------]] 136 | 137 | 138 | HoareSort(list, low, right) 139 | 140 | HoareSort(list, right+1, high) 141 | } -------------------------------------------------------------------------------- /sort/quick/quick_test.go: -------------------------------------------------------------------------------- 1 | package quick 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestQuickSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(10) 13 | 14 | // Sort(list) 15 | HoareSort(list, 0, len(list)-1) 16 | // LomutoSort(list, 0, len(list)-1) 17 | 18 | for i := 0; i < len(list)-2; i++ { 19 | if list[i] > list[i+1] { 20 | fmt.Println(list) 21 | t.Error() 22 | } 23 | } 24 | } 25 | 26 | 27 | func benchmarkQuickSort(n int, b *testing.B) { 28 | list := utils.GetArrayOfSize(n) 29 | 30 | for i := 0; i < b.N; i++ { 31 | // Sort(list) 32 | // Sort(list)LomutoSort 33 | // LomutoSort(list, 0, len(list)-1) 34 | HoareSort(list, 0, len(list)-1) 35 | } 36 | } 37 | 38 | func BenchmarkQuickSort100(b *testing.B) { benchmarkQuickSort(100, b) } 39 | func BenchmarkQuickSort1000(b *testing.B) { benchmarkQuickSort(1000, b) } 40 | func BenchmarkQuickSort10000(b *testing.B) { benchmarkQuickSort(10000, b) } 41 | func BenchmarkQuickSort100000(b *testing.B) { benchmarkQuickSort(100000, b) } 42 | -------------------------------------------------------------------------------- /sort/selection/selection.go: -------------------------------------------------------------------------------- 1 | /* 2 | # selection Sort 选择排序 3 | 4 | 类似冒泡排序,通过两层嵌套的循环来遍历、比较数组中元素。 5 | 不同的是选择排序在内层循环中不交换,而是选出最小值的位置,然后在外层循环中交换最小值到头部。 6 | 最终实现数组依次按照最小值排序。 7 | 8 | 选择排序即选择最值位置排序,效率差 9 | 10 | # Runtime: 11 | 12 | - Average: O(N^2) 13 | - Worst: O(N^2) 14 | */ 15 | package selection 16 | 17 | func Sort(arr []int) []int { 18 | for i := 0; i < len(arr); i++ { 19 | min := i 20 | for j := i + 1; j < len(arr); j++ { 21 | if arr[j] < arr[min] { 22 | min = j 23 | } 24 | } 25 | if min != i { 26 | arr[i], arr[min] = arr[min], arr[i] 27 | } 28 | } 29 | return arr 30 | } 31 | -------------------------------------------------------------------------------- /sort/selection/selection_test.go: -------------------------------------------------------------------------------- 1 | package selection 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/sort/utils" 6 | 7 | "testing" 8 | ) 9 | 10 | 11 | func TestSelectionSort(t *testing.T) { 12 | list := utils.GetArrayOfSize(100) 13 | 14 | Sort(list) 15 | 16 | for i := 0; i < len(list)-2; i++ { 17 | if list[i] > list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkSelectionSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkSelectionSort100(b *testing.B) { benchmarkSelectionSort(100, b) } 33 | func BenchmarkSelectionSort1000(b *testing.B) { benchmarkSelectionSort(1000, b) } 34 | func BenchmarkSelectionSort10000(b *testing.B) { benchmarkSelectionSort(10000, b) } 35 | func BenchmarkSelectionSort100000(b *testing.B) { benchmarkSelectionSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/shell/shell.go: -------------------------------------------------------------------------------- 1 | /* 2 | # shell sort 希尔排序 3 | 4 | #核心——通过设置下标增量来将数据分组,然后用插入排序法处理每个分组,再将下标增量减半。 5 | 接下来循环调用此过程直到下标增量为0。 6 | 7 | 又叫缩小增量排序算法,以科学家 DL.Shell 名字命名。 8 | 9 | 简直美爆了!小步长增量来插入排序时可以利用大步长增量的有序性, 10 | 利用了插入排序适合小数据量和基本有序的特点,充分发挥插入排序的优点, 11 | 使得整体用来处理大数据量的排序非常不错——虽然比快排还差点。 12 | 13 | 14 | # runtime 15 | - Worst:O(n^2) O(n^1.5) O(n((log^2)n))跟增量大小有关 16 | - Best:O(n) 17 | - Average:O(n^(1~2)) 18 | 19 | # stability 20 | 不稳定 21 | */ 22 | package shell 23 | 24 | /* 25 | 排序起始点与步长为变量而非常量0和1的时候乃是更为一般化的实现。 26 | */ 27 | func insertion(arr []int, start, gap int) { 28 | length := len(arr) 29 | 30 | for traverseVal := start + gap; traverseVal < length; traverseVal += gap { 31 | backup := arr[traverseVal] 32 | trackVal := traverseVal - gap 33 | for trackVal >= 0 && backup < arr[trackVal] { 34 | arr[trackVal + gap] = arr[trackVal] 35 | trackVal -= gap 36 | } 37 | arr[trackVal + gap] = backup 38 | } 39 | } 40 | func Sort(arr []int) []int { 41 | //设定步长增量 42 | gap := len(arr)/2 43 | //结束条件 44 | for gap > 0 { 45 | for pos := 0; pos list[i+1] { 18 | fmt.Println(list) 19 | t.Error() 20 | } 21 | } 22 | } 23 | 24 | func benchmarkShellSort(n int, b *testing.B) { 25 | list := utils.GetArrayOfSize(n) 26 | 27 | for i := 0; i < b.N; i++ { 28 | Sort(list) 29 | } 30 | } 31 | 32 | func BenchmarkShellSort100(b *testing.B) { benchmarkShellSort(100, b) } 33 | func BenchmarkShellSort1000(b *testing.B) { benchmarkShellSort(1000, b) } 34 | func BenchmarkShellSort10000(b *testing.B) { benchmarkShellSort(10000, b) } 35 | func BenchmarkShellSort100000(b *testing.B) { benchmarkShellSort(100000, b) } 36 | -------------------------------------------------------------------------------- /sort/utils/RandIntGen.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "io" 7 | "math/rand" 8 | "strconv" 9 | ) 10 | //检测路径是否存在 11 | func PathExists(path string) (bool) { 12 | _, err := os.Stat(path) 13 | 14 | if os.IsNotExist(err) { 15 | return false 16 | } 17 | return true 18 | } 19 | //生成定锚随机数 20 | func GetRandInt(anchor int) (int){ 21 | 22 | rand.Seed(int64(anchor)) 23 | // 获取指定范围内的随机数 24 | return rand.Intn(100000) 25 | } 26 | //获取文件句柄 27 | func GetFile(filePath string) (*os.File, error){ 28 | var f *os.File 29 | var err error 30 | 31 | if PathExists(filePath) { 32 | f, err = os.OpenFile(filePath, os.O_APPEND, 0666) 33 | }else{ 34 | f, err = os.Create(filePath) //创建文件 35 | } 36 | if err != nil { 37 | log.Println(err) 38 | log.Println("open file err") 39 | } 40 | 41 | return f,err 42 | } 43 | func main() { 44 | var numVol = 100000 45 | var filePath = "IntegerArray.txt" 46 | var f *os.File 47 | var err error 48 | 49 | if f,err = GetFile(filePath);err != nil{ 50 | return 51 | } 52 | for i := 0 ; i < numVol ; i++ { 53 | io.WriteString(f, strconv.Itoa(GetRandInt(i))+"\n") 54 | } 55 | log.Println("done") 56 | } -------------------------------------------------------------------------------- /sort/utils/helper.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bufio" 5 | "go/build" 6 | "os" 7 | "path/filepath" 8 | "strconv" 9 | ) 10 | 11 | func GetArrayOfSize(n int) []int { 12 | p, err := build.Default.Import("Algorithms-Learning-With-Go/sort/utils", "", build.FindOnly) 13 | 14 | if err != nil { 15 | // handle error 16 | } 17 | 18 | fname := filepath.Join(p.Dir, "IntegerArray.txt") 19 | 20 | f, _ := os.Open(fname) 21 | 22 | defer f.Close() 23 | 24 | numbers := make([]int, 0) 25 | scanner := bufio.NewScanner(f) 26 | 27 | for scanner.Scan() { 28 | 29 | s, _ := strconv.Atoi(scanner.Text()) 30 | numbers = append(numbers, s) 31 | } 32 | 33 | return numbers[0:n] 34 | } 35 | -------------------------------------------------------------------------------- /utils/generator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | // 获取模块名参数 11 | module := flag.String("module", "====", "Input your module name") 12 | module2 := flag.String("module2", "====2", "Input your module name2") 13 | flag.Parse() 14 | // help := flag.Usage() 15 | help := flag.Args()//非-option形式的参数 16 | help2 := flag.NArg() 17 | help3 := flag.NFlag() 18 | flag.PrintDefaults() 19 | 20 | // fmt.Println(help) 21 | fmt.Println(help) 22 | fmt.Println(help2) 23 | fmt.Println(help3) 24 | fmt.Println("======++++++++++++=======") 25 | fmt.Println(*module) 26 | // fmt.Println(*module.Name) 27 | fmt.Println(*module2) 28 | 29 | // 拷贝模块模板并重命名(文件夹、代码文件、测试文件) 30 | current_dir, _ := os.Getwd() 31 | fmt.Println(current_dir) 32 | 33 | dirhandle, err := os.Open(current_dir + "/") 34 | if err != nil { 35 | panic(err) 36 | } 37 | defer dirhandle.Close() 38 | 39 | fis, err := dirhandle.Readdir(0) 40 | fmt.Println(fis) 41 | for _,f := range fis { 42 | fmt.Println(f.Name()) 43 | 44 | if f.IsDir() { 45 | fmt.Println("dir+++++++++++++++++++++++") 46 | 47 | } else { 48 | //如果是普通文件 直接写入 dir 后面已经有了 / 49 | fmt.Println("file=====================") 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /utils/module/module.go: -------------------------------------------------------------------------------- 1 | /* 2 | module intro: 3 | 4 | */ 5 | package module 6 | 7 | /* 8 | func intro: 9 | 10 | */ 11 | func Module() { 12 | 13 | } -------------------------------------------------------------------------------- /utils/module/module_test.go: -------------------------------------------------------------------------------- 1 | package module 2 | 3 | import ( 4 | "fmt" 5 | "Algorithms-Learning-With-Go/dummy/module" 6 | "testing" 7 | ) 8 | 9 | /* 10 | 单元测试 11 | */ 12 | func TestModule(t *testing.T) { 13 | 14 | Module() 15 | 16 | if false { 17 | fmt.Println("module") 18 | t.Error() 19 | } 20 | } 21 | 22 | func benchmarkModule(n int, b *testing.B) { 23 | Module() 24 | } 25 | 26 | /* 27 | benchmark 测试 28 | */ 29 | func BenchmarkQuickSort100(b *testing.B) { benchmarkModule(100, b) } 30 | func BenchmarkQuickSort1000(b *testing.B) { benchmarkModule(1000, b) } 31 | func BenchmarkQuickSort10000(b *testing.B) { benchmarkModule(10000, b) } 32 | func BenchmarkQuickSort100000(b *testing.B) { benchmarkModule(100000, b) } --------------------------------------------------------------------------------