├── README.md ├── search └── binarySearch(二分查找).js ├── sort ├── 1.selectionSort(选择排序).js ├── 2.insertionSort(插入排序).js ├── 3.shellSort(希尔排序).js ├── 4.bubbleSort(冒泡排序).js └── 5.mergeSort(归并排序).js └── util ├── isSorted.js └── sortTestHelper.js /README.md: -------------------------------------------------------------------------------- 1 | # 准备重拾算法的枯燥与乐趣了 2 | -------------------------------------------------------------------------------- /search/binarySearch(二分查找).js: -------------------------------------------------------------------------------- 1 | var arr = [41, 55, 76, 87, 88, 99, 123, 432, 546, 577, 688, 786]; 2 | 3 | function twoFind(arr, wantVal, leftIndex, rightIndex) { 4 | if (leftIndex > rightIndex) { 5 | document.writeln('SORRY: 找不到 ' + wantVal + ' !'); 6 | return; 7 | } 8 | var minIndex = Math.floor((leftIndex + rightIndex) / 2); 9 | if (arr[minIndex] > wantVal) { 10 | twoFind(arr, wantVal, leftIndex, minIndex - 1); 11 | } else if (arr[minIndex] < wantVal) { 12 | twoFind(arr, wantVal, minIndex + 1, rightIndex); 13 | } else { 14 | document.writeln('找到了 ' + wantVal + ' ,下表为' + minIndex); 15 | } 16 | } 17 | twoFind(arr, 9, 0, arr.length - 1); 18 | -------------------------------------------------------------------------------- /sort/1.selectionSort(选择排序).js: -------------------------------------------------------------------------------- 1 | const generateRandomArray = require('../util/sortTestHelper.js') 2 | 3 | let arr = generateRandomArray(30000, 10, 100) 4 | 5 | /* 6 | 方法说明:选择排序 7 | @param arr 待排序数组 8 | */ 9 | 10 | //基本原理:遍历找到最小的索引值,然后与当前元素进行交换 11 | 12 | function selectionSort(arr) { 13 | 14 | console.time('t') 15 | 16 | for (let i = 0, len = arr.length; i < len; i++) { 17 | 18 | let minIndex = i 19 | 20 | for (let j = i + 1; j < len; j++) { 21 | if (arr[j] < arr[minIndex]) { 22 | minIndex = j 23 | } 24 | 25 | } 26 | 27 | /* 28 | 第一种交换两个数字的方法,不引入临时变量,缺陷就是容易越界 29 | if (minIndex !== i) { //如果最小的数字就排在首位就不交换位置,由于数字是引用,index值一样,交换会出问题 30 | arr[i] = arr[i] + arr[minIndex] 31 | 32 | arr[minIndex] = arr[i] - arr[minIndex] 33 | 34 | arr[i] = arr[i] - arr[minIndex] 35 | } 36 | */ 37 | 38 | 39 | /* 40 | 第二种交换两个数字的方法,引入一个临时变量,缺陷就是引入了临时变量 41 | let temp 42 | temp = arr[i] 43 | arr[i] = arr[minIndex] 44 | arr[minIndex] = temp 45 | */ 46 | 47 | 48 | //第三种交换两个数字的方法,这里逼格高一点,采用位操作,还好我学过C语言,缺陷就是不能处理浮点数 49 | if (minIndex !== i) { 50 | arr[i] = arr[i] ^ arr[minIndex] 51 | arr[minIndex] = arr[i] ^ arr[minIndex] 52 | arr[i] = arr[i] ^ arr[minIndex] 53 | } 54 | 55 | } 56 | 57 | console.timeEnd('t') 58 | 59 | 60 | return arr 61 | } 62 | 63 | 64 | console.log(selectionSort(arr)) 65 | -------------------------------------------------------------------------------- /sort/2.insertionSort(插入排序).js: -------------------------------------------------------------------------------- 1 | const generateRandomArray = require('../util/sortTestHelper.js') 2 | 3 | let arr = generateRandomArray(10, 10, 100) 4 | 5 | /* 6 | 方法说明:插入排序 7 | @param array 待排序数组 8 | */ 9 | 10 | //排序思路:每次将一个待排序的元素与已排序的元素进行逐一比较,直到找到合适的位置按大小插入。 11 | 12 | 13 | //原始版 14 | function insertionSort(arr) { 15 | 16 | console.time('t') 17 | 18 | for (let i = 1, len = arr.length; i < len; i++) { 19 | 20 | for (let j = i; j > 0 && arr[j] < arr[j - 1]; j--) { 21 | 22 | let temp 23 | temp = arr[j] 24 | arr[j] = arr[j - 1] 25 | arr[j - 1] = temp 26 | } 27 | } 28 | 29 | console.timeEnd('t') 30 | 31 | return arr 32 | } 33 | 34 | 35 | //优化版,每次比较不再交换,而是移动位置来优化提高性能 36 | function improveInsertSort(arr) { 37 | 38 | console.time('t') 39 | 40 | for (let i = 1, len = arr.length; i < len; i++) { 41 | 42 | let target = arr[i] //先把目标元素复制一份,保存起来,不去贸然交换位置 43 | 44 | let j //j就是target最后应该插入的位置 45 | 46 | for (j = i; j > 0; j--) { 47 | 48 | if (arr[j - 1] > target) { //如果目标元素比前面一个元素小,那么这个元素不应该放在当前位置 49 | 50 | arr[j] = arr[j - 1] //把目标元素前面的一个数字向后挪一个位置 51 | 52 | } else { 53 | 54 | break 55 | 56 | } 57 | 58 | } 59 | 60 | arr[j] = target 61 | 62 | } 63 | 64 | console.timeEnd('t') 65 | 66 | return arr 67 | 68 | } 69 | 70 | console.log(improveInsertSort(arr)) 71 | -------------------------------------------------------------------------------- /sort/3.shellSort(希尔排序).js: -------------------------------------------------------------------------------- 1 | const generateRandomArray = require('../util/sortTestHelper.js') 2 | 3 | 4 | let arr = generateRandomArray(15, 1, 120) 5 | 6 | /* 7 | 方法说明:希尔排序 8 | @param array 待排序数组 9 | */ 10 | 11 | //希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。希尔排序是非稳定排序算法。 12 | 13 | //排序思路:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是最高的,因此希尔排序在时间效率上比前两种方法有较大提高。 14 | 15 | 16 | function shellSort(arr) { 17 | 18 | let gap = 1, 19 | len = arr.length, 20 | target, j 21 | 22 | //动态定义间隔序列 23 | while (gap < len / 5) { 24 | gap = gap * 5 + 1 25 | } 26 | 27 | console.time('shellSort') 28 | 29 | for (gap; gap > 0; gap = Math.floor(gap / 5)) { 30 | 31 | for (let i = gap; i < len; i++) { 32 | 33 | target = arr[i] 34 | 35 | for (j = i - gap; j >= 0; j -= gap) { 36 | 37 | if (arr[j] > target) { 38 | arr[j + gap] = arr[j] 39 | } else { 40 | break 41 | } 42 | } 43 | 44 | arr[j + gap] = target 45 | } 46 | } 47 | console.timeEnd('shellSort') 48 | 49 | return arr 50 | 51 | } 52 | 53 | console.log(shellSort(arr)) 54 | -------------------------------------------------------------------------------- /sort/4.bubbleSort(冒泡排序).js: -------------------------------------------------------------------------------- 1 | const generateRandomArray = require('../util/sortTestHelper.js') 2 | 3 | let arr = generateRandomArray(20000, 1, 12000) 4 | 5 | /* 6 | 方法说明:冒泡排序 7 | @param array 待排序数组 8 | */ 9 | 10 | //排序思路:从最下面的元素开始,对相邻的元素进行比较,经过交换使得较小的元素在较大的元素之上,经过对每个元素的两两比较,最后最小的元素被移到前面的位置。 11 | 12 | 13 | //原始版 14 | function bubbleSort(arr) { 15 | let i, len, j, temp 16 | console.time('bubbleSort') 17 | for (i = 0, len = arr.length; i < len - 1; i++) { // 有N个元素只需比较N-1次 18 | for (j = len - 1; j > i; j--) { 19 | if (arr[j] < arr[j - 1]) { 20 | temp = arr[j] 21 | arr[j] = arr[j - 1] 22 | arr[j - 1] = temp 23 | } 24 | } 25 | } 26 | console.timeEnd('bubbleSort') 27 | return arr 28 | } 29 | 30 | 31 | //优化版,对前面已经是有序的就不用排了 32 | function improveBubbleSort1(arr) { // 如果前面的已经排好序,那么之后的就不用进行交换和比较了 33 | let i, len, j, flag, temp 34 | console.time('improveBubbleSort1') 35 | for (i = 0, len = arr.length; i < len - 1; i++) { //有N个元素只需比较N-1次 36 | flag = false 37 | for (j = len - 1; j > i; j--) { 38 | if (arr[j] < arr[j - 1]) { 39 | temp = arr[j] 40 | arr[j] = arr[j - 1] 41 | arr[j - 1] = temp 42 | flag = true // 如果交换了则变为true 43 | } 44 | } 45 | if (flag == false) { 46 | break 47 | } 48 | } 49 | console.timeEnd('improveBubbleSort1') 50 | return arr 51 | } 52 | 53 | 54 | //再次优化版,记录每次交换的位置,从交换位置的地方再次比较,比上面的更优雅先进 55 | function improveBubbleSort2(arr) { 56 | let i, pos, j, temp //初始时,最后位置保持不变 57 | i = arr.length - 1 58 | console.time('improveBubbleSort2') 59 | while (i > 0) { 60 | pos = 0 //每趟开始时,无记录交换 61 | for (j = 0; j < i; j++) { 62 | if (arr[j] > arr[j + 1]) { 63 | pos = j //记录交换的位置 64 | temp = arr[j] 65 | arr[j] = arr[j + 1] 66 | arr[j + 1] = temp 67 | } 68 | } 69 | i = pos //为下一趟排序作准备 70 | } 71 | console.timeEnd('improveBubbleSort2') 72 | return arr 73 | } 74 | 75 | 76 | //究极版,两头齐头并进,最终汇合。 77 | function improveBubbleSort3(arr) { 78 | let start = 0, 79 | end = arr.length - 1, 80 | temp, i 81 | console.time('improveBubbleSort3') 82 | while (start < end) { 83 | for (i = start; i < end; i++) { 84 | //正向冒泡,找到最大者 85 | if (arr[i] > arr[i + 1]) { 86 | temp = arr[i] 87 | arr[i] = arr[i + 1] 88 | arr[i + 1] = temp 89 | } 90 | } 91 | --end 92 | //反向冒泡,找到最小者 93 | for (i = end; i > start; i--) { 94 | if (arr[i] < arr[i - 1]) { 95 | temp = arr[i] 96 | arr[i] = arr[i - 1] 97 | arr[i - 1] = temp 98 | } 99 | } 100 | ++start 101 | } 102 | console.timeEnd('improveBubbleSort3') 103 | return arr 104 | } 105 | 106 | function improveBubbleSort4(arr) { 107 | 108 | } 109 | 110 | 111 | let arr0 = JSON.parse(JSON.stringify(arr)) 112 | let arr1 = JSON.parse(JSON.stringify(arr)) 113 | let arr2 = JSON.parse(JSON.stringify(arr)) 114 | let arr3 = JSON.parse(JSON.stringify(arr)) 115 | 116 | bubbleSort(arr0) 117 | improveBubbleSort1(arr1) 118 | improveBubbleSort2(arr2) 119 | improveBubbleSort3(arr3) 120 | -------------------------------------------------------------------------------- /sort/5.mergeSort(归并排序).js: -------------------------------------------------------------------------------- 1 | const generateRandomArray = require('../util/sortTestHelper.js') 2 | 3 | let arr = generateRandomArray(20, 1, 12000) 4 | 5 | /* 6 | 方法说明:归并排序 7 | @param array 待排序的数组 8 | */ 9 | //排序思路: 10 | -------------------------------------------------------------------------------- /util/isSorted.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 检测数组是否排序成功 3 | */ 4 | 5 | function isSorted(arr) { 6 | for (let i = 0, len = arr.length; i < len - 1; i++) { 7 | if (arr[i] > arr[i + 1]) { 8 | return false 9 | } 10 | } 11 | return true 12 | } 13 | -------------------------------------------------------------------------------- /util/sortTestHelper.js: -------------------------------------------------------------------------------- 1 | //生成N个一定范围的随机数组 2 | 3 | module.exports = function generateRandomArray(n, start, end) { 4 | let arr = [] 5 | if (start > end) { 6 | console.log('输入有误,请重新输入!') 7 | return 8 | } 9 | for (let i = 0; i < n; i++) { 10 | arr[i] = Math.round(Math.random() * (end - start) + start) 11 | } 12 | 13 | return arr 14 | 15 | } 16 | 17 | 18 | 19 | //生成N个几乎是有序的随机数组 20 | 21 | function generateNealyOrderArray(n, swapTimes) { 22 | let arr = [] 23 | for (let i = 0; i < n; i++) { 24 | arr[i] = i 25 | } 26 | 27 | for (let i = 0; i < swapTimes; i++) { 28 | 29 | let posx = Math.floor(Math.random() * n) 30 | let posy = Math.floor(Math.random() * n) 31 | 32 | arr[posx] = arr[posx] ^ arr[posy] 33 | arr[posy] = arr[posx] ^ arr[posy] 34 | arr[posx] = arr[posx] ^ arr[posy] 35 | 36 | } 37 | 38 | return arr 39 | 40 | } 41 | --------------------------------------------------------------------------------