├── .github └── FUNDING.yml ├── .gitignore ├── .travis.yml ├── 1.bubbleSort.md ├── 10.radixSort.md ├── 2.selectionSort.md ├── 3.insertionSort.md ├── 4.shellSort.md ├── 5.mergeSort.md ├── 6.quickSort.md ├── 7.heapSort.md ├── 8.countingSort.md ├── 9.bucketSort.md ├── README.md ├── SUMMARY.md ├── res ├── bubbleSort.gif ├── countingSort.gif ├── heapSort.gif ├── insertionSort.gif ├── mergeSort.gif ├── quickSort.gif ├── radixSort.gif ├── selectionSort.gif └── sort.png └── src ├── goSortTest.go ├── java ├── main │ ├── BubbleSort.java │ ├── BucketSort.java │ ├── CountingSort.java │ ├── HeapSort.java │ ├── IArraySort.java │ ├── InsertSort.java │ ├── MergeSort.java │ ├── QuickSort.java │ ├── RadixSort.java │ ├── SelectionSort.java │ └── ShellSort.java ├── pom.xml ├── target │ ├── maven-archiver │ │ └── pom.properties │ └── sort-1.0-SNAPSHOT.jar └── test │ └── ArraySortTest.java ├── phpSortTest.php └── pythonSortTest.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ['https://paypal.me/hustcc', 'https://atool.vip'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | _book 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | *.pdf 17 | \.idea/ 18 | 19 | *.iml 20 | 21 | src/javaSortTest/target/ 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | before_install: 5 | - npm i -g lint-md-cli 6 | script: lint-md ./ 7 | -------------------------------------------------------------------------------- /1.bubbleSort.md: -------------------------------------------------------------------------------- 1 | # 冒泡排序 2 | 3 | 冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。 4 | 5 | 作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来说并没有什么太大作用。 6 | 7 | 8 | ## 1. 算法步骤 9 | 10 | 1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。 11 | 12 | 2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。 13 | 14 | 3. 针对所有的元素重复以上的步骤,除了最后一个。 15 | 16 | 4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。 17 | 18 | 19 | ## 2. 动图演示 20 | 21 | ![动图演示](res/bubbleSort.gif) 22 | 23 | 24 | ## 3. 什么时候最快 25 | 26 | 当输入的数据已经是正序时(都已经是正序了,我还要你冒泡排序有何用啊)。 27 | 28 | 29 | ## 4. 什么时候最慢 30 | 31 | 当输入的数据是反序时(写一个 for 循环反序输出数据不就行了,干嘛要用你冒泡排序呢,我是闲的吗)。 32 | 33 | 34 | ## 5. JavaScript 代码实现 35 | 36 | ```js 37 | function bubbleSort(arr) { 38 | var len = arr.length; 39 | for (var i = 0; i < len - 1; i++) { 40 | for (var j = 0; j < len - 1 - i; j++) { 41 | if (arr[j] > arr[j+1]) { // 相邻元素两两对比 42 | var temp = arr[j+1]; // 元素交换 43 | arr[j+1] = arr[j]; 44 | arr[j] = temp; 45 | } 46 | } 47 | } 48 | return arr; 49 | } 50 | ``` 51 | 52 | 53 | 54 | ## 6. Python 代码实现 55 | 56 | ```python 57 | def bubbleSort(arr): 58 | for i in range(1, len(arr)): 59 | for j in range(0, len(arr)-i): 60 | if arr[j] > arr[j+1]: 61 | arr[j], arr[j + 1] = arr[j + 1], arr[j] 62 | return arr 63 | ``` 64 | 65 | ## 7. Go 代码实现 66 | 67 | ```go 68 | func bubbleSort(arr []int) []int { 69 | length := len(arr) 70 | for i := 0; i < length; i++ { 71 | for j := 0; j < length-1-i; j++ { 72 | if arr[j] > arr[j+1] { 73 | arr[j], arr[j+1] = arr[j+1], arr[j] 74 | } 75 | } 76 | } 77 | return arr 78 | } 79 | ``` 80 | 81 | ## 8. Java 代码实现 82 | 83 | ```java 84 | public class BubbleSort implements IArraySort { 85 | 86 | @Override 87 | public int[] sort(int[] sourceArray) throws Exception { 88 | // 对 arr 进行拷贝,不改变参数内容 89 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 90 | 91 | for (int i = 1; i < arr.length; i++) { 92 | // 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。 93 | boolean flag = true; 94 | 95 | for (int j = 0; j < arr.length - i; j++) { 96 | if (arr[j] > arr[j + 1]) { 97 | int tmp = arr[j]; 98 | arr[j] = arr[j + 1]; 99 | arr[j + 1] = tmp; 100 | 101 | flag = false; 102 | } 103 | } 104 | 105 | if (flag) { 106 | break; 107 | } 108 | } 109 | return arr; 110 | } 111 | } 112 | ``` 113 | 114 | ## 9. PHP 代码实现 115 | 116 | ```php 117 | function bubbleSort($arr) 118 | { 119 | $len = count($arr); 120 | for ($i = 0; $i < $len - 1; $i++) { 121 | for ($j = 0; $j < $len - 1 - $i; $j++) { 122 | if ($arr[$j] > $arr[$j+1]) { 123 | $tmp = $arr[$j]; 124 | $arr[$j] = $arr[$j+1]; 125 | $arr[$j+1] = $tmp; 126 | } 127 | } 128 | } 129 | return $arr; 130 | } 131 | ``` 132 | -------------------------------------------------------------------------------- /10.radixSort.md: -------------------------------------------------------------------------------- 1 | # 基数排序 2 | 3 | 基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。 4 | 5 | 6 | ## 1. 基数排序 vs 计数排序 vs 桶排序 7 | 8 | 基数排序有两种方法: 9 | 10 | 这三种排序算法都利用了桶的概念,但对桶的使用方法上有明显差异案例看大家发的: 11 | 12 | - 基数排序:根据键值的每位数字来分配桶; 13 | - 计数排序:每个桶只存储单一键值; 14 | - 桶排序:每个桶存储一定范围的数值; 15 | 16 | 17 | ## 2. LSD 基数排序动图演示 18 | 19 | ![动图演示](res/radixSort.gif) 20 | 21 | 22 | ## 3. JavaScript 代码实现 23 | 24 | ```js 25 | //LSD Radix Sort 26 | var counter = []; 27 | function radixSort(arr, maxDigit) { 28 | var mod = 10; 29 | var dev = 1; 30 | for (var i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { 31 | for(var j = 0; j < arr.length; j++) { 32 | var bucket = parseInt((arr[j] % mod) / dev); 33 | if(counter[bucket]==null) { 34 | counter[bucket] = []; 35 | } 36 | counter[bucket].push(arr[j]); 37 | } 38 | var pos = 0; 39 | for(var j = 0; j < counter.length; j++) { 40 | var value = null; 41 | if(counter[j]!=null) { 42 | while ((value = counter[j].shift()) != null) { 43 | arr[pos++] = value; 44 | } 45 | } 46 | } 47 | } 48 | return arr; 49 | } 50 | ``` 51 | 52 | 53 | ## 4. python 代码实现 54 | 55 | ```python 56 | def radix(arr): 57 | 58 | digit = 0 59 | max_digit = 1 60 | max_value = max(arr) 61 | #找出列表中最大的位数 62 | while 10**max_digit < max_value: 63 | max_digit = max_digit + 1 64 | 65 | while digit < max_digit: 66 | temp = [[] for i in range(10)] 67 | for i in arr: 68 | #求出每一个元素的个、十、百位的值 69 | t = int((i/10**digit)%10) 70 | temp[t].append(i) 71 | 72 | coll = [] 73 | for bucket in temp: 74 | for i in bucket: 75 | coll.append(i) 76 | 77 | arr = coll 78 | digit = digit + 1 79 | 80 | return arr 81 | ``` 82 | 83 | 84 | ## 5. Java 代码实现 85 | 86 | ```java 87 | /** 88 | * 基数排序 89 | * 考虑负数的情况还可以参考: https://code.i-harness.com/zh-CN/q/e98fa9 90 | */ 91 | public class RadixSort implements IArraySort { 92 | 93 | @Override 94 | public int[] sort(int[] sourceArray) throws Exception { 95 | // 对 arr 进行拷贝,不改变参数内容 96 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 97 | 98 | int maxDigit = getMaxDigit(arr); 99 | return radixSort(arr, maxDigit); 100 | } 101 | 102 | /** 103 | * 获取最高位数 104 | */ 105 | private int getMaxDigit(int[] arr) { 106 | int maxValue = getMaxValue(arr); 107 | return getNumLenght(maxValue); 108 | } 109 | 110 | private int getMaxValue(int[] arr) { 111 | int maxValue = arr[0]; 112 | for (int value : arr) { 113 | if (maxValue < value) { 114 | maxValue = value; 115 | } 116 | } 117 | return maxValue; 118 | } 119 | 120 | protected int getNumLenght(long num) { 121 | if (num == 0) { 122 | return 1; 123 | } 124 | int lenght = 0; 125 | for (long temp = num; temp != 0; temp /= 10) { 126 | lenght++; 127 | } 128 | return lenght; 129 | } 130 | 131 | private int[] radixSort(int[] arr, int maxDigit) { 132 | int mod = 10; 133 | int dev = 1; 134 | 135 | for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { 136 | // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) 137 | int[][] counter = new int[mod * 2][0]; 138 | 139 | for (int j = 0; j < arr.length; j++) { 140 | int bucket = ((arr[j] % mod) / dev) + mod; 141 | counter[bucket] = arrayAppend(counter[bucket], arr[j]); 142 | } 143 | 144 | int pos = 0; 145 | for (int[] bucket : counter) { 146 | for (int value : bucket) { 147 | arr[pos++] = value; 148 | } 149 | } 150 | } 151 | 152 | return arr; 153 | } 154 | 155 | /** 156 | * 自动扩容,并保存数据 157 | * 158 | * @param arr 159 | * @param value 160 | */ 161 | private int[] arrayAppend(int[] arr, int value) { 162 | arr = Arrays.copyOf(arr, arr.length + 1); 163 | arr[arr.length - 1] = value; 164 | return arr; 165 | } 166 | } 167 | ``` 168 | 169 | ## 6. PHP 代码实现 170 | 171 | ```php 172 | function radixSort($arr, $maxDigit = null) 173 | { 174 | if ($maxDigit === null) { 175 | $maxDigit = max($arr); 176 | } 177 | $counter = []; 178 | for ($i = 0; $i < $maxDigit; $i++) { 179 | for ($j = 0; $j < count($arr); $j++) { 180 | preg_match_all('/\d/', (string) $arr[$j], $matches); 181 | $numArr = $matches[0]; 182 | $lenTmp = count($numArr); 183 | $bucket = array_key_exists($lenTmp - $i - 1, $numArr) 184 | ? intval($numArr[$lenTmp - $i - 1]) 185 | : 0; 186 | if (!array_key_exists($bucket, $counter)) { 187 | $counter[$bucket] = []; 188 | } 189 | $counter[$bucket][] = $arr[$j]; 190 | } 191 | $pos = 0; 192 | for ($j = 0; $j < count($counter); $j++) { 193 | $value = null; 194 | if ($counter[$j] !== null) { 195 | while (($value = array_shift($counter[$j])) !== null) { 196 | $arr[$pos++] = $value; 197 | } 198 | } 199 | } 200 | } 201 | 202 | return $arr; 203 | } 204 | ``` 205 | -------------------------------------------------------------------------------- /2.selectionSort.md: -------------------------------------------------------------------------------- 1 | # 选择排序 2 | 3 | 选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。 4 | 5 | 6 | ## 1. 算法步骤 7 | 8 | 1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置 9 | 10 | 2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。 11 | 12 | 3. 重复第二步,直到所有元素均排序完毕。 13 | 14 | 15 | ## 2. 动图演示 16 | 17 | ![动图演示](res/selectionSort.gif) 18 | 19 | 20 | ## 3. JavaScript 代码实现 21 | 22 | ```js 23 | function selectionSort(arr) { 24 | var len = arr.length; 25 | var minIndex, temp; 26 | for (var i = 0; i < len - 1; i++) { 27 | minIndex = i; 28 | for (var j = i + 1; j < len; j++) { 29 | if (arr[j] < arr[minIndex]) { // 寻找最小的数 30 | minIndex = j; // 将最小数的索引保存 31 | } 32 | } 33 | temp = arr[i]; 34 | arr[i] = arr[minIndex]; 35 | arr[minIndex] = temp; 36 | } 37 | return arr; 38 | } 39 | ``` 40 | 41 | ## 4. Python 代码实现 42 | 43 | ```python 44 | def selectionSort(arr): 45 | for i in range(len(arr) - 1): 46 | # 记录最小数的索引 47 | minIndex = i 48 | for j in range(i + 1, len(arr)): 49 | if arr[j] < arr[minIndex]: 50 | minIndex = j 51 | # i 不是最小数时,将 i 和最小数进行交换 52 | if i != minIndex: 53 | arr[i], arr[minIndex] = arr[minIndex], arr[i] 54 | return arr 55 | ``` 56 | 57 | ## 5. Go 代码实现 58 | 59 | ```go 60 | func selectionSort(arr []int) []int { 61 | length := len(arr) 62 | for i := 0; i < length-1; i++ { 63 | min := i 64 | for j := i + 1; j < length; j++ { 65 | if arr[min] > arr[j] { 66 | min = j 67 | } 68 | } 69 | arr[i], arr[min] = arr[min], arr[i] 70 | } 71 | return arr 72 | } 73 | ``` 74 | 75 | ## 6. Java 代码实现 76 | 77 | ```java 78 | public class SelectionSort implements IArraySort { 79 | 80 | @Override 81 | public int[] sort(int[] sourceArray) throws Exception { 82 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 83 | 84 | // 总共要经过 N-1 轮比较 85 | for (int i = 0; i < arr.length - 1; i++) { 86 | int min = i; 87 | 88 | // 每轮需要比较的次数 N-i 89 | for (int j = i + 1; j < arr.length; j++) { 90 | if (arr[j] < arr[min]) { 91 | // 记录目前能找到的最小值元素的下标 92 | min = j; 93 | } 94 | } 95 | 96 | // 将找到的最小值和i位置所在的值进行交换 97 | if (i != min) { 98 | int tmp = arr[i]; 99 | arr[i] = arr[min]; 100 | arr[min] = tmp; 101 | } 102 | 103 | } 104 | return arr; 105 | } 106 | } 107 | ``` 108 | 109 | ## 7. PHP 代码实现 110 | 111 | ```php 112 | function selectionSort($arr) 113 | { 114 | $len = count($arr); 115 | for ($i = 0; $i < $len - 1; $i++) { 116 | $minIndex = $i; 117 | for ($j = $i + 1; $j < $len; $j++) { 118 | if ($arr[$j] < $arr[$minIndex]) { 119 | $minIndex = $j; 120 | } 121 | } 122 | $temp = $arr[$i]; 123 | $arr[$i] = $arr[$minIndex]; 124 | $arr[$minIndex] = $temp; 125 | } 126 | return $arr; 127 | } 128 | ``` 129 | -------------------------------------------------------------------------------- /3.insertionSort.md: -------------------------------------------------------------------------------- 1 | # 插入排序 2 | 3 | 插入排序的代码实现虽然没有冒泡排序和选择排序那么简单粗暴,但它的原理应该是最容易理解的了,因为只要打过扑克牌的人都应该能够秒懂。插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。 4 | 5 | 插入排序和冒泡排序一样,也有一种优化算法,叫做拆半插入。 6 | 7 | 8 | ## 1. 算法步骤 9 | 10 | 1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。 11 | 12 | 2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。) 13 | 14 | 15 | ## 2. 动图演示 16 | 17 | ![动图演示](res/insertionSort.gif) 18 | 19 | 20 | ## 3. JavaScript 代码实现 21 | 22 | ```js 23 | function insertionSort(arr) { 24 | var len = arr.length; 25 | var preIndex, current; 26 | for (var i = 1; i < len; i++) { 27 | preIndex = i - 1; 28 | current = arr[i]; 29 | while(preIndex >= 0 && arr[preIndex] > current) { 30 | arr[preIndex+1] = arr[preIndex]; 31 | preIndex--; 32 | } 33 | arr[preIndex+1] = current; 34 | } 35 | return arr; 36 | } 37 | ``` 38 | 39 | ## 4. Python 代码实现 40 | 41 | ```python 42 | def insertionSort(arr): 43 | for i in range(len(arr)): 44 | preIndex = i-1 45 | current = arr[i] 46 | while preIndex >= 0 and arr[preIndex] > current: 47 | arr[preIndex+1] = arr[preIndex] 48 | preIndex-=1 49 | arr[preIndex+1] = current 50 |    return arr 51 | ``` 52 | 53 | ## 5. Go 代码实现 54 | ```go 55 | func insertionSort(arr []int) []int { 56 | for i := range arr { 57 | preIndex := i - 1 58 | current := arr[i] 59 | for preIndex >= 0 && arr[preIndex] > current { 60 | arr[preIndex+1] = arr[preIndex] 61 | preIndex -= 1 62 | } 63 | arr[preIndex+1] = current 64 | } 65 | return arr 66 | } 67 | ``` 68 | 69 | ## 6. Java 代码实现 70 | 71 | ```java 72 | public class InsertSort implements IArraySort { 73 | 74 | @Override 75 | public int[] sort(int[] sourceArray) throws Exception { 76 | // 对 arr 进行拷贝,不改变参数内容 77 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 78 | 79 | // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的 80 | for (int i = 1; i < arr.length; i++) { 81 | 82 | // 记录要插入的数据 83 | int tmp = arr[i]; 84 | 85 | // 从已经排序的序列最右边的开始比较,找到比其小的数 86 | int j = i; 87 | while (j > 0 && tmp < arr[j - 1]) { 88 | arr[j] = arr[j - 1]; 89 | j--; 90 | } 91 | 92 | // 存在比其小的数,插入 93 | if (j != i) { 94 | arr[j] = tmp; 95 | } 96 | 97 | } 98 | return arr; 99 | } 100 | } 101 | ``` 102 | 103 | ## 7. PHP 代码实现 104 | 105 | ```php 106 | function insertionSort($arr) 107 | { 108 | $len = count($arr); 109 | for ($i = 1; $i < $len; $i++) { 110 | $preIndex = $i - 1; 111 | $current = $arr[$i]; 112 | while($preIndex >= 0 && $arr[$preIndex] > $current) { 113 | $arr[$preIndex+1] = $arr[$preIndex]; 114 | $preIndex--; 115 | } 116 | $arr[$preIndex+1] = $current; 117 | } 118 | return $arr; 119 | } 120 | ``` 121 | -------------------------------------------------------------------------------- /4.shellSort.md: -------------------------------------------------------------------------------- 1 | # 希尔排序 2 | 3 | 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。 4 | 5 | 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 6 | 7 | - 插入排序在对几乎已经排好序的数据操作时,效率高,即可以达到线性排序的效率; 8 | - 但插入排序一般来说是低效的,因为插入排序每次只能将数据移动一位; 9 | 10 | 希尔排序的基本思想是:先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。 11 | 12 | 13 | ## 1. 算法步骤 14 | 15 | 1. 选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1; 16 | 17 | 2. 按增量序列个数 k,对序列进行 k 趟排序; 18 | 19 | 3. 每趟排序,根据对应的增量 ti,将待排序列分割成若干长度为 m 的子序列,分别对各子表进行直接插入排序。仅增量因子为 1 时,整个序列作为一个表来处理,表长度即为整个序列的长度。 20 | 21 | 22 | ## 2. JavaScript 代码实现 23 | 24 | ```js 25 | function shellSort(arr) { 26 | var len = arr.length, 27 | temp, 28 | gap = 1; 29 | while(gap < len/3) { //动态定义间隔序列 30 | gap =gap*3+1; 31 | } 32 | for (gap; gap > 0; gap = Math.floor(gap/3)) { 33 | for (var i = gap; i < len; i++) { 34 | temp = arr[i]; 35 | for (var j = i-gap; j >= 0 && arr[j] > temp; j-=gap) { 36 | arr[j+gap] = arr[j]; 37 | } 38 | arr[j+gap] = temp; 39 | } 40 | } 41 | return arr; 42 | } 43 | ``` 44 | 45 | ## 3. Python 代码实现 46 | 47 | ```python 48 | def shellSort(arr): 49 | import math 50 | gap=1 51 | while(gap < len(arr)/3): 52 | gap = gap*3+1 53 | while gap > 0: 54 | for i in range(gap,len(arr)): 55 | temp = arr[i] 56 | j = i-gap 57 | while j >=0 and arr[j] > temp: 58 | arr[j+gap]=arr[j] 59 | j-=gap 60 | arr[j+gap] = temp 61 | gap = math.floor(gap/3) 62 | return arr 63 | } 64 | ``` 65 | 66 | ## 4. Go 代码实现 67 | 68 | ```go 69 | func shellSort(arr []int) []int { 70 | length := len(arr) 71 | gap := 1 72 | for gap < length/3 { 73 | gap = gap*3 + 1 74 | } 75 | for gap > 0 { 76 | for i := gap; i < length; i++ { 77 | temp := arr[i] 78 | j := i - gap 79 | for j >= 0 && arr[j] > temp { 80 | arr[j+gap] = arr[j] 81 | j -= gap 82 | } 83 | arr[j+gap] = temp 84 | } 85 | gap = gap / 3 86 | } 87 | return arr 88 | } 89 | ``` 90 | 91 | ## 5. Java 代码实现 92 | 93 | ```java 94 | public class ShellSort implements IArraySort { 95 | 96 | @Override 97 | public int[] sort(int[] sourceArray) throws Exception { 98 | // 对 arr 进行拷贝,不改变参数内容 99 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 100 | 101 | int gap = 1; 102 | while (gap < arr.length/3) { 103 | gap = gap * 3 + 1; 104 | } 105 | 106 | while (gap > 0) { 107 | for (int i = gap; i < arr.length; i++) { 108 | int tmp = arr[i]; 109 | int j = i - gap; 110 | while (j >= 0 && arr[j] > tmp) { 111 | arr[j + gap] = arr[j]; 112 | j -= gap; 113 | } 114 | arr[j + gap] = tmp; 115 | } 116 | gap = (int) Math.floor(gap / 3); 117 | } 118 | 119 | return arr; 120 | } 121 | } 122 | ``` 123 | 124 | ## 6. PHP 代码实现 125 | 126 | ```php 127 | function shellSort($arr) 128 | { 129 | $len = count($arr); 130 | $temp = 0; 131 | $gap = 1; 132 | while($gap < $len / 3) { 133 | $gap = $gap * 3 + 1; 134 | } 135 | for ($gap; $gap > 0; $gap = floor($gap / 3)) { 136 | for ($i = $gap; $i < $len; $i++) { 137 | $temp = $arr[$i]; 138 | for ($j = $i - $gap; $j >= 0 && $arr[$j] > $temp; $j -= $gap) { 139 | $arr[$j+$gap] = $arr[$j]; 140 | } 141 | $arr[$j+$gap] = $temp; 142 | } 143 | } 144 | return $arr; 145 | } 146 | ``` 147 | 148 | ## 7. C++ 代码实现 149 | 150 | ```cpp 151 | void shellSort(vector& arr) { 152 | int gap = 1; 153 | while (gap < (int)arr.size() / 3) { 154 | gap = gap * 3 + 1; 155 | } 156 | for (; gap >= 1; gap /= 3) { 157 | for (int i = 0; i < gap; ++i) { 158 | for (int j = i + gap; j < arr.size(); j += gap) { 159 | for (int k = j; k - gap >= 0 && arr[k] < arr[k - gap]; k -= gap) { 160 | swap(arr[k], arr[k - gap]); 161 | } 162 | } 163 | } 164 | } 165 | } 166 | ``` 167 | -------------------------------------------------------------------------------- /5.mergeSort.md: -------------------------------------------------------------------------------- 1 | # 归并排序 2 | 3 | 归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。 4 | 5 | 作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法: 6 | - 自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法); 7 | - 自下而上的迭代; 8 | 9 | 在《数据结构与算法 JavaScript 描述》中,作者给出了自下而上的迭代方法。但是对于递归法,作者却认为: 10 | 11 | > However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle. 12 | > 13 | > 然而,在 JavaScript 中这种方式不太可行,因为这个算法的递归深度对它来讲太深了。 14 | 15 | 16 | 说实话,我不太理解这句话。意思是 JavaScript 编译器内存太小,递归太深容易造成内存溢出吗?还望有大神能够指教。 17 | 18 | 和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。 19 | 20 | 21 | ## 2. 算法步骤 22 | 23 | 1. 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列; 24 | 25 | 2. 设定两个指针,最初位置分别为两个已经排序序列的起始位置; 26 | 27 | 3. 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置; 28 | 29 | 4. 重复步骤 3 直到某一指针达到序列尾; 30 | 31 | 5. 将另一序列剩下的所有元素直接复制到合并序列尾。 32 | 33 | 34 | ## 3. 动图演示 35 | 36 | ![动图演示](res/mergeSort.gif) 37 | 38 | 39 | ## 4. JavaScript 代码实现 40 | 41 | ```js 42 | function mergeSort(arr) { // 采用自上而下的递归方法 43 | var len = arr.length; 44 | if(len < 2) { 45 | return arr; 46 | } 47 | var middle = Math.floor(len / 2), 48 | left = arr.slice(0, middle), 49 | right = arr.slice(middle); 50 | return merge(mergeSort(left), mergeSort(right)); 51 | } 52 | 53 | function merge(left, right) 54 | { 55 | var result = []; 56 | 57 | while (left.length && right.length) { 58 | if (left[0] <= right[0]) { 59 | result.push(left.shift()); 60 | } else { 61 | result.push(right.shift()); 62 | } 63 | } 64 | 65 | while (left.length) 66 | result.push(left.shift()); 67 | 68 | while (right.length) 69 | result.push(right.shift()); 70 | 71 | return result; 72 | } 73 | ``` 74 | 75 | ## 5. Python 代码实现 76 | 77 | ```python 78 | def mergeSort(arr): 79 | import math 80 | if(len(arr)<2): 81 | return arr 82 | middle = math.floor(len(arr)/2) 83 | left, right = arr[0:middle], arr[middle:] 84 | return merge(mergeSort(left), mergeSort(right)) 85 | 86 | def merge(left,right): 87 | result = [] 88 | while left and right: 89 | if left[0] <= right[0]: 90 | result.append(left.pop(0)); 91 | else: 92 | result.append(right.pop(0)); 93 | while left: 94 | result.append(left.pop(0)); 95 | while right: 96 | result.append(right.pop(0)); 97 | return result 98 | ``` 99 | 100 | ## 6. Go 代码实现 101 | 102 | ```go 103 | func mergeSort(arr []int) []int { 104 | length := len(arr) 105 | if length < 2 { 106 | return arr 107 | } 108 | middle := length / 2 109 | left := arr[0:middle] 110 | right := arr[middle:] 111 | return merge(mergeSort(left), mergeSort(right)) 112 | } 113 | 114 | func merge(left []int, right []int) []int { 115 | var result []int 116 | for len(left) != 0 && len(right) != 0 { 117 | if left[0] <= right[0] { 118 | result = append(result, left[0]) 119 | left = left[1:] 120 | } else { 121 | result = append(result, right[0]) 122 | right = right[1:] 123 | } 124 | } 125 | 126 | for len(left) != 0 { 127 | result = append(result, left[0]) 128 | left = left[1:] 129 | } 130 | 131 | for len(right) != 0 { 132 | result = append(result, right[0]) 133 | right = right[1:] 134 | } 135 | 136 | return result 137 | } 138 | ``` 139 | 140 | ## 7. Java 代码实现 141 | 142 | ```java 143 | public class MergeSort implements IArraySort { 144 | 145 | @Override 146 | public int[] sort(int[] sourceArray) throws Exception { 147 | // 对 arr 进行拷贝,不改变参数内容 148 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 149 | 150 | if (arr.length < 2) { 151 | return arr; 152 | } 153 | int middle = (int) Math.floor(arr.length / 2); 154 | 155 | int[] left = Arrays.copyOfRange(arr, 0, middle); 156 | int[] right = Arrays.copyOfRange(arr, middle, arr.length); 157 | 158 | return merge(sort(left), sort(right)); 159 | } 160 | 161 | protected int[] merge(int[] left, int[] right) { 162 | int[] result = new int[left.length + right.length]; 163 | int i = 0; 164 | while (left.length > 0 && right.length > 0) { 165 | if (left[0] <= right[0]) { 166 | result[i++] = left[0]; 167 | left = Arrays.copyOfRange(left, 1, left.length); 168 | } else { 169 | result[i++] = right[0]; 170 | right = Arrays.copyOfRange(right, 1, right.length); 171 | } 172 | } 173 | 174 | while (left.length > 0) { 175 | result[i++] = left[0]; 176 | left = Arrays.copyOfRange(left, 1, left.length); 177 | } 178 | 179 | while (right.length > 0) { 180 | result[i++] = right[0]; 181 | right = Arrays.copyOfRange(right, 1, right.length); 182 | } 183 | 184 | return result; 185 | } 186 | 187 | } 188 | ``` 189 | 190 | ## 8. PHP 代码实现 191 | 192 | ```php 193 | function mergeSort($arr) 194 | { 195 | $len = count($arr); 196 | if ($len < 2) { 197 | return $arr; 198 | } 199 | $middle = floor($len / 2); 200 | $left = array_slice($arr, 0, $middle); 201 | $right = array_slice($arr, $middle); 202 | return merge(mergeSort($left), mergeSort($right)); 203 | } 204 | 205 | function merge($left, $right) 206 | { 207 | $result = []; 208 | 209 | while (count($left) > 0 && count($right) > 0) { 210 | if ($left[0] <= $right[0]) { 211 | $result[] = array_shift($left); 212 | } else { 213 | $result[] = array_shift($right); 214 | } 215 | } 216 | 217 | while (count($left)) 218 | $result[] = array_shift($left); 219 | 220 | while (count($right)) 221 | $result[] = array_shift($right); 222 | 223 | return $result; 224 | } 225 | ``` 226 | 227 | ## 9. C++ 代码实现 228 | 229 | ```cpp 230 | void merge(vector& arr, int l, int mid, int r) { 231 | int index = 0; 232 | int ptrL = l; 233 | int ptrR = mid; 234 | static vectortempary; 235 | if (arr.size() > tempary.size()) { 236 | tempary.resize(arr.size()); 237 | } 238 | while (ptrL != mid && ptrR != r) { 239 | if (arr[ptrL] < arr[ptrR]) { 240 | tempary[index++] = arr[ptrL++]; 241 | } else { 242 | tempary[index++] = arr[ptrR++]; 243 | } 244 | } 245 | while (ptrL != mid) { 246 | tempary[index++] = arr[ptrL++]; 247 | } 248 | while (ptrR != r) { 249 | tempary[index++] = arr[ptrR++]; 250 | } 251 | copy(tempary.begin(), tempary.begin() + index, arr.begin() + l); 252 | } 253 | void mergeSort(vector& arr, int l, int r) { // sort the range [l, r) in arr 254 | if (r - l <= 1) { 255 | return; 256 | } 257 | int mid = (l + r) / 2; 258 | mergeSort(arr, l, mid); 259 | mergeSort(arr, mid, r); 260 | merge(arr, l, mid, r); 261 | } 262 | ``` 263 | -------------------------------------------------------------------------------- /6.quickSort.md: -------------------------------------------------------------------------------- 1 | # 快速排序 2 | 3 | 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。 4 | 5 | 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。 6 | 7 | 快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。 8 | 9 | 快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好,可是这是为什么呢,我也不知道。好在我的强迫症又犯了,查了 N 多资料终于在《算法艺术与信息学竞赛》上找到了满意的答案: 10 | 11 | > 快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。 12 | 13 | 14 | ## 1. 算法步骤 15 | 16 | 1. 从数列中挑出一个元素,称为 “基准”(pivot); 17 | 18 | 2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作; 19 | 20 | 3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序; 21 | 22 | 递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。 23 | 24 | 25 | ## 2. 动图演示 26 | 27 | ![动图演示](res/quickSort.gif) 28 | 29 | 30 | ## 3. JavaScript 代码实现 31 | 32 | ```js 33 | function quickSort(arr, left, right) { 34 | var len = arr.length, 35 | partitionIndex, 36 | left = typeof left != 'number' ? 0 : left, 37 | right = typeof right != 'number' ? len - 1 : right; 38 | 39 | if (left < right) { 40 | partitionIndex = partition(arr, left, right); 41 | quickSort(arr, left, partitionIndex-1); 42 | quickSort(arr, partitionIndex+1, right); 43 | } 44 | return arr; 45 | } 46 | 47 | function partition(arr, left ,right) { // 分区操作 48 | var pivot = left, // 设定基准值(pivot) 49 | index = pivot + 1; 50 | for (var i = index; i <= right; i++) { 51 | if (arr[i] < arr[pivot]) { 52 | swap(arr, i, index); 53 | index++; 54 | } 55 | } 56 | swap(arr, pivot, index - 1); 57 | return index-1; 58 | } 59 | 60 | function swap(arr, i, j) { 61 | var temp = arr[i]; 62 | arr[i] = arr[j]; 63 | arr[j] = temp; 64 | } 65 | function partition2(arr, low, high) { 66 | let pivot = arr[low]; 67 | while (low < high) { 68 | while (low < high && arr[high] > pivot) { 69 | --high; 70 | } 71 | arr[low] = arr[high]; 72 | while (low < high && arr[low] <= pivot) { 73 | ++low; 74 | } 75 | arr[high] = arr[low]; 76 | } 77 | arr[low] = pivot; 78 | return low; 79 | } 80 | 81 | function quickSort2(arr, low, high) { 82 | if (low < high) { 83 | let pivot = partition2(arr, low, high); 84 | quickSort2(arr, low, pivot - 1); 85 | quickSort2(arr, pivot + 1, high); 86 | } 87 | return arr; 88 | } 89 | 90 | ``` 91 | 92 | 93 | ## 4. Python 代码实现 94 | 95 | ```python 96 | def quickSort(arr, left=None, right=None): 97 | left = 0 if not isinstance(left,(int, float)) else left 98 | right = len(arr)-1 if not isinstance(right,(int, float)) else right 99 | if left < right: 100 | partitionIndex = partition(arr, left, right) 101 | quickSort(arr, left, partitionIndex-1) 102 | quickSort(arr, partitionIndex+1, right) 103 | return arr 104 | 105 | def partition(arr, left, right): 106 | pivot = left 107 | index = pivot+1 108 | i = index 109 | while i <= right: 110 | if arr[i] < arr[pivot]: 111 | swap(arr, i, index) 112 | index+=1 113 | i+=1 114 | swap(arr,pivot,index-1) 115 | return index-1 116 | 117 | def swap(arr, i, j): 118 | arr[i], arr[j] = arr[j], arr[i] 119 | ``` 120 | 121 | ## 5. Go 代码实现 122 | 123 | ```go 124 | func quickSort(arr []int) []int { 125 | return _quickSort(arr, 0, len(arr)-1) 126 | } 127 | 128 | func _quickSort(arr []int, left, right int) []int { 129 | if left < right { 130 | partitionIndex := partition(arr, left, right) 131 | _quickSort(arr, left, partitionIndex-1) 132 | _quickSort(arr, partitionIndex+1, right) 133 | } 134 | return arr 135 | } 136 | 137 | func partition(arr []int, left, right int) int { 138 | pivot := left 139 | index := pivot + 1 140 | 141 | for i := index; i <= right; i++ { 142 | if arr[i] < arr[pivot] { 143 | swap(arr, i, index) 144 | index += 1 145 | } 146 | } 147 | swap(arr, pivot, index-1) 148 | return index - 1 149 | } 150 | 151 | func swap(arr []int, i, j int) { 152 | arr[i], arr[j] = arr[j], arr[i] 153 | } 154 | ``` 155 | 156 | ## 6. C++版 157 | 158 | 159 | ```C++ 160 | //严蔚敏《数据结构》标准分割函数 161 | Paritition1(int A[], int low, int high) { 162 | int pivot = A[low]; 163 | while (low < high) { 164 | while (low < high && A[high] >= pivot) { 165 | --high; 166 | } 167 | A[low] = A[high]; 168 | while (low < high && A[low] <= pivot) { 169 | ++low; 170 | } 171 | A[high] = A[low]; 172 | } 173 | A[low] = pivot; 174 | return low; 175 | } 176 | 177 | void QuickSort(int A[], int low, int high) //快排母函数 178 | { 179 | if (low < high) { 180 | int pivot = Paritition1(A, low, high); 181 | QuickSort(A, low, pivot - 1); 182 | QuickSort(A, pivot + 1, high); 183 | } 184 | } 185 | ``` 186 | 187 | ## 7. Java 代码实现 188 | 189 | ```java 190 | public class QuickSort implements IArraySort { 191 | 192 | @Override 193 | public int[] sort(int[] sourceArray) throws Exception { 194 | // 对 arr 进行拷贝,不改变参数内容 195 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 196 | 197 | return quickSort(arr, 0, arr.length - 1); 198 | } 199 | 200 | private int[] quickSort(int[] arr, int left, int right) { 201 | if (left < right) { 202 | int partitionIndex = partition(arr, left, right); 203 | quickSort(arr, left, partitionIndex - 1); 204 | quickSort(arr, partitionIndex + 1, right); 205 | } 206 | return arr; 207 | } 208 | 209 | private int partition(int[] arr, int left, int right) { 210 | // 设定基准值(pivot) 211 | int pivot = left; 212 | int index = pivot + 1; 213 | for (int i = index; i <= right; i++) { 214 | if (arr[i] < arr[pivot]) { 215 | swap(arr, i, index); 216 | index++; 217 | } 218 | } 219 | swap(arr, pivot, index - 1); 220 | return index - 1; 221 | } 222 | 223 | private void swap(int[] arr, int i, int j) { 224 | int temp = arr[i]; 225 | arr[i] = arr[j]; 226 | arr[j] = temp; 227 | } 228 | 229 | } 230 | ``` 231 | 232 | ## 8. PHP 代码实现 233 | 234 | ```php 235 | function quickSort($arr) 236 | { 237 | if (count($arr) <= 1) 238 | return $arr; 239 | $middle = $arr[0]; 240 | $leftArray = array(); 241 | $rightArray = array(); 242 | 243 | for ($i = 1; $i < count($arr); $i++) { 244 | if ($arr[$i] > $middle) 245 | $rightArray[] = $arr[$i]; 246 | else 247 | $leftArray[] = $arr[$i]; 248 | } 249 | $leftArray = quickSort($leftArray); 250 | $leftArray[] = $middle; 251 | 252 | $rightArray = quickSort($rightArray); 253 | return array_merge($leftArray, $rightArray); 254 | } 255 | ``` 256 | -------------------------------------------------------------------------------- /7.heapSort.md: -------------------------------------------------------------------------------- 1 | # 堆排序 2 | 3 | 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法: 4 | 5 | 1. 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列; 6 | 2. 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列; 7 | 8 | 堆排序的平均时间复杂度为 Ο(nlogn)。 9 | 10 | 11 | ## 1. 算法步骤 12 | 13 | 1. 将待排序序列构建成一个堆 H[0……n-1],根据(升序降序需求)选择大顶堆或小顶堆; 14 | 15 | 2. 把堆首(最大值)和堆尾互换; 16 | 17 | 3. 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置; 18 | 19 | 4. 重复步骤 2,直到堆的尺寸为 1。 20 | 21 | 22 | ## 2. 动图演示 23 | 24 | ![动图演示](res/heapSort.gif) 25 | 26 | 27 | ## 3. JavaScript 代码实现 28 | 29 | ```js 30 | var len; // 因为声明的多个函数都需要数据长度,所以把len设置成为全局变量 31 | 32 | function buildMaxHeap(arr) { // 建立大顶堆 33 | len = arr.length; 34 | for (var i = Math.floor(len/2); i >= 0; i--) { 35 | heapify(arr, i); 36 | } 37 | } 38 | 39 | function heapify(arr, i) { // 堆调整 40 | var left = 2 * i + 1, 41 | right = 2 * i + 2, 42 | largest = i; 43 | 44 | if (left < len && arr[left] > arr[largest]) { 45 | largest = left; 46 | } 47 | 48 | if (right < len && arr[right] > arr[largest]) { 49 | largest = right; 50 | } 51 | 52 | if (largest != i) { 53 | swap(arr, i, largest); 54 | heapify(arr, largest); 55 | } 56 | } 57 | 58 | function swap(arr, i, j) { 59 | var temp = arr[i]; 60 | arr[i] = arr[j]; 61 | arr[j] = temp; 62 | } 63 | 64 | function heapSort(arr) { 65 | buildMaxHeap(arr); 66 | 67 | for (var i = arr.length-1; i > 0; i--) { 68 | swap(arr, 0, i); 69 | len--; 70 | heapify(arr, 0); 71 | } 72 | return arr; 73 | } 74 | ``` 75 | ## 4. Python 代码实现 76 | 77 | ```python 78 | def buildMaxHeap(arr): 79 | import math 80 | for i in range(math.floor(len(arr)/2),-1,-1): 81 | heapify(arr,i) 82 | 83 | def heapify(arr, i): 84 | left = 2*i+1 85 | right = 2*i+2 86 | largest = i 87 | if left < arrLen and arr[left] > arr[largest]: 88 | largest = left 89 | if right < arrLen and arr[right] > arr[largest]: 90 | largest = right 91 | 92 | if largest != i: 93 | swap(arr, i, largest) 94 | heapify(arr, largest) 95 | 96 | def swap(arr, i, j): 97 | arr[i], arr[j] = arr[j], arr[i] 98 | 99 | def heapSort(arr): 100 | global arrLen 101 | arrLen = len(arr) 102 | buildMaxHeap(arr) 103 | for i in range(len(arr)-1,0,-1): 104 | swap(arr,0,i) 105 | arrLen -=1 106 | heapify(arr, 0) 107 |    return arr 108 | ``` 109 | 110 | ## 5. Go 代码实现 111 | 112 | ```go 113 | func heapSort(arr []int) []int { 114 | arrLen := len(arr) 115 | buildMaxHeap(arr, arrLen) 116 | for i := arrLen - 1; i >= 0; i-- { 117 | swap(arr, 0, i) 118 | arrLen -= 1 119 | heapify(arr, 0, arrLen) 120 | } 121 | return arr 122 | } 123 | 124 | func buildMaxHeap(arr []int, arrLen int) { 125 | for i := arrLen / 2; i >= 0; i-- { 126 | heapify(arr, i, arrLen) 127 | } 128 | } 129 | 130 | func heapify(arr []int, i, arrLen int) { 131 | left := 2*i + 1 132 | right := 2*i + 2 133 | largest := i 134 | if left < arrLen && arr[left] > arr[largest] { 135 | largest = left 136 | } 137 | if right < arrLen && arr[right] > arr[largest] { 138 | largest = right 139 | } 140 | if largest != i { 141 | swap(arr, i, largest) 142 | heapify(arr, largest, arrLen) 143 | } 144 | } 145 | 146 | func swap(arr []int, i, j int) { 147 | arr[i], arr[j] = arr[j], arr[i] 148 | } 149 | ``` 150 | 151 | ## 6. Java 代码实现 152 | 153 | ```java 154 | public class HeapSort implements IArraySort { 155 | 156 | @Override 157 | public int[] sort(int[] sourceArray) throws Exception { 158 | // 对 arr 进行拷贝,不改变参数内容 159 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 160 | 161 | int len = arr.length; 162 | 163 | buildMaxHeap(arr, len); 164 | 165 | for (int i = len - 1; i > 0; i--) { 166 | swap(arr, 0, i); 167 | len--; 168 | heapify(arr, 0, len); 169 | } 170 | return arr; 171 | } 172 | 173 | private void buildMaxHeap(int[] arr, int len) { 174 | for (int i = (int) Math.floor(len / 2); i >= 0; i--) { 175 | heapify(arr, i, len); 176 | } 177 | } 178 | 179 | private void heapify(int[] arr, int i, int len) { 180 | int left = 2 * i + 1; 181 | int right = 2 * i + 2; 182 | int largest = i; 183 | 184 | if (left < len && arr[left] > arr[largest]) { 185 | largest = left; 186 | } 187 | 188 | if (right < len && arr[right] > arr[largest]) { 189 | largest = right; 190 | } 191 | 192 | if (largest != i) { 193 | swap(arr, i, largest); 194 | heapify(arr, largest, len); 195 | } 196 | } 197 | 198 | private void swap(int[] arr, int i, int j) { 199 | int temp = arr[i]; 200 | arr[i] = arr[j]; 201 | arr[j] = temp; 202 | } 203 | 204 | } 205 | ``` 206 | 207 | ## 7. PHP 代码实现 208 | 209 | ```php 210 | function buildMaxHeap(&$arr) 211 | { 212 | global $len; 213 | for ($i = floor($len/2); $i >= 0; $i--) { 214 | heapify($arr, $i); 215 | } 216 | } 217 | 218 | function heapify(&$arr, $i) 219 | { 220 | global $len; 221 | $left = 2 * $i + 1; 222 | $right = 2 * $i + 2; 223 | $largest = $i; 224 | 225 | if ($left < $len && $arr[$left] > $arr[$largest]) { 226 | $largest = $left; 227 | } 228 | 229 | if ($right < $len && $arr[$right] > $arr[$largest]) { 230 | $largest = $right; 231 | } 232 | 233 | if ($largest != $i) { 234 | swap($arr, $i, $largest); 235 | heapify($arr, $largest); 236 | } 237 | } 238 | 239 | function swap(&$arr, $i, $j) 240 | { 241 | $temp = $arr[$i]; 242 | $arr[$i] = $arr[$j]; 243 | $arr[$j] = $temp; 244 | } 245 | 246 | function heapSort($arr) { 247 | global $len; 248 | $len = count($arr); 249 | buildMaxHeap($arr); 250 | for ($i = count($arr) - 1; $i > 0; $i--) { 251 | swap($arr, 0, $i); 252 | $len--; 253 | heapify($arr, 0); 254 | } 255 | return $arr; 256 | } 257 | ``` 258 | -------------------------------------------------------------------------------- /8.countingSort.md: -------------------------------------------------------------------------------- 1 | # 计数排序 2 | 3 | 计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 4 | 5 | ## 1. 动图演示 6 | 7 | ![动图演示](res/countingSort.gif) 8 | 9 | 10 | ## 2. JavaScript 代码实现 11 | 12 | ```js 13 | function countingSort(arr, maxValue) { 14 | var bucket = new Array(maxValue+1), 15 | sortedIndex = 0; 16 | arrLen = arr.length, 17 | bucketLen = maxValue + 1; 18 | 19 | for (var i = 0; i < arrLen; i++) { 20 | if (!bucket[arr[i]]) { 21 | bucket[arr[i]] = 0; 22 | } 23 | bucket[arr[i]]++; 24 | } 25 | 26 | for (var j = 0; j < bucketLen; j++) { 27 | while(bucket[j] > 0) { 28 | arr[sortedIndex++] = j; 29 | bucket[j]--; 30 | } 31 | } 32 | 33 | return arr; 34 | } 35 | ``` 36 | 37 | ## 3. Python 代码实现 38 | 39 | 40 | ```python 41 | def countingSort(arr, maxValue): 42 | bucketLen = maxValue+1 43 | bucket = [0]*bucketLen 44 | sortedIndex =0 45 | arrLen = len(arr) 46 | for i in range(arrLen): 47 | if not bucket[arr[i]]: 48 | bucket[arr[i]]=0 49 | bucket[arr[i]]+=1 50 | for j in range(bucketLen): 51 | while bucket[j]>0: 52 | arr[sortedIndex] = j 53 | sortedIndex+=1 54 | bucket[j]-=1 55 | return arr 56 | ``` 57 | 58 | ## 4. Go 代码实现 59 | 60 | ```go 61 | func countingSort(arr []int, maxValue int) []int { 62 | bucketLen := maxValue + 1 63 | bucket := make([]int, bucketLen) // 初始为0的数组 64 | 65 | sortedIndex := 0 66 | length := len(arr) 67 | 68 | for i := 0; i < length; i++ { 69 | bucket[arr[i]] += 1 70 | } 71 | 72 | for j := 0; j < bucketLen; j++ { 73 | for bucket[j] > 0 { 74 | arr[sortedIndex] = j 75 | sortedIndex += 1 76 | bucket[j] -= 1 77 | } 78 | } 79 | 80 | return arr 81 | } 82 | ``` 83 | 84 | ## 5. Java 代码实现 85 | 86 | ```java 87 | public class CountingSort implements IArraySort { 88 | 89 | @Override 90 | public int[] sort(int[] sourceArray) throws Exception { 91 | // 对 arr 进行拷贝,不改变参数内容 92 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 93 | 94 | int maxValue = getMaxValue(arr); 95 | 96 | return countingSort(arr, maxValue); 97 | } 98 | 99 | private int[] countingSort(int[] arr, int maxValue) { 100 | int bucketLen = maxValue + 1; 101 | int[] bucket = new int[bucketLen]; 102 | 103 | for (int value : arr) { 104 | bucket[value]++; 105 | } 106 | 107 | int sortedIndex = 0; 108 | for (int j = 0; j < bucketLen; j++) { 109 | while (bucket[j] > 0) { 110 | arr[sortedIndex++] = j; 111 | bucket[j]--; 112 | } 113 | } 114 | return arr; 115 | } 116 | 117 | private int getMaxValue(int[] arr) { 118 | int maxValue = arr[0]; 119 | for (int value : arr) { 120 | if (maxValue < value) { 121 | maxValue = value; 122 | } 123 | } 124 | return maxValue; 125 | } 126 | 127 | } 128 | ``` 129 | 130 | ## 6. PHP 代码实现 131 | 132 | ```php 133 | function countingSort($arr, $maxValue = null) 134 | { 135 | if ($maxValue === null) { 136 | $maxValue = max($arr); 137 | } 138 | for ($m = 0; $m < $maxValue + 1; $m++) { 139 | $bucket[] = null; 140 | } 141 | 142 | $arrLen = count($arr); 143 | for ($i = 0; $i < $arrLen; $i++) { 144 | if (!array_key_exists($arr[$i], $bucket)) { 145 | $bucket[$arr[$i]] = 0; 146 | } 147 | $bucket[$arr[$i]]++; 148 | } 149 | 150 | $sortedIndex = 0; 151 | foreach ($bucket as $key => $len) { 152 | if($len !== null){ 153 | for($j = 0; $j < $len; $j++){ 154 | $arr[$sortedIndex++] = $key; 155 | } 156 | } 157 | } 158 | 159 | return $arr; 160 | } 161 | ``` -------------------------------------------------------------------------------- /9.bucketSort.md: -------------------------------------------------------------------------------- 1 | # 桶排序 2 | 3 | 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。为了使桶排序更加高效,我们需要做到这两点: 4 | 5 | 1. 在额外空间充足的情况下,尽量增大桶的数量 6 | 2. 使用的映射函数能够将输入的 N 个数据均匀的分配到 K 个桶中 7 | 8 | 同时,对于桶中元素的排序,选择何种比较排序算法对于性能的影响至关重要。 9 | 10 | 11 | ## 1. 什么时候最快 12 | 13 | 当输入的数据可以均匀的分配到每一个桶中。 14 | 15 | 16 | ## 2. 什么时候最慢 17 | 18 | 当输入的数据被分配到了同一个桶中。 19 | 20 | 21 | ## 3. JavaScript 代码实现 22 | 23 | ```js 24 | function bucketSort(arr, bucketSize) { 25 | if (arr.length === 0) { 26 | return arr; 27 | } 28 | 29 | var i; 30 | var minValue = arr[0]; 31 | var maxValue = arr[0]; 32 | for (i = 1; i < arr.length; i++) { 33 | if (arr[i] < minValue) { 34 | minValue = arr[i]; // 输入数据的最小值 35 | } else if (arr[i] > maxValue) { 36 | maxValue = arr[i]; // 输入数据的最大值 37 | } 38 | } 39 | 40 | //桶的初始化 41 | var DEFAULT_BUCKET_SIZE = 5; // 设置桶的默认数量为5 42 | bucketSize = bucketSize || DEFAULT_BUCKET_SIZE; 43 | var bucketCount = Math.floor((maxValue - minValue) / bucketSize) + 1; 44 | var buckets = new Array(bucketCount); 45 | for (i = 0; i < buckets.length; i++) { 46 | buckets[i] = []; 47 | } 48 | 49 | //利用映射函数将数据分配到各个桶中 50 | for (i = 0; i < arr.length; i++) { 51 | buckets[Math.floor((arr[i] - minValue) / bucketSize)].push(arr[i]); 52 | } 53 | 54 | arr.length = 0; 55 | for (i = 0; i < buckets.length; i++) { 56 | insertionSort(buckets[i]); // 对每个桶进行排序,这里使用了插入排序 57 | for (var j = 0; j < buckets[i].length; j++) { 58 | arr.push(buckets[i][j]); 59 | } 60 | } 61 | 62 | return arr; 63 | } 64 | ``` 65 | 66 | ## 4. Java 代码实现 67 | 68 | ```java 69 | public class BucketSort implements IArraySort { 70 | 71 | private static final InsertSort insertSort = new InsertSort(); 72 | 73 | @Override 74 | public int[] sort(int[] sourceArray) throws Exception { 75 | // 对 arr 进行拷贝,不改变参数内容 76 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 77 | 78 | return bucketSort(arr, 5); 79 | } 80 | 81 | private int[] bucketSort(int[] arr, int bucketSize) throws Exception { 82 | if (arr.length == 0) { 83 | return arr; 84 | } 85 | 86 | int minValue = arr[0]; 87 | int maxValue = arr[0]; 88 | for (int value : arr) { 89 | if (value < minValue) { 90 | minValue = value; 91 | } else if (value > maxValue) { 92 | maxValue = value; 93 | } 94 | } 95 | 96 | int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1; 97 | int[][] buckets = new int[bucketCount][0]; 98 | 99 | // 利用映射函数将数据分配到各个桶中 100 | for (int i = 0; i < arr.length; i++) { 101 | int index = (int) Math.floor((arr[i] - minValue) / bucketSize); 102 | buckets[index] = arrAppend(buckets[index], arr[i]); 103 | } 104 | 105 | int arrIndex = 0; 106 | for (int[] bucket : buckets) { 107 | if (bucket.length <= 0) { 108 | continue; 109 | } 110 | // 对每个桶进行排序,这里使用了插入排序 111 | bucket = insertSort.sort(bucket); 112 | for (int value : bucket) { 113 | arr[arrIndex++] = value; 114 | } 115 | } 116 | 117 | return arr; 118 | } 119 | 120 | /** 121 | * 自动扩容,并保存数据 122 | * 123 | * @param arr 124 | * @param value 125 | */ 126 | private int[] arrAppend(int[] arr, int value) { 127 | arr = Arrays.copyOf(arr, arr.length + 1); 128 | arr[arr.length - 1] = value; 129 | return arr; 130 | } 131 | 132 | } 133 | ``` 134 | 135 | ## 5. PHP 代码实现 136 | 137 | ```php 138 | function bucketSort($arr, $bucketSize = 5) 139 | { 140 | if (count($arr) === 0) { 141 | return $arr; 142 | } 143 | 144 | $minValue = $arr[0]; 145 | $maxValue = $arr[0]; 146 | for ($i = 1; $i < count($arr); $i++) { 147 | if ($arr[$i] < $minValue) { 148 | $minValue = $arr[$i]; 149 | } else if ($arr[$i] > $maxValue) { 150 | $maxValue = $arr[$i]; 151 | } 152 | } 153 | 154 | $bucketCount = floor(($maxValue - $minValue) / $bucketSize) + 1; 155 | $buckets = array(); 156 | for ($i = 0; $i < count($buckets); $i++) { 157 | $buckets[$i] = []; 158 | } 159 | 160 | for ($i = 0; $i < count($arr); $i++) { 161 | $buckets[floor(($arr[$i] - $minValue) / $bucketSize)][] = $arr[$i]; 162 | } 163 | 164 | $arr = array(); 165 | for ($i = 0; $i < count($buckets); $i++) { 166 | $bucketTmp = $buckets[$i]; 167 | sort($bucketTmp); 168 | for ($j = 0; $j < count($bucketTmp); $j++) { 169 | $arr[] = $bucketTmp[$j]; 170 | } 171 | } 172 | 173 | return $arr; 174 | } 175 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 十大经典排序算法 2 | 3 | [![Build Status](https://travis-ci.org/hustcc/JS-Sorting-Algorithm.svg?branch=master)](https://travis-ci.org/hustcc/JS-Sorting-Algorithm) 4 | 5 | 排序算法是《数据结构与算法》中最基本的算法之一。 6 | 7 | 排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:**插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序**等。用一张图概括: 8 | 9 | ![十大经典排序算法 概览截图](res/sort.png) 10 | 11 | 12 | **关于时间复杂度**: 13 | 14 | 1. 平方阶 (O(n2)) 排序 15 | 各类简单排序:直接插入、直接选择和冒泡排序。 16 | 2. 线性对数阶 (O(nlog2n)) 排序 17 | 快速排序、堆排序和归并排序; 18 | 3. O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 19 | 希尔排序 20 | 4. 线性阶 (O(n)) 排序 21 | 基数排序,此外还有桶、箱排序。 22 | 23 | 24 | **关于稳定性**: 25 | 26 | 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。 27 | 28 | 不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。 29 | 30 | 31 | **名词解释**: 32 | 33 | **n**:数据规模 34 | 35 | **k**:“桶”的个数 36 | 37 | **In-place**:占用常数内存,不占用额外内存 38 | 39 | **Out-place**:占用额外内存 40 | 41 | **稳定性**:排序后 2 个相等键值的顺序和排序之前它们的顺序相同 42 | 43 | ---- 44 | 45 | 46 | **GitBook 内容大纲** 47 | 48 | 1. [冒泡排序](1.bubbleSort.md) 49 | 2. [选择排序](2.selectionSort.md) 50 | 3. [插入排序](3.insertionSort.md) 51 | 4. [希尔排序](4.shellSort.md) 52 | 5. [归并排序](5.mergeSort.md) 53 | 6. [快速排序](6.quickSort.md) 54 | 7. [堆排序](7.heapSort.md) 55 | 8. [计数排序](8.countingSort.md) 56 | 9. [桶排序](9.bucketSort.md) 57 | 10. [基数排序](10.radixSort.md) 58 | 59 | ---- 60 | 61 | 本书内容几乎完全来源于网络。 62 | 63 | 开源项目地址:[https://github.com/hustcc/JS-Sorting-Algorithm](https://github.com/hustcc/JS-Sorting-Algorithm),整理人 [hustcc](https://github.com/hustcc)。 64 | 65 | GitBook 在线阅读地址:[https://sort.hust.cc/](https://sort.hust.cc/)。 66 | 67 | 本项目使用 [lint-md](https://github.com/hustcc/lint-md) 进行中文 Markdown 文件的格式检查,务必在提交 Pr 之前,保证 Markdown 格式正确。 68 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | 1. [冒泡排序](1.bubbleSort.md) 4 | 2. [选择排序](2.selectionSort.md) 5 | 3. [插入排序](3.insertionSort.md) 6 | 4. [希尔排序](4.shellSort.md) 7 | 5. [归并排序](5.mergeSort.md) 8 | 6. [快速排序](6.quickSort.md) 9 | 7. [堆排序](7.heapSort.md) 10 | 8. [计数排序](8.countingSort.md) 11 | 9. [桶排序](9.bucketSort.md) 12 | 10. [基数排序](10.radixSort.md) 13 | -------------------------------------------------------------------------------- /res/bubbleSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/bubbleSort.gif -------------------------------------------------------------------------------- /res/countingSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/countingSort.gif -------------------------------------------------------------------------------- /res/heapSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/heapSort.gif -------------------------------------------------------------------------------- /res/insertionSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/insertionSort.gif -------------------------------------------------------------------------------- /res/mergeSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/mergeSort.gif -------------------------------------------------------------------------------- /res/quickSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/quickSort.gif -------------------------------------------------------------------------------- /res/radixSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/radixSort.gif -------------------------------------------------------------------------------- /res/selectionSort.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/selectionSort.gif -------------------------------------------------------------------------------- /res/sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/res/sort.png -------------------------------------------------------------------------------- /src/goSortTest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | /* global varialbe for heapsort*/ 10 | var arrLen int 11 | 12 | // 初始化 array with num 13 | func initArray(num int) []int { 14 | if num < 1 { 15 | panic("num must bigger than 1") 16 | } 17 | 18 | arr := make([]int, num) 19 | middle := num / 2 20 | // fmt.Println("middle :", middle) 21 | for i, _ := range arr { 22 | arr[i] = i - middle 23 | } 24 | return arr 25 | } 26 | 27 | // 比较 sort 前后数组是否相同 28 | func compare(arr1 []int, arr2 []int) bool { 29 | if len(arr1) != len(arr2) { 30 | return false 31 | } 32 | 33 | for i, _ := range arr1 { 34 | if arr1[i] != arr2[i] { 35 | return false 36 | } 37 | } 38 | 39 | return true 40 | } 41 | 42 | // 测试 sort func 是否有效 43 | func test_func(num int, sort func(arr []int) []int) { 44 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 45 | src := initArray(num) 46 | dest := make([]int, len(src)) 47 | perm := r.Perm(len(src)) 48 | for i, v := range perm { 49 | dest[v] = src[i] 50 | } 51 | 52 | // fmt.Println(src) 53 | // fmt.Println(dest) 54 | result := sort(dest) 55 | // fmt.Println(result) 56 | 57 | if compare(src, result) { 58 | fmt.Println("Test passed") 59 | } else { 60 | fmt.Println("Test failed") 61 | } 62 | } 63 | 64 | // bubble sort 65 | func bubbleSort(arr []int) []int { 66 | length := len(arr) 67 | for i := 0; i < length; i++ { 68 | for j := 0; j < length-1-i; j++ { 69 | if arr[j] > arr[j+1] { 70 | arr[j], arr[j+1] = arr[j+1], arr[j] 71 | } 72 | } 73 | } 74 | return arr 75 | } 76 | 77 | // selection sort 78 | func selectionSort(arr []int) []int { 79 | length := len(arr) 80 | for i := 0; i < length-1; i++ { 81 | min := i 82 | for j := i + 1; j < length; j++ { 83 | if arr[min] > arr[j] { 84 | min = j 85 | } 86 | } 87 | arr[i], arr[min] = arr[min], arr[i] 88 | } 89 | return arr 90 | } 91 | 92 | // insertion sort 93 | func insertionSort(arr []int) []int { 94 | for i := range arr { 95 | preIndex := i - 1 96 | current := arr[i] 97 | for preIndex >= 0 && arr[preIndex] > current { 98 | arr[preIndex+1] = arr[preIndex] 99 | preIndex -= 1 100 | } 101 | arr[preIndex+1] = current 102 | } 103 | return arr 104 | } 105 | 106 | // shellsort 107 | func shellSort(arr []int) []int { 108 | length := len(arr) 109 | gap := 1 110 | for gap < gap/3 { 111 | gap = gap*3 + 1 112 | } 113 | for gap > 0 { 114 | for i := gap; i < length; i++ { 115 | temp := arr[i] 116 | j := i - gap 117 | for j >= 0 && arr[j] > temp { 118 | arr[j+gap] = arr[j] 119 | j -= gap 120 | } 121 | arr[j+gap] = temp 122 | } 123 | gap = gap / 3 124 | } 125 | return arr 126 | } 127 | 128 | // merge sort 129 | func mergeSort(arr []int) []int { 130 | length := len(arr) 131 | if length < 2 { 132 | return arr 133 | } 134 | middle := length / 2 135 | left := arr[0:middle] 136 | right := arr[middle:] 137 | return merge(mergeSort(left), mergeSort(right)) 138 | } 139 | 140 | func merge(left []int, right []int) []int { 141 | var result []int 142 | for len(left) != 0 && len(right) != 0 { 143 | if left[0] <= right[0] { 144 | result = append(result, left[0]) 145 | left = left[1:] 146 | } else { 147 | result = append(result, right[0]) 148 | right = right[1:] 149 | } 150 | } 151 | 152 | for len(left) != 0 { 153 | result = append(result, left[0]) 154 | left = left[1:] 155 | } 156 | 157 | for len(right) != 0 { 158 | result = append(result, right[0]) 159 | right = right[1:] 160 | } 161 | 162 | return result 163 | } 164 | 165 | // quicksort 166 | func quickSort(arr []int) []int { 167 | return _quickSort(arr, 0, len(arr)-1) 168 | } 169 | 170 | func _quickSort(arr []int, left, right int) []int { 171 | if left < right { 172 | partitionIndex := partition(arr, left, right) 173 | _quickSort(arr, left, partitionIndex-1) 174 | _quickSort(arr, partitionIndex+1, right) 175 | } 176 | return arr 177 | } 178 | 179 | func partition(arr []int, left, right int) int { 180 | pivot := left 181 | index := pivot + 1 182 | 183 | for i := index; i <= right; i++ { 184 | if arr[i] < arr[pivot] { 185 | swap(arr, i, index) 186 | index += 1 187 | } 188 | } 189 | swap(arr, pivot, index-1) 190 | return index - 1 191 | } 192 | 193 | // heap sort 194 | func heapSort(arr []int) []int { 195 | arrLen := len(arr) 196 | buildMaxHeap(arr, arrLen) 197 | for i := arrLen - 1; i >= 0; i-- { 198 | swap(arr, 0, i) 199 | arrLen -= 1 200 | heapify(arr, 0, arrLen) 201 | } 202 | return arr 203 | } 204 | 205 | func buildMaxHeap(arr []int, arrLen int) { 206 | for i := arrLen / 2; i >= 0; i-- { 207 | heapify(arr, i, arrLen) 208 | } 209 | } 210 | 211 | func heapify(arr []int, i, arrLen int) { 212 | left := 2*i + 1 213 | right := 2*i + 2 214 | largest := i 215 | if left < arrLen && arr[left] > arr[largest] { 216 | largest = left 217 | } 218 | if right < arrLen && arr[right] > arr[largest] { 219 | largest = right 220 | } 221 | if largest != i { 222 | swap(arr, i, largest) 223 | heapify(arr, largest, arrLen) 224 | } 225 | } 226 | 227 | func swap(arr []int, i, j int) { 228 | arr[i], arr[j] = arr[j], arr[i] 229 | } 230 | 231 | func main() { 232 | num := 5000 233 | test_func(num, bubbleSort) 234 | test_func(num, selectionSort) 235 | test_func(num, insertionSort) 236 | test_func(num, shellSort) 237 | test_func(num, mergeSort) 238 | test_func(num, quickSort) 239 | test_func(num, heapSort) 240 | } 241 | -------------------------------------------------------------------------------- /src/java/main/BubbleSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 冒泡排序 5 | */ 6 | public class BubbleSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | for (int i = 1; i < arr.length; i++) { 14 | // 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。 15 | boolean flag = true; 16 | 17 | for (int j = 0; j < arr.length - i; j++) { 18 | if (arr[j] > arr[j + 1]) { 19 | int tmp = arr[j]; 20 | arr[j] = arr[j + 1]; 21 | arr[j + 1] = tmp; 22 | 23 | flag = false; 24 | } 25 | } 26 | 27 | if (flag) { 28 | break; 29 | } 30 | } 31 | return arr; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/java/main/BucketSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 桶排序 5 | */ 6 | public class BucketSort implements IArraySort { 7 | 8 | private static final InsertSort insertSort = new InsertSort(); 9 | 10 | @Override 11 | public int[] sort(int[] sourceArray) throws Exception { 12 | // 对 arr 进行拷贝,不改变参数内容 13 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 14 | 15 | return bucketSort(arr, 5); 16 | } 17 | 18 | private int[] bucketSort(int[] arr, int bucketSize) throws Exception { 19 | if (arr.length == 0) { 20 | return arr; 21 | } 22 | 23 | int minValue = arr[0]; 24 | int maxValue = arr[0]; 25 | for (int value : arr) { 26 | if (value < minValue) { 27 | minValue = value; 28 | } else if (value > maxValue) { 29 | maxValue = value; 30 | } 31 | } 32 | 33 | int bucketCount = (int) Math.floor((maxValue - minValue) / bucketSize) + 1; 34 | int[][] buckets = new int[bucketCount][0]; 35 | 36 | // 利用映射函数将数据分配到各个桶中 37 | for (int i = 0; i < arr.length; i++) { 38 | int index = (int) Math.floor((arr[i] - minValue) / bucketSize); 39 | buckets[index] = arrAppend(buckets[index], arr[i]); 40 | } 41 | 42 | int arrIndex = 0; 43 | for (int[] bucket : buckets) { 44 | if (bucket.length <= 0) { 45 | continue; 46 | } 47 | // 对每个桶进行排序,这里使用了插入排序 48 | bucket = insertSort.sort(bucket); 49 | for (int value : bucket) { 50 | arr[arrIndex++] = value; 51 | } 52 | } 53 | 54 | return arr; 55 | } 56 | 57 | /** 58 | * 自动扩容,并保存数据 59 | * 60 | * @param arr 61 | * @param value 62 | */ 63 | private int[] arrAppend(int[] arr, int value) { 64 | arr = Arrays.copyOf(arr, arr.length + 1); 65 | arr[arr.length - 1] = value; 66 | return arr; 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/java/main/CountingSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 计数排序 5 | */ 6 | public class CountingSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | int maxValue = getMaxValue(arr); 14 | 15 | return countingSort(arr, maxValue); 16 | } 17 | 18 | private int[] countingSort(int[] arr, int maxValue) { 19 | int bucketLen = maxValue + 1; 20 | int[] bucket = new int[bucketLen]; 21 | 22 | for (int value : arr) { 23 | bucket[value]++; 24 | } 25 | 26 | int sortedIndex = 0; 27 | for (int j = 0; j < bucketLen; j++) { 28 | while (bucket[j] > 0) { 29 | arr[sortedIndex++] = j; 30 | bucket[j]--; 31 | } 32 | } 33 | return arr; 34 | } 35 | 36 | private int getMaxValue(int[] arr) { 37 | int maxValue = arr[0]; 38 | for (int value : arr) { 39 | if (maxValue < value) { 40 | maxValue = value; 41 | } 42 | } 43 | return maxValue; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/java/main/HeapSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 堆排序 5 | */ 6 | public class HeapSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | int len = arr.length; 14 | 15 | buildMaxHeap(arr, len); 16 | 17 | for (int i = len - 1; i > 0; i--) { 18 | swap(arr, 0, i); 19 | len--; 20 | heapify(arr, 0, len); 21 | } 22 | return arr; 23 | } 24 | 25 | private void buildMaxHeap(int[] arr, int len) { 26 | for (int i = (int) Math.floor(len / 2); i >= 0; i--) { 27 | heapify(arr, i, len); 28 | } 29 | } 30 | 31 | private void heapify(int[] arr, int i, int len) { 32 | int left = 2 * i + 1; 33 | int right = 2 * i + 2; 34 | int largest = i; 35 | 36 | if (left < len && arr[left] > arr[largest]) { 37 | largest = left; 38 | } 39 | 40 | if (right < len && arr[right] > arr[largest]) { 41 | largest = right; 42 | } 43 | 44 | if (largest != i) { 45 | swap(arr, i, largest); 46 | heapify(arr, largest, len); 47 | } 48 | } 49 | 50 | private void swap(int[] arr, int i, int j) { 51 | int temp = arr[i]; 52 | arr[i] = arr[j]; 53 | arr[j] = temp; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/java/main/IArraySort.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by corning on 2017/12/19. 3 | */ 4 | public interface IArraySort { 5 | /** 6 | * 对数组进行排序,并返回排序后的数组 7 | * 8 | * @param sourceArray 9 | * @return 10 | * @throws Exception 11 | */ 12 | int[] sort(int[] sourceArray) throws Exception; 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/java/main/InsertSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 插入排序 5 | */ 6 | public class InsertSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的 14 | for (int i = 1; i < arr.length; i++) { 15 | 16 | // 记录要插入的数据 17 | int tmp = arr[i]; 18 | 19 | // 从已经排序的序列最右边的开始比较,找到比其小的数 20 | int j = i; 21 | while (j > 0 && tmp < arr[j - 1]) { 22 | arr[j] = arr[j - 1]; 23 | j--; 24 | } 25 | 26 | // 存在比其小的数,插入 27 | if (j != i) { 28 | arr[j] = tmp; 29 | } 30 | 31 | } 32 | return arr; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/java/main/MergeSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 归并排序 5 | */ 6 | public class MergeSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | if (arr.length < 2) { 14 | return arr; 15 | } 16 | int middle = (int) Math.floor(arr.length / 2); 17 | 18 | int[] left = Arrays.copyOfRange(arr, 0, middle); 19 | int[] right = Arrays.copyOfRange(arr, middle, arr.length); 20 | 21 | return merge(sort(left), sort(right)); 22 | } 23 | 24 | protected int[] merge(int[] left, int[] right) { 25 | int[] result = new int[left.length + right.length]; 26 | int l = 0, r = 0, len = 0; 27 | while (len < left.length + right.length) { 28 | if (left[l] <= right[r]) { 29 | result[len++] = left[l++]; 30 | 31 | if (l == left.length) { 32 | for (int i = r; i < right.length; i++) { 33 | result[len++] = right[r++]; 34 | } 35 | } 36 | } else { 37 | result[len++] = right[r++]; 38 | 39 | if (r == right.length) { 40 | for (int i = l; i < left.length; i++) { 41 | result[len++] = left[l++]; 42 | } 43 | } 44 | } 45 | } 46 | 47 | return result; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/java/main/QuickSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 快速排序 5 | */ 6 | public class QuickSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | return quickSort(arr, 0, arr.length - 1); 14 | } 15 | 16 | private int[] quickSort(int[] arr, int left, int right) { 17 | if (left < right) { 18 | int partitionIndex = partition(arr, left, right); 19 | quickSort(arr, left, partitionIndex - 1); 20 | quickSort(arr, partitionIndex + 1, right); 21 | } 22 | return arr; 23 | } 24 | 25 | private int partition(int[] arr, int left, int right) { 26 | // 设定基准值(pivot) 27 | int pivot = left; 28 | int index = pivot + 1; 29 | for (int i = index; i <= right; i++) { 30 | if (arr[i] < arr[pivot]) { 31 | swap(arr, i, index); 32 | index++; 33 | } 34 | } 35 | swap(arr, pivot, index - 1); 36 | return index - 1; 37 | } 38 | 39 | private void swap(int[] arr, int i, int j) { 40 | int temp = arr[i]; 41 | arr[i] = arr[j]; 42 | arr[j] = temp; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/java/main/RadixSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 基数排序 5 | *

6 | * 考虑负数的情况还可以参考: https://code.i-harness.com/zh-CN/q/e98fa9 7 | */ 8 | public class RadixSort implements IArraySort { 9 | 10 | @Override 11 | public int[] sort(int[] sourceArray) throws Exception { 12 | // 对 arr 进行拷贝,不改变参数内容 13 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 14 | 15 | int maxDigit = getMaxDigit(arr); 16 | return radixSort(arr, maxDigit); 17 | } 18 | 19 | /** 20 | * 获取最高位数 21 | */ 22 | private int getMaxDigit(int[] arr) { 23 | int maxValue = getMaxValue(arr); 24 | return getNumLenght(maxValue); 25 | } 26 | 27 | private int getMaxValue(int[] arr) { 28 | int maxValue = arr[0]; 29 | for (int value : arr) { 30 | if (maxValue < value) { 31 | maxValue = value; 32 | } 33 | } 34 | return maxValue; 35 | } 36 | 37 | protected int getNumLenght(long num) { 38 | if (num == 0) { 39 | return 1; 40 | } 41 | int lenght = 0; 42 | for (long temp = num; temp != 0; temp /= 10) { 43 | lenght++; 44 | } 45 | return lenght; 46 | } 47 | 48 | private int[] radixSort(int[] arr, int maxDigit) { 49 | int mod = 10; 50 | int dev = 1; 51 | 52 | for (int i = 0; i < maxDigit; i++, dev *= 10, mod *= 10) { 53 | // 考虑负数的情况,这里扩展一倍队列数,其中 [0-9]对应负数,[10-19]对应正数 (bucket + 10) 54 | int[][] counter = new int[mod * 2][0]; 55 | 56 | for (int j = 0; j < arr.length; j++) { 57 | int bucket = ((arr[j] % mod) / dev) + mod; 58 | counter[bucket] = arrayAppend(counter[bucket], arr[j]); 59 | } 60 | 61 | int pos = 0; 62 | for (int[] bucket : counter) { 63 | for (int value : bucket) { 64 | arr[pos++] = value; 65 | } 66 | } 67 | } 68 | 69 | return arr; 70 | } 71 | 72 | /** 73 | * 自动扩容,并保存数据 74 | * 75 | * @param arr 76 | * @param value 77 | */ 78 | private int[] arrayAppend(int[] arr, int value) { 79 | arr = Arrays.copyOf(arr, arr.length + 1); 80 | arr[arr.length - 1] = value; 81 | return arr; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/java/main/SelectionSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 选择排序 5 | */ 6 | public class SelectionSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 11 | 12 | // 总共要经过 N-1 轮比较 13 | for (int i = 0; i < arr.length - 1; i++) { 14 | int min = i; 15 | 16 | // 每轮需要比较的次数 N-i 17 | for (int j = i + 1; j < arr.length; j++) { 18 | if (arr[j] < arr[min]) { 19 | // 记录目前能找到的最小值元素的下标 20 | min = j; 21 | } 22 | } 23 | 24 | // 将找到的最小值和i位置所在的值进行交换 25 | if (i != min) { 26 | int tmp = arr[i]; 27 | arr[i] = arr[min]; 28 | arr[min] = tmp; 29 | } 30 | 31 | } 32 | return arr; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/java/main/ShellSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /** 4 | * 希尔排序 5 | */ 6 | public class ShellSort implements IArraySort { 7 | 8 | @Override 9 | public int[] sort(int[] sourceArray) throws Exception { 10 | // 对 arr 进行拷贝,不改变参数内容 11 | int[] arr = Arrays.copyOf(sourceArray, sourceArray.length); 12 | 13 | int gap = 1; 14 | while (gap < arr.length) { 15 | gap = gap * 3 + 1; 16 | } 17 | 18 | while (gap > 0) { 19 | for (int i = gap; i < arr.length; i++) { 20 | int tmp = arr[i]; 21 | int j = i - gap; 22 | while (j >= 0 && arr[j] > tmp) { 23 | arr[j + gap] = arr[j]; 24 | j -= gap; 25 | } 26 | arr[j + gap] = tmp; 27 | } 28 | gap = (int) Math.floor(gap / 3); 29 | } 30 | 31 | return arr; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/java/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.corning 8 | sort 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | CorningSun 15 | corningsun@163.com 16 | http://www.corningsun.com 17 | 18 | 19 | 20 | 21 | 22 | UTF-8 23 | LATEST 24 | 25 | 26 | 27 | 28 | junit 29 | junit 30 | ${dependency.version} 31 | test 32 | 33 | 34 | 35 | 36 | 37 | 38 | org.apache.maven.plugins 39 | maven-compiler-plugin 40 | 3.7.0 41 | 42 | 1.8 43 | 1.8 44 | 45 | 46 | 47 | org.apache.maven.plugins 48 | maven-surefire-plugin 49 | 2.20.1 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/java/target/maven-archiver/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven 2 | #Fri Jan 05 09:51:14 CST 2018 3 | version=1.0-SNAPSHOT 4 | groupId=com.corning 5 | artifactId=sort 6 | -------------------------------------------------------------------------------- /src/java/target/sort-1.0-SNAPSHOT.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hustcc/JS-Sorting-Algorithm/f56cfad812d52fc56b65ab0f3bce80ceb4054c88/src/java/target/sort-1.0-SNAPSHOT.jar -------------------------------------------------------------------------------- /src/java/test/ArraySortTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.After; 2 | import org.junit.Before; 3 | import org.junit.Test; 4 | 5 | import java.util.Arrays; 6 | import java.util.Random; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | /** 11 | * Created by corning on 2017/12/19. 12 | */ 13 | public class ArraySortTest { 14 | 15 | private int[] array; 16 | private int[] sortedArray; 17 | 18 | // 计数排序等不支持负数排序 19 | private int[] positiveArray; 20 | private int[] positiveArraySorted; 21 | 22 | @Before 23 | public void setUp() throws Exception { 24 | // 生成随机数组 25 | array = randomArray(-1000, 1000, 100); 26 | // 使用 Arrays.sort() 排序作为对比 27 | sortedArray = Arrays.copyOf(array, array.length); 28 | Arrays.sort(sortedArray); 29 | 30 | positiveArray = randomArray(0, 1000, 100); 31 | positiveArraySorted = Arrays.copyOf(positiveArray, positiveArray.length); 32 | Arrays.sort(positiveArraySorted); 33 | } 34 | 35 | /** 36 | * 随机指定范围内N个不重复的数 37 | * 在初始化的无重复待选数组中随机产生一个数放入结果中, 38 | * 将待选数组被随机到的数,用待选数组(len-1)下标对应的数替换 39 | * 然后从len-2里随机产生下一个随机数,如此类推 40 | * 41 | * @param max 指定范围最大值 42 | * @param min 指定范围最小值 43 | * @param n 随机数个数 44 | * @return int[] 随机数结果集 45 | */ 46 | public int[] randomArray(int min, int max, int n) { 47 | int len = max - min + 1; 48 | 49 | if (max < min || n > len) { 50 | return null; 51 | } 52 | 53 | //初始化给定范围的待选数组 54 | int[] source = new int[len]; 55 | for (int i = min; i < min + len; i++) { 56 | source[i - min] = i; 57 | } 58 | 59 | int[] result = new int[n]; 60 | Random rd = new Random(); 61 | int index = 0; 62 | for (int i = 0; i < result.length; i++) { 63 | //待选数组0到(len-2)随机一个下标 64 | index = Math.abs(rd.nextInt() % len--); 65 | //将随机到的数放入结果集 66 | result[i] = source[index]; 67 | //将待选数组中被随机到的数,用待选数组(len-1)下标对应的数替换 68 | source[index] = source[len]; 69 | } 70 | return result; 71 | } 72 | 73 | @After 74 | public void tearDown() throws Exception { 75 | array = null; 76 | sortedArray = null; 77 | } 78 | 79 | @Test 80 | public void bubbleSort() throws Exception { 81 | assertArrayEquals(sortedArray, new BubbleSort().sort(array)); 82 | } 83 | 84 | @Test 85 | public void choiceSort() throws Exception { 86 | assertArrayEquals(sortedArray, new SelectionSort().sort(array)); 87 | } 88 | 89 | @Test 90 | public void insertSort() throws Exception { 91 | assertArrayEquals(sortedArray, new InsertSort().sort(array)); 92 | } 93 | 94 | @Test 95 | public void shellSort() throws Exception { 96 | assertArrayEquals(sortedArray, new ShellSort().sort(array)); 97 | } 98 | 99 | @Test 100 | public void mergeSort() throws Exception { 101 | assertArrayEquals(sortedArray, new MergeSort().sort(array)); 102 | } 103 | 104 | @Test 105 | public void mergeSort_merge() throws Exception { 106 | assertArrayEquals(new int[]{1, 2}, new MergeSort().merge(new int[]{1, 2}, new int[]{})); 107 | assertArrayEquals(new int[]{1, 2}, new MergeSort().merge(new int[]{1}, new int[]{2})); 108 | assertArrayEquals(new int[]{1, 2, 3}, new MergeSort().merge(new int[]{1, 3}, new int[]{2})); 109 | } 110 | 111 | @Test 112 | public void quickSort() throws Exception { 113 | assertArrayEquals(sortedArray, new QuickSort().sort(array)); 114 | } 115 | 116 | @Test 117 | public void heapSort() throws Exception { 118 | assertArrayEquals(sortedArray, new HeapSort().sort(array)); 119 | } 120 | 121 | @Test 122 | public void countingSort() throws Exception { 123 | assertArrayEquals(positiveArraySorted, new CountingSort().sort(positiveArray)); 124 | } 125 | 126 | @Test 127 | public void bucketSort() throws Exception { 128 | assertArrayEquals(sortedArray, new BucketSort().sort(array)); 129 | } 130 | 131 | @Test 132 | public void radixSort() throws Exception { 133 | assertArrayEquals(sortedArray, new RadixSort().sort(array)); 134 | } 135 | 136 | @Test 137 | public void radixSort_getNumLenght() throws Exception { 138 | assertEquals(3, new RadixSort().getNumLenght(-100)); 139 | assertEquals(1, new RadixSort().getNumLenght(1)); 140 | } 141 | 142 | } -------------------------------------------------------------------------------- /src/phpSortTest.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * 主要参考了 JS 的写法及网上的一些写法。 7 | * 8 | * Require: php -v >= 5.4 9 | * Test: php phpSortTest.php 10 | */ 11 | 12 | function sortTest($func, $total = 5000) 13 | { 14 | global $arr; 15 | if (empty($arr)) { 16 | $arr = range(1, $total); 17 | echo "Verify sort md5: ", substr(md5(json_encode($arr)), 0, 8), "\r\n"; 18 | shuffle($arr); 19 | } 20 | list($m1, $n1) = explode(' ', microtime()); 21 | $res = $func($arr); 22 | list($m2, $n2) = explode(' ', microtime()); 23 | $time = round(($m2 - $m1) + ($n2 - $n1), 6); 24 | echo " $func {$time}s " . substr(md5(json_encode($res)), 0, 8) . "\r\n"; 25 | } 26 | 27 | function bubbleSort($arr) 28 | { 29 | $len = count($arr); 30 | for ($i = 0; $i < $len; $i++) { 31 | for ($j = 0; $j < $len - 1 - $i; $j++) { 32 | if ($arr[$j] > $arr[$j+1]) { 33 | $tmp = $arr[$j]; 34 | $arr[$j] = $arr[$j+1]; 35 | $arr[$j+1] = $tmp; 36 | } 37 | } 38 | } 39 | return $arr; 40 | } 41 | 42 | function selectionSort($arr) 43 | { 44 | $len = count($arr); 45 | for ($i = 0; $i < $len - 1; $i++) { 46 | $minIndex = $i; 47 | for ($j = $i + 1; $j < $len; $j++) { 48 | if ($arr[$j] < $arr[$minIndex]) { 49 | $minIndex = $j; 50 | } 51 | } 52 | $temp = $arr[$i]; 53 | $arr[$i] = $arr[$minIndex]; 54 | $arr[$minIndex] = $temp; 55 | } 56 | return $arr; 57 | } 58 | 59 | function insertionSort($arr) 60 | { 61 | $len = count($arr); 62 | for ($i = 1; $i < $len; $i++) { 63 | $preIndex = $i - 1; 64 | $current = $arr[$i]; 65 | while($preIndex >= 0 && $arr[$preIndex] > $current) { 66 | $arr[$preIndex+1] = $arr[$preIndex]; 67 | $preIndex--; 68 | } 69 | $arr[$preIndex+1] = $current; 70 | } 71 | return $arr; 72 | } 73 | 74 | function shellSort($arr) 75 | { 76 | $len = count($arr); 77 | $temp = 0; 78 | $gap = 1; 79 | while($gap < $len / 3) { 80 | $gap = $gap * 3 + 1; 81 | } 82 | for ($gap; $gap > 0; $gap = floor($gap / 3)) { 83 | for ($i = $gap; $i < $len; $i++) { 84 | $temp = $arr[$i]; 85 | for ($j = $i - $gap; $j >= 0 && $arr[$j] > $temp; $j -= $gap) { 86 | $arr[$j+$gap] = $arr[$j]; 87 | } 88 | $arr[$j+$gap] = $temp; 89 | } 90 | } 91 | return $arr; 92 | } 93 | 94 | function mergeSort($arr) 95 | { 96 | $len = count($arr); 97 | if ($len < 2) { 98 | return $arr; 99 | } 100 | $middle = floor($len / 2); 101 | $left = array_slice($arr, 0, $middle); 102 | $right = array_slice($arr, $middle); 103 | return merge(mergeSort($left), mergeSort($right)); 104 | } 105 | 106 | function merge($left, $right) 107 | { 108 | $result = []; 109 | 110 | while (count($left) > 0 && count($right) > 0) { 111 | if ($left[0] <= $right[0]) { 112 | $result[] = array_shift($left); 113 | } else { 114 | $result[] = array_shift($right); 115 | } 116 | } 117 | 118 | while (count($left)) 119 | $result[] = array_shift($left); 120 | 121 | while (count($right)) 122 | $result[] = array_shift($right); 123 | 124 | return $result; 125 | } 126 | 127 | function quickSort($arr) 128 | { 129 | if (count($arr) <= 1) 130 | return $arr; 131 | $middle = $arr[0]; 132 | $leftArray = array(); 133 | $rightArray = array(); 134 | 135 | for ($i = 1; $i < count($arr); $i++) { 136 | if ($arr[$i] > $middle) 137 | $rightArray[] = $arr[$i]; 138 | else 139 | $leftArray[] = $arr[$i]; 140 | } 141 | $leftArray = quickSort($leftArray); 142 | $leftArray[] = $middle; 143 | 144 | $rightArray = quickSort($rightArray); 145 | return array_merge($leftArray, $rightArray); 146 | } 147 | 148 | 149 | function buildMaxHeap(&$arr) 150 | { 151 | global $len; 152 | for ($i = floor($len/2); $i >= 0; $i--) { 153 | heapify($arr, $i); 154 | } 155 | } 156 | 157 | function heapify(&$arr, $i) 158 | { 159 | global $len; 160 | $left = 2 * $i + 1; 161 | $right = 2 * $i + 2; 162 | $largest = $i; 163 | 164 | if ($left < $len && $arr[$left] > $arr[$largest]) { 165 | $largest = $left; 166 | } 167 | 168 | if ($right < $len && $arr[$right] > $arr[$largest]) { 169 | $largest = $right; 170 | } 171 | 172 | if ($largest != $i) { 173 | swap($arr, $i, $largest); 174 | heapify($arr, $largest); 175 | } 176 | } 177 | 178 | function swap(&$arr, $i, $j) 179 | { 180 | $temp = $arr[$i]; 181 | $arr[$i] = $arr[$j]; 182 | $arr[$j] = $temp; 183 | } 184 | 185 | function heapSort($arr) { 186 | global $len; 187 | $len = count($arr); 188 | buildMaxHeap($arr); 189 | for ($i = count($arr) - 1; $i > 0; $i--) { 190 | swap($arr, 0, $i); 191 | $len--; 192 | heapify($arr, 0); 193 | } 194 | return $arr; 195 | } 196 | 197 | function countingSort($arr, $maxValue = null) 198 | { 199 | if ($maxValue === null) { 200 | $maxValue = max($arr); 201 | } 202 | for ($m = 0; $m < $maxValue + 1; $m++) { 203 | $bucket[] = null; 204 | } 205 | 206 | $arrLen = count($arr); 207 | for ($i = 0; $i < $arrLen; $i++) { 208 | if (!array_key_exists($arr[$i], $bucket)) { 209 | $bucket[$arr[$i]] = 0; 210 | } 211 | $bucket[$arr[$i]]++; 212 | } 213 | 214 | $sortedIndex = 0; 215 | foreach ($bucket as $key => $len) { 216 | if ($len !== null) $arr[$sortedIndex++] = $key; 217 | } 218 | 219 | return $arr; 220 | } 221 | 222 | function bucketSort($arr, $bucketSize = 5) 223 | { 224 | if (count($arr) === 0) { 225 | return $arr; 226 | } 227 | 228 | $minValue = $arr[0]; 229 | $maxValue = $arr[0]; 230 | for ($i = 1; $i < count($arr); $i++) { 231 | if ($arr[$i] < $minValue) { 232 | $minValue = $arr[$i]; 233 | } else if ($arr[$i] > $maxValue) { 234 | $maxValue = $arr[$i]; 235 | } 236 | } 237 | 238 | $bucketCount = floor(($maxValue - $minValue) / $bucketSize) + 1; 239 | $buckets = array(); 240 | for ($i = 0; $i < count($buckets); $i++) { 241 | $buckets[$i] = []; 242 | } 243 | 244 | for ($i = 0; $i < count($arr); $i++) { 245 | $buckets[floor(($arr[$i] - $minValue) / $bucketSize)][] = $arr[$i]; 246 | } 247 | 248 | $arr = array(); 249 | for ($i = 0; $i < count($buckets); $i++) { 250 | $bucketTmp = $buckets[$i]; 251 | sort($bucketTmp); 252 | for ($j = 0; $j < count($bucketTmp); $j++) { 253 | $arr[] = $bucketTmp[$j]; 254 | } 255 | } 256 | 257 | return $arr; 258 | } 259 | 260 | function radixSort($arr, $maxDigit = null) 261 | { 262 | if ($maxDigit === null) { 263 | $maxDigit = max($arr); 264 | } 265 | $counter = []; 266 | for ($i = 0; $i < $maxDigit; $i++) { 267 | for ($j = 0; $j < count($arr); $j++) { 268 | preg_match_all('/\d/', (string) $arr[$j], $matches); 269 | $numArr = $matches[0]; 270 | $lenTmp = count($numArr); 271 | $bucket = array_key_exists($lenTmp - $i - 1, $numArr) 272 | ? intval($numArr[$lenTmp - $i - 1]) 273 | : 0; 274 | if (!array_key_exists($bucket, $counter)) { 275 | $counter[$bucket] = []; 276 | } 277 | $counter[$bucket][] = $arr[$j]; 278 | } 279 | $pos = 0; 280 | for ($j = 0; $j < count($counter); $j++) { 281 | $value = null; 282 | if ($counter[$j] !== null) { 283 | while (($value = array_shift($counter[$j])) !== null) { 284 | $arr[$pos++] = $value; 285 | } 286 | } 287 | } 288 | } 289 | 290 | return $arr; 291 | } 292 | 293 | $total = 2000; 294 | 295 | sortTest('bubbleSort', $total); 296 | sortTest('selectionSort', $total); 297 | sortTest('insertionSort', $total); 298 | sortTest('shellSort', $total); 299 | sortTest('mergeSort', $total); 300 | sortTest('quickSort', $total); 301 | sortTest('heapSort', $total); 302 | sortTest('countingSort', $total); 303 | sortTest('bucketSort', $total); 304 | sortTest('radixSort', $total); 305 | -------------------------------------------------------------------------------- /src/pythonSortTest.py: -------------------------------------------------------------------------------- 1 | ''' 2 | # Create by LokiSharp(loki.sharp#gmail) at 2017-1-22 3 | ''' 4 | 5 | TOTAL = 5000 6 | 7 | 8 | def sortTest(func, total=1000): 9 | import random, copy, operator, math, time 10 | arrList = [i for i in range(-math.floor(total / 2), math.ceil(total / 2))] 11 | arrListR = copy.deepcopy(arrList) 12 | while operator.eq(arrList, arrListR): 13 | random.shuffle(arrListR) 14 | # print("--- [Origin List]", arrList, "Use", func.__name__,"with Total:", len(arrList)) 15 | # print("--> [Random List]", arrListR, "Use", func.__name__,"with Total:", len(arrList)) 16 | start = time.clock() 17 | arrListR = func(arrListR) 18 | end = time.clock() 19 | runtime = end - start 20 | # print("--> [Sorted List]", arrListR, "Use", func.__name__,"with Total:", len(arrList)) 21 | if operator.eq(arrList, arrListR): 22 | print("[Success]", func.__name__, "with Total:", len(arrList), "in %.5fs" % runtime) 23 | return True 24 | else: 25 | print("[Fail]", func.__name__, "with Total:", len(arrList), "in %.5fs" % runtime) 26 | return False 27 | 28 | 29 | def bubbleSort(arr): 30 | for i in range(1, len(arr)): 31 | for j in range(0, len(arr) - i): 32 | if arr[j] > arr[j + 1]: 33 | arr[j], arr[j + 1] = arr[j + 1], arr[j] 34 | return arr 35 | 36 | 37 | def selectionSort(arr): 38 | for i in range(len(arr) - 1): 39 | # 记录最小数的索引 40 | minIndex = i 41 | for j in range(i + 1, len(arr)): 42 | if arr[j] < arr[minIndex]: 43 | minIndex = j 44 | # i 不是最小数时,将 i 和最小数进行交换 45 | if i != minIndex: 46 | arr[i], arr[minIndex] = arr[minIndex], arr[i] 47 | return arr 48 | 49 | 50 | def insertionSort(arr): 51 | for i in range(len(arr)): 52 | preIndex = i - 1 53 | current = arr[i] 54 | while preIndex >= 0 and arr[preIndex] > current: 55 | arr[preIndex + 1] = arr[preIndex] 56 | preIndex -= 1 57 | arr[preIndex + 1] = current 58 | return arr 59 | 60 | 61 | def shellSort(arr): 62 | import math 63 | gap = 1 64 | while (gap < len(arr) / 3): 65 | gap = gap * 3 + 1 66 | while gap > 0: 67 | for i in range(gap, len(arr)): 68 | temp = arr[i] 69 | j = i - gap 70 | while j >= 0 and arr[j] > temp: 71 | arr[j + gap] = arr[j] 72 | j -= gap 73 | arr[j + gap] = temp 74 | gap = math.floor(gap / 3) 75 | return arr 76 | 77 | 78 | def mergeSort(arr): 79 | import math 80 | if (len(arr) < 2): 81 | return arr 82 | middle = math.floor(len(arr) / 2) 83 | left, right = arr[0:middle], arr[middle:] 84 | return merge(mergeSort(left), mergeSort(right)) 85 | 86 | 87 | def merge(left, right): 88 | result = [] 89 | while left and right: 90 | if left[0] <= right[0]: 91 | result.append(left.pop(0)); 92 | else: 93 | result.append(right.pop(0)); 94 | while left: 95 | result.append(left.pop(0)); 96 | while right: 97 | result.append(right.pop(0)); 98 | return result 99 | 100 | 101 | def quickSort(arr, left=None, right=None): 102 | left = 0 if not isinstance(left, (int, float)) else left 103 | right = len(arr) - 1 if not isinstance(right, (int, float)) else right 104 | if left < right: 105 | partitionIndex = partition(arr, left, right) 106 | quickSort(arr, left, partitionIndex - 1) 107 | quickSort(arr, partitionIndex + 1, right) 108 | return arr 109 | 110 | 111 | def partition(arr, left, right): 112 | pivot = left 113 | index = pivot + 1 114 | i = index 115 | while i <= right: 116 | if arr[i] < arr[pivot]: 117 | swap(arr, i, index) 118 | index += 1 119 | i += 1 120 | swap(arr, pivot, index - 1) 121 | return index - 1 122 | 123 | 124 | def swap(arr, i, j): 125 | arr[i], arr[j] = arr[j], arr[i] 126 | 127 | 128 | def buildMaxHeap(arr): 129 | import math 130 | for i in range(math.floor(len(arr) / 2), -1, -1): 131 | heapify(arr, i) 132 | 133 | 134 | def heapify(arr, i): 135 | left = 2 * i + 1 136 | right = 2 * i + 2 137 | largest = i 138 | if left < arrLen and arr[left] > arr[largest]: 139 | largest = left 140 | if right < arrLen and arr[right] > arr[largest]: 141 | largest = right 142 | 143 | if largest != i: 144 | swap(arr, i, largest) 145 | heapify(arr, largest) 146 | 147 | 148 | def swap(arr, i, j): 149 | arr[i], arr[j] = arr[j], arr[i] 150 | 151 | 152 | def heapSort(arr): 153 | global arrLen 154 | arrLen = len(arr) 155 | buildMaxHeap(arr) 156 | for i in range(len(arr) - 1, 0, -1): 157 | swap(arr, 0, i) 158 | arrLen -= 1 159 | heapify(arr, 0) 160 | return arr 161 | 162 | 163 | def countingSort(arr, maxValue=None): 164 | bucketLen = maxValue + 1 165 | bucket = [0] * bucketLen 166 | sortedIndex = 0 167 | arrLen = len(arr) 168 | for i in range(arrLen): 169 | if not bucket[arr[i]]: 170 | bucket[arr[i]] = 0 171 | bucket[arr[i]] += 1 172 | for j in range(bucketLen): 173 | while bucket[j] > 0: 174 | arr[sortedIndex] = j 175 | sortedIndex += 1 176 | bucket[j] -= 1 177 | return arr 178 | 179 | def radix_count(exp1): 180 | global list 181 | n = len(list) 182 | output = [0] * (n) 183 | count = [0] * (10) 184 | for i in range(0, n): 185 | index = (list[i] / exp1) 186 | count[(index) % 10] += 1 187 | for i in range(1,10): 188 | count[i] += count[i - 1] 189 | i = n - 1 190 | while i >= 0: 191 | index = (list[i]/exp1) 192 | output[count[(index) % 10] - 1] = list[i] 193 | count[(index) % 10] -= 1 194 | i -= 1 195 | i = 0 196 | for i in range(0,len(list)): 197 | list[i] = output[i] 198 | 199 | def radixSort(): 200 | global list 201 | max1 = max(list) 202 | exp = 1 203 | while max1 / exp > 0: 204 | radix_count(exp) 205 | exp *= 10 206 | 207 | 208 | if __name__ == '__main__': 209 | sortTest(bubbleSort, TOTAL) 210 | sortTest(selectionSort, TOTAL) 211 | sortTest(insertionSort, TOTAL) 212 | sortTest(shellSort, TOTAL) 213 | sortTest(mergeSort, TOTAL) 214 | sortTest(quickSort, TOTAL) 215 | sortTest(heapSort, TOTAL) 216 | sortTest(radixSort, TOTAL) 217 | --------------------------------------------------------------------------------