内部排序: 就是使用内存空间来排序

外部排序: 就是数据量很大,需要借助外部存储(文件)来排序.

直接上代码:

package com.lvcai;

  1. public class Sort {
  2. public static void main(String[] args) {
  3. //排序 分为: 内部排序(使用内存来排序) , 外部排序(需要借助外部存储)
  4. // 内部排序:
  5. // int[] array = {100, 6, 9, 2, 1, 0, 54,23,5};
  6. // int[] arr = new int[10000000];
  7. // for (int i = 0; i < 10000000; i++) {
  8. // arr[i] = (int) (Math.random() * 80000000); // 生成一个[0, 8000000) 数
  9. // }
  10. // int[] temp = new int[arr.length];
  11. // long before = System.currentTimeMillis();
  12. // //selectSort(arr); // 选择排序:8万个随机数,选择排序耗时 13755 毫秒
  13. // //bubbleSort(arr); // 冒泡排序:8万个随机数,选择排序耗时 13804 毫秒
  14. // //insertSort(arr); // 插入排序:8万个随机数,选择排序耗时 2381 毫秒
  15. // //shellSort(arr); // 希尔排序:8万个随机数,选择排序耗时 8606 毫秒
  16. // quickSort(arr,0,arr.length-1); // 快速排序:8万个随机数,选择排序耗时 16 毫秒
  17. // //MergeSort(arr,0,arr.length-1,temp); // 归并排序:8万个随机数,选择排序耗时 23 毫秒
  18. radixSort(arr); // 基数排序: 8万个随机数,选择排序耗时 16 毫秒
  19. // long after = System.currentTimeMillis();
  20. // System.out.println(after - before);
  21. //int[] array = {100, 6, 9, 2, 1, 0, 54,23,5};
  22. //int[] array = {8,1,2,4,5,6,7};
  23. int[] array = {6,1,2,7,9,3,4,5,10,8};
  24. int[] temp = new int[array.length];
  25. print(array);
  26. MergeSort(array,0,array.length-1,temp);
  27. print(array);
  28. }
  29. //1: 选择排序: 将第一个数,和数组中其余数比较, 比较结束后, 数组第一个数就是最小的那个数, 将第二个数 和数组中其余数比较, 比较结束后也是将最小的数组放在最前面
  30. // 测试结果: 8万个随机数,选择排序耗时8049毫秒 10万个随机数,选择排序耗时9636毫秒,
  31. public static void selectSort(int[] array){
  32. for (int i = 0; i < array.length - 1; i++) {
  33. for (int j = i+1; j < array.length; j++) {
  34. if(array[i] > array[j]){
  35. int temp = array[j];
  36. array[j] = array[i];
  37. array[i] = temp;
  38. }
  39. }
  40. }
  41. }
  42. //2: 冒泡排序: 将待排序的序列 从前向后,依次比较相邻的二个元素, 如果逆序就交换, 这样是较大的值逐渐从前向后移动, 时间复杂度 O(n^2)
  43. //测试结果: 8万个随机数,选择排序耗时9211毫秒 10万个随机数,选择排序耗时11603毫秒,
  44. public static void bubbleSort(int[] array){
  45. int temp= 0;
  46. for (int i = 0; i < array.length -1; i++) {
  47. for(int j = 0; j < array.length -1 -i ; j++){
  48. if(array[j] > array[j+1]){
  49. temp = array[j+1];
  50. array[j+1] = array[j];
  51. array[j] = temp;
  52. }
  53. }
  54. }
  55. }
  56. //2.1: 冒泡排序优化: 如果在某一次循环比较过程中, 没有发生交换,说明此时,已经是有序的,,就提前结束
  57. public static void bubbleSortBetter(int[] array){
  58. int temp= 0;
  59. for (int i = 0; i < array.length -1; i++) {
  60. int exchageCount = 0;//交换次数,
  61. for(int j = 0; j < array.length -1 -i ; j++){
  62. if(array[j] > array[j+1]){
  63. exchageCount++;
  64. temp = array[j+1];
  65. array[j+1] = array[j];
  66. array[j] = temp;
  67. }
  68. }
  69. if(exchageCount == 0){
  70. break;
  71. }
  72. }
  73. }
  74. // 3: 插入排序: 将数组第一个数看做是有序的 ,后面的数都是无序的, 对于无序数据,在已排序的数据中从后向前扫描
  75. // 速度测试结果:
  76. //就像打牌一样, 将第一个元素看做有序的, 其余的牌看成无序的,从无序中最左侧拿出一张牌, 从后向前扫描有序序列,寻找插入位置,找到位置后,将牌插入,,
  77. public static void insertSort(int[] array){
  78. //思路: 1,假设第一个元素是有序的, 从第二个元素a开始比较
  79. // 2, 如果这个元素a ,比前一个元素b小, 就将b后移一位,(会覆盖掉a,所以先将a保存下), 之后继续从后向前扫描,和a比较, 如果比a大,那么就后移,
  80. // 3, 当循环结束的时候, 就说明已经找到插入位置了
  81. /**
  82. * 比如: {3,1,0,6}
  83. * 一: 从1,和 3比较 , 1 < 3, 所以将 3 后移, 变为{3,3,0,6}, 跳出循环,此时将第一个3 替换为1 -->{1,3,0,6}
  84. * 二: 然后 0 和3 比较, 3向后移动->{1,3,3,6}, 0 和1比较, 1向后移动->{1,1,3,6}, 跳出循环,此时将 1替换为0,->{0,1,3,6}
  85. * 三: 然后 6和 3比较, 不变, 和1比较,不变, 和0 比较不变. 所以最终结果为 {0,1,3,6}
  86. *
  87. */
  88. for (int i = 1; i < array.length; i++) {
  89. int insertVal = array[i];//要插入的元素, 先保存下
  90. int insertIndex = i-1;// 要插入元素的前一元素的索引
  91. //insertVal < array[insertIndex] 表示 要插入的元素 如果小于,之前索引对应元素, 就将array[insertIndex] 向后移一位
  92. while(insertIndex >= 0 && insertVal < array[insertIndex]){
  93. array[insertIndex+1] = array[insertIndex];//就将array[insertIndex] 向后移一位,会覆盖掉要插入的元素
  94. insertIndex--;//递减,就是从后向前 扫描已排序的序列
  95. }
  96. //当跳出循环的时候, 说明 比insertVal大的元素, 都依次后移了一位, 而要插入的位置 刚好就是 insertIndex+1 的位置
  97. array[insertIndex +1] = insertVal;
  98. }
  99. }
  100. //4: 希尔排序: 又叫增量递减排序,是插入排序的优化, {3,1,6,0},由于最小数0 在最后,插入排序时,0 需要从最后移动到最前,这样效率反而低.
  101. public static void shellSort(int[] array){
  102. /**
  103. * 思路:{8,1,2,4,5,6,7}, 长度 7
  104. * 1: 步长增量 7/2 = 3, 从8开始,步长为3分组. 8,4,7 1,5 2,6 对这进行插入排序,结果为 {4,1,2,7,5,6,8}
  105. * 2: 步长增量 3/2 = 1, 从4开始,步长为1分组, 就是对{4,1,2,7,5,6,8} 进行插入排序 结果为{1,2,4,5,6,7,8}
  106. *
  107. * {8, 9, 1, 7, 2, 3, 5, 4, 6, 0} 长度为10
  108. * 1: 步长增量 10/2 = 5, 从8开始,步长为5分组, 8,3 9,5 1,4 7,6 2,0 对这五组分别进行插入排序,结果为:{3,5,1,6,0,8,9,4,7,2}
  109. * 2: 步长增量 5/2 = 2, 从3开始,步长为2分组, 3,1,0,9,7 5,6,8,4,2 对这二组 分别进行插入排序, 结果为{0,2,1,4,3,5,7,6,9,8}
  110. * 3: 步长增量 2/2 = 1, 从0开始,步长为1分组, 0,2,1,4,3,5,7,6,9,8 就是对他进行插入排序, 结果为{0,1,2,3,4,5,6,7,8,9}
  111. *
  112. * 可以看出 0 最小, 在第一次分组结束后, 0 已经到了中间,减少了移动次数
  113. */
  114. int temp;
  115. for(int grp =array.length/2 ; grp>0 ; grp /=2){//步长为长度/2
  116. for(int i = grp ; i < array.length ; i++){
  117. for(int j = i - grp; j >= 0 ; j -= grp){
  118. if(array[j] > array[j+grp]){ //组间元素对比,如果逆序, 就交换
  119. temp = array[j+grp];
  120. array[j+grp] = array[j];
  121. array[j] = temp;
  122. }
  123. }
  124. }
  125. }
  126. }
  127. //5: 快速排序: 是冒泡排序的改进,是一种分区交换排序方法, 思想如下: 一趟快速排序,采用从两头向中间扫描的方法,公式交换与基准记录
  128. // 快速排序之所以快,是因为冒泡排序时相邻二个元素,依次比较,,,而快速排序,是根据基准值,将序列变成 左侧比他小,右侧比他大,这样的比较是跳跃式的,总的比较次数是比冒泡要少
  129. /**
  130. * @param array 待排序列
  131. * @param leftIndex 待排序列起始位置
  132. * @param reightIndex 待排序列结束位置
  133. */
  134. public static void quickSort(int[] array, int leftIndex, int reightIndex){
  135. /**
  136. * 思路: {6,1,2,7,9,3,4,5,10,8}
  137. * 1: 将第一个数 6 作为基准值,坑位(下角标0), 向从后向前扫描,找到比6小的数 5, 5填到该坑位 {5,1,2,7,9,3,4,5,10,8},同时下角标 7,成为新的坑位
  138. * 2: 从前向后扫描,找到一个比6 大的数:7, 将7 填到上一个坑位 -> {5,1,2,7,9,3,4,7,10,8},下角标3成为新坑位
  139. * 3: 从7开始从后向前扫描, 找到一个比6 小的数:4, 将4填到上一个坑位,-->{5,1,2,4,9,3,4,7,10,8},下角标6成为新坑位
  140. * 4: 从4开始从前向后扫描, 找到一个比6 大的数:9, 将9填到上一个坑位,-->{5,1,2,4,9,3,9,7,10,8},下角标4成为新坑位
  141. * 5: 从9开始从后向前扫描,找到一个比6 小的数:3, 将3填到上一个坑位, -->{5,1,2,4,3,3,9,7,10,8},下角标5成为新坑位
  142. * 6: 此时循环结束, 然后将 基准值:6,填到上一个坑位 -->{5,1,2,4,3,6,9,7,10,8}
  143. * 7:此时 以6 区分 {5,1,2,4,3},{9,7,10,8} 分别进行 1-6步骤
  144. */
  145. if(leftIndex >= reightIndex){
  146. return;
  147. }
  148. int left = leftIndex;// 记录开始索引, 因为排序过程中 leftIndex 会移动, 所以要用第三方变量left来代替参与排序
  149. int reight = reightIndex;//记录尾索引,
  150. int key = array[left]; //这个是基准值,通常将第一个作为基准值, 同时left成为新坑位(下标为0)
  151. while(left < reight){
  152. //先从后向前扫描, 找到一个比基准值小的值, 将这个值赋填到上个left坑位, 同时reight成为新坑位
  153. while(key <= array[reight] && left < reight){
  154. reight--;
  155. }
  156. array[left] = array[reight];
  157. //从前向后扫描, 找到一个比基准值 大的值, 将这个值赋值给,上一个reight位置(填到坑中),同时这个left成为新坑位
  158. while( key >= array[left] && left < reight){
  159. left++;
  160. }
  161. array[reight] = array[left];
  162. }
  163. //当这个大的循环结束的时候, left== reight , 并且这个位置就是新的坑位,需要将基准值key 填到这里
  164. array[left] = key;
  165. //此时该序列变成一个: left 左侧都是比array[left]小, 右侧都是比array[reight]大 的序列
  166. // 左递归, 开始下标 leftIndex, 结束下标 left-1
  167. quickSort(array,leftIndex,left-1);
  168. // 右递归, 开始下标 left+1, 结束下标 reightIndex
  169. quickSort(array,reight+1,reightIndex);
  170. }
  171. //6: 归并排序, 归并排序需要额外的空间,temp 大小和array一样,
  172. /**
  173. *
  174. * @param array 待排序 序列
  175. * @param begin 开始索引
  176. * @param end 尾部索引
  177. * @param temp 额外空间, 大小和待排序一样
  178. */
  179. public static void MergeSort(int[] array,int begin,int end,int[] temp){
  180. if(begin < end){
  181. int mid = (begin + end)/2;
  182. //递归 将序列不停的二分
  183. MergeSort(array,begin,mid,temp);
  184. MergeSort(array,mid+1,end,temp);
  185. //合并,
  186. merge(array,begin,mid,end,temp);
  187. }
  188. }
  189. public static void merge(int[] array,int begin,int mid,int end,int[] temp){
  190. /**
  191. * 思路: {6,1,2,7,9,3,4,5,10,8}
  192. * 1: 先分成 左右两部分 {6,1,2,7,9} {3,4,5,10,8},继续分
  193. * 2: {6,1,2} {7,9} {3,4,5} {10,8},继续分
  194. * 3: {6,1} {2} {7,9} {3,4} {5} {10,8}
  195. *
  196. * 左序列 排序合并过程: {6,1} {2} {7,9}
  197. * 4.1:{6,1}排序过程: 将小的数加入到temp中 {1}, 然后发现左序列还有剩余数6, 将6 加入到temp中{1,6}, 然后将temp的数,复制到array中 {1,6,2,7,9,3,4,5,10,8}
  198. * 4.2: 由于接下来为{2}排序, 将{1,6} 和{2} 排序: 1比2小, 1添加到temp中{1}, 2比6小,2添加到temp中{1,2}, 最后左序列还有剩余6, 6添加到temp中{1,2,6}, 将temp复制到array中{1,2,6,7,9,3,4,5,10,8}
  199. * 4.3: 接下来为{1,2,6} {7,9} 排序合并.....{1,2,6,7,9}
  200. *
  201. * 4.4 右序列 排序合并过程 {3,4} {5} {10,8} ---> {3,4} {5} {8,10}. 最终变成{3,4,5,8,10}
  202. *
  203. * 5 将{1,2,6,7,9} {3,4,5,8,10} 排序合并,然后复制到array中,,最终结果{1,2,3,4,5,6,7,8,9,10}
  204. */
  205. int i = begin;//初始化,左边序列的初始索引
  206. int j = mid + 1; //初始化, 右边序列的初始索引
  207. int t = 0;//temp序列的初始索引
  208. //先把左序列 右序列的数据, 进行排序填充到temp中,直到左右两边有一边处理完毕
  209. while(i <= mid && j <= end){
  210. if(array[i] <= array[j]){
  211. temp[t] = array[i];
  212. t++;
  213. i++;
  214. }else{
  215. temp[t] = array[j];
  216. t++;
  217. j++;
  218. }
  219. }
  220. //如果左序列有剩余,就加入到temp
  221. while(i <= mid){
  222. temp[t] = array[i];
  223. t++;
  224. i++;
  225. }
  226. //如果右序列有剩余,就加入到temp
  227. while(j <= end){
  228. temp[t] = array[j];
  229. t++;
  230. j++;
  231. }
  232. //将temp已排好序的,复制到array中
  233. t = 0;
  234. //int tempLeft = begin;
  235. while(begin <= end){
  236. array[begin] = temp[t];
  237. t++;
  238. begin++;
  239. }
  240. }
  241. public static void print(int[] array){
  242. for (int i = 0; i < array.length; i++) {
  243. System.out.print(array[i]+" ");
  244. }
  245. System.out.println();
  246. }
  247. }

7;基数排序: 也叫桶排序,思路分析



代码:

  1. //7: 基数排序, 也叫桶排序, 由于单个数字只有0-9, 需要有10个桶,编号从0-9,
  2. public static void radixSort(int[] array){
  3. /**
  4. * 思路: 基数排序, 也叫桶排序, 思路请看图:
  5. */
  6. //1, 获取数组中的最大数
  7. int max = array[0];
  8. for (int i = 1; i < array.length; i++) {
  9. if(array[i] > max){
  10. max = array[i];
  11. }
  12. }
  13. //桶排序的次数为
  14. int maxLenght = (max+"").length();
  15. //2: 创建一个二维数组,来表示10个桶,为避免下标越界,每个桶的大小都为array.length
  16. int[][] bucket = new int[10][array.length];
  17. //2.1: 需要记录每个桶中的数据个数,便于取数据,这里用一个 一维数组来表示, 比如bucketNumberCount[1] = 2, 表示编号为1 的桶有2个数据
  18. int[] bucketNumberCount = new int[10];
  19. for (int i = 0 , n = 1; i < maxLenght; i++ , n *= 10) {
  20. for (int j = 0; j < array.length; j++) {
  21. //获取对应的位数, 个位,十位,百位,千位. 当n为1时候,是个位数, n为10,是十位数, n为100是百位数
  22. int numberDigit = array[j] / n % 10;
  23. //根据 位数,将数放入对应的桶中,numberDigit就是对应的桶编号,bucketNumberCount这个数组初始为[0,0,0,0,0,0,0,0,0,0], bucketNumberCount[numberDigit] = 0,表示这个桶中元素个数为0,bucketNumberCount[numberDigit] = 1,说明该桶中放了一个元素
  24. bucket[numberDigit][bucketNumberCount[numberDigit]] = array[j]; //这个数放到桶中下标为0 的位置,之后放到为1的位置
  25. bucketNumberCount[numberDigit]++;
  26. }
  27. //循环结束时候,说明都放到对应的桶中了, 接下来根据桶编号0-9, 将数据取出来,放到array中
  28. int index = 0;
  29. for (int k = 0; k < 10; k++) {
  30. if(bucketNumberCount[k] != 0){
  31. //说明 编号为k的桶中有数据,数量为bucketNumberCount[k], 循环取出,存到array中
  32. for (int h = 0; h < bucketNumberCount[k]; h++) {
  33. array[index] = bucket[k][h];
  34. index++;
  35. }
  36. }
  37. //编号为k的桶中元素取出来后,将桶中元素清0;避免影响下次存取
  38. bucketNumberCount[k] = 0;
  39. }
  40. }
  41. }

9, java数据结构和算法: 直接插入排序, 希尔排序, 简单选择排序, 堆排序, 冒泡排序,快速排序, 归并排序, 基数排序的分析和代码实现的更多相关文章

  1. 八大排序算法之三选择排序—简单选择排序(Simple Selection Sort)

    基本思想: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换:然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素 ...

  2. Java数据结构和算法(三)——冒泡、选择、插入排序算法

    上一篇博客我们实现的数组结构是无序的,也就是纯粹按照插入顺序进行排列,那么如何进行元素排序,本篇博客我们介绍几种简单的排序算法. 1.冒泡排序 这个名词的由来很好理解,一般河水中的冒泡,水底刚冒出来的 ...

  3. java数据结构和算法01(数组的简单使用)

    一直都对这一块没有什么想法,加上不怎么理解,只是懂个大概:最近突然感觉对数据结构和算法这块有点儿兴趣,决定还是尽量详细的看看这些结构和算法: 话说什么事数据结构和算法呢?现在我也说不上来,等我学的差不 ...

  4. 选择排序—简单选择排序(Simple Selection Sort)原理以及Java实现

    基本思想: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换:然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素 ...

  5. 常见排序算法总结:插入排序,希尔排序,冒泡排序,快速排序,简单选择排序以及java实现

    今天来总结一下常用的内部排序算法.内部排序算法们需要掌握的知识点大概有:算法的原理,算法的编码实现,算法的时空复杂度的计算和记忆,何时出现最差时间复杂度,以及是否稳定,何时不稳定. 首先来总结下常用内 ...

  6. Java数据结构和算法(九)——高级排序

    春晚好看吗?不存在的!!! 在Java数据结构和算法(三)——冒泡.选择.插入排序算法中我们介绍了三种简单的排序算法,它们的时间复杂度大O表示法都是O(N2),如果数据量少,我们还能忍受,但是数据量大 ...

  7. 数据结构与算法(C/C++版)【排序】

    第八章<排序>  一.直接插入排序  //直接插入排序 //算法思想:每趟将一个待排的关键字按照其值的大小插入到已经排好的部分有序序列的适当位置上,直到所有待排关键字都被插入到有序序列中为 ...

  8. Python实现八大排序(基数排序、归并排序、堆排序、简单选择排序、直接插入排序、希尔排序、快速排序、冒泡排序)

    目录 八大排序 基数排序 归并排序 堆排序 简单选择排序 直接插入排序 希尔排序 快速排序 冒泡排序 时间测试 八大排序 大概了解了一下八大排序,发现排序方法的难易程度相差很多,相应的,他们计算同一列 ...

  9. Java数据结构和算法(五)--希尔排序和快速排序

    在前面复习了三个简单排序Java数据结构和算法(三)--三大排序--冒泡.选择.插入排序,属于算法的基础,但是效率是偏低的,所以现在 学习高级排序 插入排序存在的问题: 插入排序在逻辑把数据分为两部分 ...

随机推荐

  1. POJ1236 强连通 (缩点后度数的应用)

    题意:       一些学校有一个发送消息的体系,现在给你一些可以直接发送消息的一些关系(单向)然后有两个问题 (1) 问你至少向多少个学校发送消息可以让所有的学校都得到消息 (2) 问至少加多少条边 ...

  2. Win64 驱动内核编程-27.强制读写受保护的内存

    强制读写受保护的内存 某些时候我们需要读写别的进程的内存,某些时候别的进程已经对自己的内存读写做了保护,这里说四个思路(两个R3的,两个R0的). 方案1(R3):直接修改别人内存 最基本的也最简单的 ...

  3. Spring Framework自动装配setAutowireMode和Mybatis案例的源码探究

    由前文可得知, Spring Framework的自动装配有两种方式:xml配置和注解配置: 自动装配的类型有: (1)xml配置中的byType根据类型查找(@Autowired注解是默认根据类型查 ...

  4. 【插件篇】前段bootstrap-table-treegrid试手,解决无法显示树形列表或者图标不显示问题。

    说明:具体代码操作我就不贴了.官方有正规的例子!bootstrap-table-examples传送 使用注意事项: 传入的id和pid可以是string类型的(我后台返回的是Long类型转换成str ...

  5. 电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决

    电脑提示无法装入/加载SolidWorks DLL文件:sldshellutils如何解决 参考资料:http://www.xitongcheng.com/jiaocheng/dnrj_article ...

  6. Securecrt 在win7下 字体太少问题

    用WIN7,觉得securecrt里面可用的字体太少了.很多都没有,比如lucida console,经过一番查找,终于找到解决问题的方法了. 原因就是win7里面的很多字体都被设置为隐藏了,所以se ...

  7. Codeforces Round #688 (Div. 2)

    A. Cancel the Trains 题意:给定两个数组,找出这两个数组中有多少重复元素,然后输出 思路:直接找 代码: 1 #include<iostream> 2 #include ...

  8. 最新.NET Core面试题汇总

    这几天给.neter们整理了26道.NET Core面试题,初衷也很简单,就是希望在面试的时候能够帮助到大家,减轻大家的负担和节省时间.对于没有跳槽打算的也可以复习一下相关知识点,就当是查缺补漏! 对 ...

  9. Iterable 和 Iterator

    可以被for循环输出的为iterable (可迭代对象) 可以被next()调用并不断返回下一个数据的对象为iterator迭代器(python一切皆对象) 数据流,无法知晓其终点,只能推过next不 ...

  10. [bug] Flask css 不更新

    参考 https://blog.csdn.net/weixin_30454481/article/details/97108510