zoukankan      html  css  js  c++  java
  • 八大排序算法

    冒泡排序

    1. 思想
      1. 通过对待排序序列从前向后依次比较相邻元素的值, 若发现逆序则交换, 使值较大的元素逐渐从前移向后部, 就像水底下的气泡一样逐渐向上冒.
    2. 优化
      1. 因为排序的过程中, 各元素不断接近自己的位置, 如果一趟比较下来没有进行过交换, 说明序列有序了.因此要在排序的过程中设置一个flag判断元素是否进行过交换, 从而减少不必要的比较.
    3. 代码
          public static void bubbleSort(int[] arr) {
              boolean flag = false;
              for(int i = 0; i < arr.length - 1; i++) {
                  for(int j = 0; j < arr.length-1-i; j++) {
                      if(arr[j] > arr[j+1]) {
                          swap(arr, j, j+1);
                          flag = true;
                      }
                  }
                  if(!flag) {
                      return;
                  }
                  flag = false;
              }
          }
      
          private static void swap(int[] arr, int j, int i) {
              int temp = arr[j];
              arr[j] = arr[i];
              arr[i] = temp;
          }

    选择排序

    1. 基本介绍
      1. 是从欲排序的数据中, 按指定的规则选出某一元素, 再依规定交换位置后达到排序的目的.
    2. 基本思想
      1. 第一次从arr[0]到arr[n-1]中选取最小值, 与arr[0]交换.
      2. 第二次从arr[1]到arr[n-1]中选取最小值, 与arr[1]交换,
      3. ......
    3. 代码
          public static void selectSort(int[] arr) {
              for (int i = 0; i < arr.length - 1; i++) {
                  for (int j = i + 1; j < arr.length; j++) {
                      if (arr[i] > arr[j]) {
                          swap(arr, i, j);
                      }
                  }
              }
          }
      
          private static void swap(int[] arr, int j, int i) {
              int temp = arr[j];
              arr[j] = arr[i];
              arr[i] = temp;
          }

    插入排序

    1. 介绍
      1. 是对于欲排序的元素以插入的方式找该元素适当位置, 以达到排序的目的.
    2. 思想
      1. 把n个待排序的元素看成一个有序表和一个无序表, 开始时有序表只有一个元素, 无序表有n-1个元素, 排序过程中每次从无序表中取出第一个元素, 把它的排序码依次与有序表元素的排序码比较, 将它插入到有序表中的适当位置.
    3. 代码
          public static void insertSort(int[] arr) {
              int i, j, temp;
              for (i = 0; i < arr.length; i++) {
                  temp = arr[i];
                  j = i - 1;
                  while (j >= 0 && temp < arr[j]) {
                      arr[j + 1] = arr[j];
                      j--;
                  }
                  arr[j + 1] = temp;
              }
          }

    快速排序

    1. 介绍
      1. quickSort是对冒泡排序的一种改进.
      2. 基本思想: 通过一趟排序将要排序的数据分隔为独立的两部分, 其中一部分的所有数据比另一部分的所有数据都小, 然后按此方法对两部分数据分别快排, (整个排序过程可以看成一个递归过程), 依此下去, 直到有序.
    2. 代码
          public static void quickSort(int[] arr, int left, int right) {
              int l = left; // 左索引
              int r = right; // 右索引
              // int mid = arr[(int)Math.random()*(right-left+1)+left];
              int mid = arr[(left + right) / 2];
              // while循环的目的是让比mid小的放到其左边, 比mid大的值放到右边.
              while (l < r) {
                  // 在mid左边一直找, 直到找到>=mid的值
                  while (arr[l] < mid) {
                      l++;
                  }
                  // 在mid右边一直找, 直到找到<=mid的值
                  while (arr[r] > mid) {
                      r--;
                  }
                  // 如果 l>=r 成立, 说明mid左右两边的值已经按照左边都<=mid, 右边都>=mid了.
                  if (l >= r)
                      break;
                  // 交换
                  swap(arr, l, r);
      
                  // 如果交换完后, 发现arr[l] == mid, 让r--
                  if (arr[l] == mid)
                      r--;
                  // 如果交换完后, 发现arr[r] == mid, 让l++
                  if (arr[r] == mid)
                      l++;
              }
              // 如果l==r, 必须l++, r--, 否则栈溢出
              if (l == r) {
                  l++;
                  r--;
              }
              // 向左递归
              if (left < r)
                  quickSort(arr, left, r);
              // 向右递归
              if (right > l)
                  quickSort(arr, l, right);
          }

    希尔排序

    1. 概述
      1. 希尔排序也是一种插入排序, 它是简单插入排序经过改进后的高效版本, 也叫缩小增量排序.
    2. 基本思想
      1. 把记录按下标的一定增量分组, 对每组使用直接插入排序算法排序, 随着增量逐渐减少, 每组包含的关键词变多, 当增量减至1时, 整个文件恰好被分为一组, 算法终止.
    3. 代码
      1. 交换式, 很垃圾, 比插入排序还慢
            public static void shellSort(int[] arr) {
                int gap = arr.length / 2;
                while (gap > 0) {
                    for (int i = gap; i < arr.length; i++) {
                        for (int j = i - gap; j >= 0; j -= gap) {
                            if (arr[j] > arr[j + gap])
                                swap(arr, j, j + gap);
                        }
                    }
                    gap /= 2;
                }
            }
      2. 移动式
            public static void shellSort(int[] arr) {
                int i, j, temp;
                int gap = arr.length / 2;
                while (gap > 0) {
                    for (i = gap; i < arr.length; i++) {
                        j = i;
                        temp = arr[i];
                        if (arr[j] < arr[j - gap]) {
                            while (j - gap >= 0 && temp < arr[j - gap]) {
                                arr[j] = arr[j - gap];
                                j -= gap;
                            }
                            arr[j] = temp;
                        }
                    }
                    gap /= 2;
                }
            }

    归并排序

    1. 介绍
      1. 采取分治策略
        • 分: 把问题分成一些小的问题然后递归求解
        • 治: 把分的阶段得到的各答案"修补"在一起, 即分而治之.
    2. 代码
          // 分+合的方法
          public static void mergeSort(int[] arr, int left, int right, int[] temp) {
              if (left < right) {
                  int mid = (left + right) / 2; // 中间的索引
                  // 向左递归进行分解
                  mergeSort(arr, left, mid, temp);
                  // 向右递归进行分解
                  mergeSort(arr, mid + 1, right, temp);
                  // 合并
                  merge(arr, left, mid, right, temp);
              }
          }
      
          // 合并的方法
          public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
              int i = left; // 初始化i, 左边有序序列的初始索引
              int j = mid + 1; // 初始化j, 右边有序序列的初始索引
              int t = 0; // 指向temp数组的当前索引
      
              // 先把左右两边(有序)的数据按照规则填充到temp数组, 直到有一边全部处理完毕
              while (i <= mid && j <= right) {
                  if (arr[i] <= arr[j]) {
                      temp[t++] = arr[i++];
                  } else {
                      temp[t++] = arr[j++];
                  }
      
              }
      
              // 把剩余的填充到temp数组中
              while (i <= mid) {
                  temp[t++] = arr[i++];
              }
      
              while (j <= right) {
                  temp[t++] = arr[j++];
              }
      
              // 将temp数组的元素拷贝到arr
              // 并不是每次都拷贝所有的
              t = 0;
              int tempLeft = left;
              while (tempLeft <= right) {
                  arr[tempLeft++] = temp[t++];
              }
          }

    基数排序

    1. 介绍
      1. 属于分配式排序, 又称桶排序, 顾名思义, 它是通过键值的各个位的值, 将要排序的元素分配至某些桶中,  达到排序的作用.
      2. 是将整数按位数切割成不同的数字, 然后按每个位数分别比较.
    2. 基本思想
      1. 将所有待比较数值统一为同样的数位长度, 数位短的数前面补零, 然后从最低位开始, 依次进行依次排序, 这样从最低位排序一直到最高位排序完成以后, 数列就有序了.
      2. 第一轮: 将每个元素的个位数取出, 然后看这个数应该放在哪个对应的桶, 按照这个桶的顺序(一维数组的下标依次取出数据, 放入原来数组)
      3. 第二轮: 将每个元素的十位数取出, 然后看这个数该放入哪个对应的桶, 按照这个桶的顺序(一维数组的下标依次取出数据, 放入原来数组)
      4. 依次下去, 直到有序
    3. 小数不能用基数排序
    4. 代码
          //该代码仅仅实现了非负数的排序, 若有负数出现, 则会ArrayIndexOutOfBoundsException
          public static void radixSort(int[] arr) {
              int[][] bucket = new int[10][arr.length];
              int[] cnt = new int[10];
              int max = arr[0];
              for (int i = 1; i < arr.length; i++) {
                  if (arr[i] > max)
                      max = arr[i];
              }
              int maxLen = ("" + max).length();
              for (int i = 0, n = 1; i < maxLen; i++, n *= 10) {
                  for (int j = 0; j < arr.length; j++) {
                      int digit = arr[j] / n % 10;
                      bucket[digit][cnt[digit]++] = arr[j];
                  }
                  int index = 0;
                  for (int k = 0; k < arr.length; k++) {
                      if (cnt[k] != 0) {
                          for (int l = 0; l < cnt[k]; l++)
                              arr[index++] = bucket[k][l];
                      }
                      cnt[k] = 0;
                  }
              }
          }
    5. 一轮一轮的讲解
          public static void radixSort(int[] arr) {
      
              // 定义一个二维数组表示10个桶, 每个桶就是一个一维数组
              // 为了防止放数时数据溢出, 则每个桶的大小定为arr.length
              // 很明显, 基数排序是用空间换时间的经典算法.
              int[][] bucket = new int[10][arr.length];
      
              // 为了记录每个桶中实际存放了多少个数据, 我们定义一个一维数组来记录各个桶每次放入数据个数
              int[] cnt = new int[10];
      
              // 第一轮(针对每个元素的个位进行排序处理)
              for (int i = 0; i < arr.length; i++) {
                  // 取出每个元素的个位
                  int digit = arr[i] % 10;
                  // 放入到对应桶中
                  bucket[digit][cnt[digit]++] = arr[i];
              }
              // 按照桶的顺序, 放入原来数组
              int index = 0;
              // 遍历每个桶, 并将每个桶中数据放入原数组
              for (int i = 0; i < cnt.length; i++) {
                  // 如果桶中有数据, 才放入到原数组
                  if (cnt[i] != 0) {
                      // 循环第i个桶, 放入数据即可
                      for (int j = 0; j < cnt[i]; j++) {
                          arr[index++] = bucket[i][j];
                      }
                  }
                  // 第一轮结束把cnt数组清空
                  cnt[i] = 0;
              }
              System.out.println("第一轮对个位的处理: " + Arrays.toString(arr));
      
              // 第二轮(针对每个元素的十位进行排序处理)
              for (int i = 0; i < arr.length; i++) {
                  // 取出每个元素的十位
                  int digit = arr[i] / 10 % 10;
                  // 放入到对应桶中
                  bucket[digit][cnt[digit]++] = arr[i];
              }
              // 按照桶的顺序, 放入原来数组
              index = 0;
              // 遍历每个桶, 并将每个桶中数据放入原数组
              for (int i = 0; i < cnt.length; i++) {
                  // 如果桶中有数据, 才放入到原数组
                  if (cnt[i] != 0) {
                      // 循环第i个桶, 放入数据即可
                      for (int j = 0; j < cnt[i]; j++) {
                          arr[index++] = bucket[i][j];
                      }
                  }
                  cnt[i] = 0;
              }
              System.out.println("第二轮对个位的处理: " + Arrays.toString(arr));
      
              // 第三轮(针对每个元素的百位进行排序处理)
              for (int i = 0; i < arr.length; i++) {
                  // 取出每百元素的个位
                  int digit = arr[i] / 100 % 10;
                  // 放入到对应桶中
                  bucket[digit][cnt[digit]++] = arr[i];
              }
              // 按照桶的顺序, 放入原来数组
              index = 0;
              // 遍历每个桶, 并将每个桶中数据放入原数组
              for (int i = 0; i < cnt.length; i++) {
                  // 如果桶中有数据, 才放入到原数组
                  if (cnt[i] != 0) {
                      // 循环第i个桶, 放入数据即可
                      for (int j = 0; j < cnt[i]; j++) {
                          arr[index++] = bucket[i][j];
                      }
                  }
                  cnt[i] = 0;
              }
              System.out.println("第三轮对个位的处理: " + Arrays.toString(arr));
          }

    堆排序

    ################

    总结

        

    • In-place: 不占用额外内存, Out-place: 占用额外内存
  • 相关阅读:
    Android Service总结06 之AIDL
    Android Service总结05 之IntentService
    Android Service总结04 之被绑定的服务 -- Bound Service
    Android Service总结02 service介绍
    Android Service总结03 之被启动的服务 -- Started Service
    Android Service总结01 目录
    Android 数据存储04之Content Provider
    Android 数据存储03之SQLite
    Android 数据存储02之文件读写
    Android 数据存储01之SharedPreferences
  • 原文地址:https://www.cnblogs.com/binwenhome/p/12838429.html
Copyright © 2011-2022 走看看