[关闭]
@lzb1096101803 2016-03-08T20:58:45.000000Z 字数 7796 阅读 538

排序算法背诵

电话面试


冒泡排序

冒泡排序算法的运作如下:(从小到大)
- 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。结果,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较

  1. package 排序.冒泡排序;
  2. /**
  3. * 冒泡排序
  4. * 交换排序:冒泡排序和快速排序
  5. * 最差O(n^2) 平均:O(n^2) 最好O(n)
  6. * 空间复杂度:辅助存储O(1)
  7. * 稳定
  8. */
  9. public class BubbleSort {
  10. public void bubble(Integer[] data){
  11. for(int i=0;i<data.length;i++){
  12. for(int j=0;j<data.length-1-i;j++){
  13. if(data[j]>data[j+1]){ //如果后一个数小于前一个数交换
  14. int tmp=data[j];
  15. data[j]=data[j+1];
  16. data[j+1]=tmp;
  17. }
  18. }
  19. }
  20. }
  21. public static void main(String[] args) {
  22. Integer[] list={12,21,96,72,38,44,1};
  23. BubbleSort bs=new BubbleSort();
  24. bs.bubble(list);
  25. for(int i=0;i<list.length;i++){
  26. System.out.print(list[i]+" ");
  27. }
  28. System.out.println();
  29. }
  30. }

选择排序

①初始状态:无序区为R[1..n],有序区为空。
②第1趟排序
在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

  1. package 排序.选择排序;
  2. /**
  3. * 选择排序
  4. * 最差O(n^2) 平均:O(n^2) 最好O(n^2)
  5. * 空间复杂度:辅助存储O(1)
  6. * 不稳定
  7. */
  8. public class ChoseSort {
  9. public int[] choseSort(int[] intArr){
  10. for(int i=0;i<intArr.length;i++){
  11. int lowIndex = i;
  12. for(int j=i+1;j<intArr.length;j++){
  13. if(intArr[j]>intArr[lowIndex]){
  14. lowIndex = j;
  15. }
  16. }
  17. //将当前第一个元素与它后面序列中的最小的一个 元素交换,也就是将最小的元素放在最前端
  18. if(i!=lowIndex){
  19. int temp = intArr[i];
  20. intArr[i] = intArr[lowIndex];
  21. intArr[lowIndex] = temp;
  22. }
  23. }
  24. return intArr;
  25. }
  26. public static void main(String[] args) {
  27. ChoseSort choseSort = new ChoseSort();
  28. int[] intArr = {80,2,99,96,47,72,78};
  29. int[] intArrAfterSort = choseSort.choseSort(intArr);
  30. for(int k=0;k<intArrAfterSort.length;k++){
  31. System.out.print(intArrAfterSort[k]+" ");
  32. }
  33. }
  34. }

插入排序

把待排序的纪录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的纪录插入完为止,得到一个新的有序序列。

  1. package 排序.简单插入排序;
  2. /**
  3. * 简单插入排序
  4. * 插入排序:简单插入排序和希尔排序
  5. * 最差O(n^2) 平均:O(n^2) 最好O(n) 和冒泡一样
  6. * 空间复杂度:辅助存储O(1)
  7. * 稳定
  8. */
  9. public class InsertSort {
  10. public static void main(String[] args) {
  11. int[] array = new int[] { 72,60,32,66,81,48,8 };
  12. InsertSort.insertSort(array);
  13. for(int k=0;k<array.length;k++){
  14. System.out.print(array[k]+" ");
  15. }
  16. }
  17. public static int[] insertSort(int[] arr) {
  18. int i, j;
  19. int insertNote;// 要插入的数据
  20. int[] array = arr;
  21. // 从数组的第二个元素开始循环将数组中的元素插入
  22. for (i = 1; i < array.length; i++) {
  23. // 设置数组中的第2个元素为第一次循环要播讲的数据
  24. insertNote = array[i];
  25. j = i - 1;
  26. while (j >= 0 && insertNote > array[j]) {
  27. // 如果要播讲的元素小于第j个元素,就将第j个元素向后移动
  28. array[j + 1] = array[j];
  29. j--;
  30. }
  31. // 直到要插入的元素不小于第j个元素,将insertNote插入到数组中
  32. array[j + 1] = insertNote;
  33. }
  34. // 打印排序后的数组
  35. // System.out.println(Arrays.toString(array));
  36. return array;
  37. }
  38. }

快速排序

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

  1. package 排序.快速排序;
  2. /**
  3. * 快速排序
  4. * 交换排序:冒泡排序和快速排序
  5. * 最差O(n^2) 平均:O(n*log2n) 最好O(n*log2n)
  6. * 空间复杂度:辅助存储O(n*log2n)
  7. * 不稳定
  8. * 算法导论P95
  9. * 分解-解决-合并
  10. */
  11. public class QuickSort {
  12. public static void main(String[] args) {
  13. Integer[] list={3,71,89,8,55,48,42};
  14. QuickSort.quickSort(list,0,list.length-1);
  15. for(int i=0;i<list.length;i++){
  16. System.out.print(list[i]+" ");
  17. }
  18. System.out.println();
  19. }
  20. public static void quickSort(Integer[] list, int low, int high) {
  21. if (low < high) {
  22. int middle = getMiddle(list, low, high); //将list数组进行一分为二 partition
  23. for(int a:list){
  24. System.out.print(a+" ");
  25. }
  26. System.out.println();
  27. quickSort(list, low, middle - 1); //对低字表进行递归排序
  28. quickSort(list, middle + 1, high); //对高字表进行递归排序
  29. }
  30. }
  31. public static int getMiddle(Integer[] list, int low, int high) {
  32. int tmp = list[low]; //数组的第一个作为中轴
  33. while (low < high) {
  34. while (low < high && list[high] <= tmp) {
  35. high--;
  36. }
  37. //比中轴小的记录移到低端
  38. if (low < high)
  39. list[low++] = list[high];
  40. while (low < high && list[low] >= tmp) {
  41. low++;
  42. }
  43. //比中轴大的记录移到高端
  44. if (low < high)
  45. list[high--] = list[low];
  46. }
  47. list[low] = tmp; //中轴记录到尾
  48. return low; //返回中轴的位置
  49. }
  50. }

归并排序

归并过程为:比较a[i]和a[j]的大小,若a[i]≤a[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;否则将第二个有序表中的元素a[j]复制到r[k]中,并令j和k分别加上1,如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元

  1. package 排序.归并排序;
  2. /**
  3. * 归并排序
  4. * 最差O(n*log2n) 平均:O(n*log2n) 最好O(n*log2n)
  5. * 空间复杂度:辅助存储O(1)
  6. * 稳定
  7. */
  8. public class MergeSort {
  9. public static void main(String[] args) {
  10. int[] data = new int[] {59,93,99,0,95,1,46};
  11. print(data);
  12. mergeSort(data);
  13. System.out.println("排序后的数组:");
  14. print(data);
  15. }
  16. public static void mergeSort(int[] data) {
  17. sort(data, 0, data.length - 1);
  18. }
  19. public static void sort(int[] data, int left, int right) {
  20. if (left >= right)
  21. return;
  22. // 找出中间索引
  23. int center = (left + right) / 2;
  24. // 对左边数组进行递归
  25. sort(data, left, center);
  26. // 对右边数组进行递归
  27. sort(data, center + 1, right);
  28. // 合并
  29. merge(data, left, center, right);
  30. print(data);
  31. }
  32. /**
  33. * 将两个数组进行归并,归并前面2个数组已有序,归并后依然有序
  34. *
  35. * @param data
  36. * 数组对象
  37. * @param left
  38. * 左数组的第一个元素的索引
  39. * @param center
  40. * 左数组的最后一个元素的索引,center+1是右数组第一个元素的索引
  41. * @param right
  42. * 右数组最后一个元素的索引
  43. */
  44. public static void merge(int[] data, int left, int center, int right) {
  45. System.out.println();
  46. System.out.println("left:"+left+" center"+center+" right:"+right);
  47. // 临时数组
  48. int[] tmpArr = new int[data.length];
  49. // 右数组第一个元素索引
  50. int mid = center + 1;
  51. // third 记录临时数组的索引
  52. int third = left;
  53. // 缓存左数组第一个元素的索引
  54. int tmp = left;
  55. while (left <= center && mid <= right) {
  56. // 从两个数组中取出最小的放入临时数组
  57. if (data[left] >= data[mid]) {
  58. tmpArr[third++] = data[left++];
  59. } else {
  60. tmpArr[third++] = data[mid++];
  61. }
  62. }
  63. // 剩余部分依次放入临时数组(实际上两个while只会执行其中一个)
  64. while (mid <= right) {
  65. tmpArr[third++] = data[mid++];
  66. }
  67. while (left <= center) {
  68. tmpArr[third++] = data[left++];
  69. }
  70. // 将临时数组中的内容拷贝回原数组中
  71. // (原left-right范围的内容被复制回原数组)
  72. while (tmp <= right) {
  73. data[tmp] = tmpArr[tmp++];
  74. }
  75. }
  76. public static void print(int[] data) {
  77. for (int i = 0; i < data.length; i++) {
  78. System.out.print(data[i] + ",");
  79. }
  80. System.out.println();
  81. }
  82. }

堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

构造大顶堆,堆排序

  1. package 排序.堆排序;
  2. /**
  3. * 堆排序
  4. * http://upload.wikimedia.org/wikipedia/commons/4/4d/Heapsort-example.gif
  5. * 最差O(n*log2n) 平均:O(n*log2n) 最好O(n*log2n)
  6. * 算法导论P84
  7. */
  8. public class HeapSort {
  9. public static void main(String[] args) {
  10. int[] data = new int[]{16,4,10,14,28,9,3,2,8,30};
  11. sort(data);
  12. for(int a:data){
  13. System.out.print(a+" ");
  14. }
  15. }
  16. public static void sort(int[] data) {
  17. // 构建最大堆
  18. buildMaxHeap(data);
  19. // 循环,每次把根节点和最后一个节点调换位置
  20. for (int i = data.length; i > 1; i--) {
  21. int tmp = data[0];
  22. data[0] = data[i - 1];
  23. data[i - 1] = tmp;
  24. // 堆的长度减少1,排除置换到最后位置的根节点
  25. maxHeapify(data, 1, i - 1);
  26. }
  27. }
  28. // 根据输入数组构建一个最大堆 i>heapSize/2都是叶子节点(下标从1开始)
  29. private static void buildMaxHeap(int[] data) {
  30. for (int i = (data.length) / 2; i > 0; i--) {
  31. maxHeapify(data, i, data.length);
  32. }
  33. }
  34. //堆调整,以parentNodeIndex-1为根节点,使其子树生成最大堆
  35. //parentNodeIndex最小只能是1,否则根节点得不到左右节点,因此下面采用parentNodeIndex-1获取值
  36. private static void maxHeapify(int[] data, int parentNodeIndex, int heapSize) {
  37. // 左子节点索引
  38. int leftChildNodeIndex = parentNodeIndex * 2;
  39. // 右子 索引
  40. int rightChildNodeIndexAddOne = parentNodeIndex * 2 + 1;
  41. // 最大节点索引
  42. int largestNodeIndex = parentNodeIndex;
  43. // 如果左子节点大于父节点,则将左子节点作为最大节点
  44. //前面判断用于第一次时为了防止越界,&&具有截断作用
  45. if (leftChildNodeIndex <= heapSize && (data[leftChildNodeIndex - 1] - data[parentNodeIndex - 1]) > 0) {
  46. largestNodeIndex = leftChildNodeIndex;
  47. }
  48. // 如果右子节点比最大节点还大,那么最大节点应该是右子节点
  49. if (rightChildNodeIndexAddOne <= heapSize && (data[rightChildNodeIndexAddOne - 1] - data[largestNodeIndex - 1]) > 0) {
  50. largestNodeIndex = rightChildNodeIndexAddOne;
  51. }
  52. // 最后,如果最大节点和父节点不一致,则交换他们的值
  53. if (largestNodeIndex != parentNodeIndex) {
  54. int tmp = data[parentNodeIndex - 1];
  55. data[parentNodeIndex - 1] = data[largestNodeIndex - 1];
  56. data[largestNodeIndex - 1] = tmp;
  57. // 交换完父节点和子节点的值,对换了值的子节点检查是否符合最大堆的特性
  58. maxHeapify(data, largestNodeIndex, heapSize);
  59. }
  60. }
  61. }

基数排序

将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后, 数列就变成一个有序序列。

  1. package 排序.基数排序;
  2. import java.util.Arrays;
  3. /**
  4. * 基数排序
  5. * 最差O(d(n+r)) 平均:O(d(r+n)) 最好O(d(n+rd))
  6. * 空间复杂度:辅助存储O(rd+n)
  7. * 稳定
  8. */
  9. public class RadixSort {
  10. private static void radixSort(int[] array, int distance){
  11. radixSort(array, 10, distance);
  12. }
  13. //基于计数排序的基数排序算法
  14. private static void radixSort(int[] array,int radix, int distance) {
  15. //array为待排序数组
  16. //radix,代表基数
  17. //distance代表排序元素的位数
  18. int length = array.length;
  19. int[] temp = new int[length];//用于暂存元素
  20. int[] count = new int[radix];//用于计数排序 每个位的个数有多少个,
  21. int divide = 1;
  22. for (int i = 0; i < distance; i++) {
  23. System.arraycopy(array, 0,temp, 0, length);
  24. Arrays.fill(count, 0); //每一次循环count数组清0
  25. for (int j = 0; j < length; j++) {
  26. int tempKey = (temp[j]/divide)%radix;
  27. count[tempKey]++;
  28. }
  29. for (int j = 1; j < radix; j++) { //记录每位个数后,作用改变了,变成要插入的位置
  30. count [j] = count[j] + count[j-1];
  31. }
  32. for (int j = length - 1; j >= 0; j--) {
  33. int tempKey = (temp[j]/divide)%radix;
  34. count[tempKey]--;
  35. array[count[tempKey]] = temp[j];
  36. }
  37. for (int k = 0; k < array.length; k++) {
  38. System.out.print(array[k]+" ");
  39. }
  40. System.out.println();
  41. divide = divide * radix;
  42. }
  43. }
  44. public static void main(String[] args) {
  45. int[] array = {27,55,58,94,77,46,13};
  46. radixSort(array,2); //基数一般都是10
  47. for (int i = 0; i < array.length; i++) {
  48. System.out.print(array[i]+" ");
  49. }
  50. System.out.println();
  51. /* int[] array2 = {10,1001,1110,10000,1011011,0,101111};
  52. radixSort(array2, 2, 6);
  53. for (int i = 0; i < array2.length; i++) {
  54. System.out.print(array2[i]+" ");
  55. }*/
  56. }
  57. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注