JavaScript to achieve the ten common sorting algorithm library
1 ; 2 (function (global, factory) { 3 // 兼容amd和cmd的写法 4 // 基本的新式是 cmd ? cmd : amd ? amd : global || window 5 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 6 typeof define === 'function' && define.amd ? define(factory) : 7 (global.PAS = factory()); 8 })(this, (function () { 9 // 判断是否数组 10 function isArray(arr) { 11 return typeof Array.isArray === 'function' ? 12 Array.isArray(arr) : 13 Object.prototype.toString.call(arr) === '[object Array]'; 14 } 15 16 // 交换两个元素 17 function swap(v1, v2, context) { 18 [context[v1], context[v2]] = [context[v2], context[v1]]; 19 return void 0; 20 } 21 22 // 冒泡排序 23 function bubble(arr) { 24 let len = arr.length; 25 for (let i = 0; i < len; i++) { 26 for (let j = 0; j < len - 1 - i; j++) { 27 if (arr[j] > arr[j + 1]) { 28 swap(j, j + 1, arr) 29 } 30 } 31 } 32 return arr; 33 } 34 35 // 插入排序 36 function insert(arr) { 37 let len = arr.length; 38 let pIndex, current; // 前一个元素的索引,当前元素的值 39 for (let i = 1; i < len; i++) { 40 pIndex = i - 1; 41 current = arr[i]; 42 43 // 依次把当前元素和前面的元素进行比较 44 while (pIndex >= 0 && arr[pIndex] > current) { 45 // 比当前的元素大,向后移一位 46 arr[pIndex + 1] = arr[pIndex]; 47 pIndex--; 48 } 49 // 插入当前元素到合适的位置 50 arr[pIndex + 1] = current; 51 } 52 return arr; 53 } 54 55 // 快速排序 -- 这个方法不改变原数组 56 function quick(arr) { 57 let len = arr.length; 58 59 if (len < 2) { 60 return arr; 61 } 62 63 let middleIndex = Math.floor(len / 2); // 中间元素的索引值 64 let baseValue = arr.splice(middleIndex, 1); // 基准值 65 66 let left = []; // 保存小于基准值元素 67 let right = []; // 保存大于或等于基准值元素 68 69 for (let i = 0; i < arr.length; i++) { 70 if (arr[i] < baseValue) { 71 left.push(arr[i]); 72 } else { 73 right.push(arr[i]); 74 } 75 } 76 return quick(left).concat(baseValue, quick(right)); 77 } 78 79 // 选择排序 80 function selection(arr) { 81 let len = arr.length; 82 let minIndex = 0; // 用于保存最小值的索引 83 84 for (let i = 0; i < len - 1; i++) { 85 minIndex = i; 86 // 遍历后面的元素和当前认为的最小值进行比较 87 for (let j = i + 1; j < len; j++) { 88 if (arr[minIndex] > arr[j]) { 89 // 比认为的最小值小 交换索引 90 minIndex = j; 91 } 92 } 93 // 找到最小值和当前值交换 94 if (minIndex !== i) { 95 swap(minIndex, i, arr); 96 } 97 } 98 return arr; 99 } 100 101 // 归并排序 102 function merge(arr) { 103 let len = arr.length; 104 if (len < 2) { 105 return arr; 106 } 107 let middleIndex = Math.floor(len / 2); // 获取中间元素的索引 108 let left = arr.slice(0, middleIndex); // 获取左半部分的元素 109 let right = arr.slice(middleIndex); // 获取右半部分的元素 110 111 let merges = function (left, right) { 112 // 保存结果的数组 113 let result = []; 114 115 while (left.length && right.length) { 116 if (left[0] < right[0]) { 117 result.push(left.shift()) 118 } else { 119 result.push(right.shift()) 120 } 121 } 122 123 // 如果左半边还有元素 124 while (left.length) { 125 result.push(left.shift()); 126 } 127 128 // 如果右半边还有元素 129 while (right.length) { 130 result.push(right.shift()); 131 } 132 133 return result; 134 } 135 136 return merges(merge(left), merge(right)); 137 } 138 139 // 希尔排序 140 function shell(arr) { 141 let len = arr.length, 142 temp, 143 gap = 1; 144 145 while (gap < len / 3) { 146 gap = gap * 3 + 1; 147 } 148 149 for (gap; gap > 0; gap = Math.floor(gap / 3)) { 150 for (let i = gap; i < len; i++) { 151 temp = arr[i]; 152 for (var j = i - gap; j >= 0 && arr[j] > temp; j -= gap) { 153 arr[j + gap] = arr[j]; 154 } 155 arr[j + gap] = temp; 156 } 157 } 158 return arr; 159 } 160 161 // 堆排序 162 function heap(arr) { 163 let len = arr.length; 164 165 let heapify = function ( 166 arr // 待排序的数组 167 , x // 元素的下标 168 , len // 数组的长度 169 ) { 170 let l = 2 * x + 1; 171 let r = 2 * x + 2; 172 let largest = x; 173 174 if (l < len && arr[l] > arr[largest]) { 175 largest = l; 176 } 177 178 if (r < len && arr[r] > arr[largest]) { 179 largest = r; 180 } 181 182 if (largest !== x) { 183 swap(x, largest, arr); 184 heapify(arr, largest, len); 185 } 186 } 187 188 for (let i = Math.floor(len / 2); i >= 0; i--) { 189 heapify(arr, i, len); 190 } 191 192 for (let i = len - 1; i >= 1; i--) { 193 swap(0, i, arr); 194 heapify(arr, 0, --len); 195 } 196 return arr; 197 } 198 199 // 基数排序 200 function radix(arr) { 201 const SIZE = 10; 202 let len = arr.length; 203 let buckets = []; 204 let max = Math.max.apply(null, arr); // 数组中的最大值 205 let maxLength = String(max).length; // 最大数字的长度 206 207 // 进行循环将桶中的数组填充成数组 208 for (let i = 0; i < SIZE; i++) { 209 buckets[i] = []; 210 } 211 212 // 进行循环--对数据进行操作--放桶的行为 213 for (let i = 0; i < maxLength; i++) { 214 // 第二轮循环是将数据按照个位数进行分类 215 for (let j = 0; j < len; j++) { 216 let value = String(arr[j]); 217 // 判断长度--进行分类 218 if (value.length >= i + 1) { 219 let num = Number(value[value.length - 1 - i]); // 依次的从右到左获取各个数字 220 //放入对应的桶中 221 buckets[num].push(arr[j]); 222 } else { 223 // 长度不满足的时候,就放在第一个桶中 224 buckets[0].push(arr[i]); 225 } 226 } 227 // 将原数组清空 228 arr.length = 0; 229 230 //这次循环是依次取出上面分类好的数组存放到原数组中 231 for (let j = 0; j < SIZE; j++) { 232 // 获取各个桶的长度 233 let l = buckets[j].length; 234 // 循环取出数据 235 for (let k = 0; k < l; k++) { 236 arr.push(buckets[j][k]); 237 } 238 // 将对应的桶清空,方便下次存放数据 239 buckets[j] = []; 240 } 241 } 242 return arr; 243 } 244 245 // 桶排序 -- 不改变原数组 246 function bucket(arr, size = 5) { 247 let len = arr.length; 248 if (len < 2) { 249 return arr; 250 } 251 252 // 获取最大值和最小值 253 const max = Math.max.apply(null, arr); 254 const min = Math.min.apply(null, arr); 255 256 // 计算出桶的数量 size是截距 257 const bucketCount = Math.floor((max - min) / size) + 1; 258 // 根据桶的个数创建指定长度的数组 259 const buckets = new Array(bucketCount); 260 // 将每个桶塞到大桶里面去 261 for (let i = 0; i < bucketCount; i++) { 262 buckets[i] = []; 263 } 264 // 利用映射函数将数据分配到各个桶里面去 265 for (let i = 0; i < arr.length; i++) { 266 // 逢size进1 267 let index = Math.floor((arr[i] - min) / size); 268 buckets[index].push(arr[i]); 269 } 270 //对每个桶中的数据进行排序--借助于快速排序算法 271 for (let i = 0; i < buckets.length; i++) { 272 buckets[i] = quick(buckets[i]); 273 } 274 275 // flatten数组--有点不足就是会将原数组中的String改变为Number 276 return buckets.join(',').split(',').filter(v => v !== '').map(Number); 277 } 278 279 // 计数排序 280 function count(arr) { 281 let index = 0; 282 let len = arr.length; 283 let min = Math.min.apply(null, arr); // 最小值 284 let max = Math.max.apply(null, arr); // 最大值 285 let result = []; // 结果数组 286 287 // 向新数组中填充0 288 for (let i = min; i <= max; i++) { 289 result[i] = 0; 290 } 291 // 把各个数组中对应的元素计数加一 292 for (let i = 0; i < len; i++) { 293 result[arr[i]]++; 294 } 295 // 按照计数的元素进行排序 296 for (let i = min; i <= max; i++) { 297 while (result[i]-- > 0) { 298 arr[index++] = i; 299 } 300 } 301 return arr; 302 } 303 304 const PAS = {}; 305 306 [ 307 bubble, 308 insert, 309 quick, 310 selection, 311 merge, 312 shell, 313 heap, 314 radix, 315 bucket, 316 count 317 ].forEach(function (func) { 318 let name = func.name; 319 //增加层外包装,判断参数是不是数组 320 Object.defineProperty(PAS, name, { 321 get: function () { 322 return function (args) { 323 if (!isArray(args)) { 324 throw new Error('the arguments of PAS.' + name + ' must be Array'); 325 } 326 return func.call(null, args); 327 } 328 }, 329 configurable: true 330 }) 331 332 // 在数组的原型上添加方法 333 Object.defineProperty(Array.prototype, name, { 334 get: function () { 335 var vm = this; 336 return function () { 337 return func.call(vm, vm); 338 } 339 }, 340 configurable: true 341 }) 342 }) 343 344 return PAS; 345 }))