码迷,mamicode.com
首页 > 编程语言 > 详细

经典排序算法

时间:2021-06-08 22:35:45      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:数值   线性   选择排序   遇到   基数排序   array   nlog   映射关系   java   

排序

  1. 分类

    • 外排序:由于数据太大,因此把数据放在磁盘中,而排序通过磁盘和内存的数据传输才能进行(k路归并)

    • 内排序:所有操作再内存就可以完成

    • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。

    • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

    • ![image](https://img2020.cnblogs.com/blog/1586275/202106/1586275-20210607220445367-665732494.jpg)

    • ![image](https://img2020.cnblogs.com/blog/1586275/202106/1586275-20210607220455449-1642496006.jpg)

  2. 冒泡排序:

    • 比较两个相邻的元素,如果前一个比后一个大,就交换 = 每次回确定一个最大数并且交换到对应的末位

    •  public static void main(String[] args) {
           int[] arr = {2, 4, 1, 14, 22, -5, 9, 0};
           int len = arr.length;
           for (int i = 0; i < len; i++) {
               for (int j = 1; j < len - i; j++) {
                   //前一个比后面的大就交换
                   if (arr[j - 1] > arr[j]) {
                       int tmp = arr[j - 1];
                       arr[j - 1] = arr[j];
                       arr[j] = tmp;
                  }
              }
          }
           System.out.println(Arrays.toString(arr));
       }
  3. 选择排序:

    • 初始状态:无序区为 [0, n),有序区为空

    • 每次从无序区找到第i小的数,将其与i位置的数交换,无序区减一

    •  public static void main(String[] args) {
           int[] arr = {2, 4, 1, 14, 22, -5, 9, 0};
           int len = arr.length;
           for (int i = 0; i < len - 1; ++i) {
               int min = i;
               for (int j = i + 1; j < len; ++j) {
                   if (arr[min] > arr[j]) {
                       min = j;
                  }
              }
               int tmp = arr[i];
               arr[i] = arr[min];
               arr[min] = tmp;
          }
           System.out.println(Arrays.toString(arr));
       }
  4. 插入排序:

    • 初始状态:一般认为第数组的一个数是已排序状态,之后为还未排序区域

    • 每次将当前数与前一个数比较,如果比前一个数小,就交换,直到遇到比它小的或到头了

    •  public static void main(String[] args) {
           int[] arr = {2, 4, 1, 14, 22, -5, 9, 0};
           for (int i = 1; i < arr.length; i++) {
               int inNext = arr[i]; //待排序的数
               int index = i - 1; //待排序数的前一个数下标
               while (index >= 0 && inNext < arr[index]) {
                   arr[index + 1] = arr[index];
                   index--;
              } //退出循环代表以找到位置
               arr[index + 1] = inNext;
          }
           System.out.println(Arrays.toString(arr));
       }
  5. 希尔排序:(缩小增量排序)

    • 简单插入排序的改进版,与插入排序的不同之处在于,它会优先比较距离较远的元素

    • 思路:每次对数组分为Len/2组,每组进行比较交换,每次分组越来越细

    •  public static void main(String[] args) {
           int[] arr = {2, 4, 1, 14, 22, -5, 9, 0};
       //       sort(arr);
           sortMove(arr);
       }
       //交换法
       public static void sort(int[] arr) {
           int temp = 0;
           for (int interval = arr.length / 2; interval > 0; interval /= 2) {
               for (int i = interval; i < arr.length; i++) {
                   for (int j = i - interval; j >= 0; j -= interval) {
                       if (arr[j] > arr[j + interval]) {
                           temp = arr[j];
                           arr[j] = arr[j + interval];
                           arr[j + interval] = temp;
                      }
                  }
              }
          }
           System.out.println(Arrays.toString(arr));
       }
       //移位法
       public static void sortMove(int[] arr) {
           for (int interval = arr.length / 2; interval > 0; interval /= 2) {
               for (int i = interval; i < arr.length; i++) {
                   int j = i;
                   int temp = arr[j];
                   if (arr[j] < arr[j - interval]) {
                       while (j - interval >= 0 && temp < arr[j - interval]) {
                           arr[j] = arr[j - interval];
                           j -= interval;
                      }
                       arr[j] = temp;
                  }
              }
          }
           System.out.println(Arrays.toString(arr));
       }
  6. 归并排序:

    • 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并

    • 步骤:分 -> 合

      1. 把长度为n的输入序列分成两个长度为n/2的子序列;

      2. 对这两个子序列分别采用归并排序;

      3. 将两个排序好的子序列合并成一个最终的排序序列;

    •  //分 : 将数组按二分法分为左右子数组(左右指针),递归,直到left == right跳出递归;
       //合 : 设置两个指针分别对应左右数组,比较大小按序合并为一个数组
  7. 快速排序:

    • 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。(分治法)

    • 步骤

      1. 从数列中挑出一个元素,称为 “基准”(pivot);

      2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

      3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

    •  public static void main(String[] args) {
           int[] arr ={32,6,88,63,2,95,33,8};
           sort(arr);
           System.out.println(Arrays.toString(arr));
       }
       ?
       public static void sort(int[] arr){
           int first = 0;
           int tail = arr.length-1;
           sort(arr,first,tail);
       }
       ?
       public static void sort(int[] arr,int first,int tail){
           if (first<tail){
               int index = partition(arr,first,tail);
               //向左排序
               sort(arr,first,index-1);
               //向右排序
               sort(arr,index+1,tail);
          }
       }
       ?
       public static int partition(int[] arr, int first, int tail){
           int i = first;
           int j = tail;
           int temp = arr[first];
           while (i<j){
               //从右到左,找到第一个小于temp的值
               while (arr[j]>=temp && i<j){
                   j--;
              }
               //将找到的值填入arr[i],i指针向右移一位
               if (i<j){
                   arr[i] = arr[j];
                   i++;
              }
               //从左到右,找到第一个大于temp的值
               while (arr[i]<temp && i<j){
                   i++;
              }
               //将找到的值填入arr[j],j指针向左移一位
               if (i<j){
                   arr[j] = arr[i];
                   j--;
              }
          }
           arr[i] = temp;
           return i;
       }
    • 优化:

      • 对于快排,最主要的点就是基准值的确定,当基准值的数值在中间区域时是最优的,当基准值是最大或者最小时,快排的时间复杂度将是最差的[O(n^2)]

      • 可以对区间取左,右,中三个数,取中位数为基准值

  8. 堆排序:

    • 堆排序(HeapSort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点

    • Java中优先队列(PriorityQueue)实现的方式

    • 步骤:

    •  

  9. 计数排序

    • 计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。 作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数

  10. 桶排序

    • 桶排序是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序 (Bucket sort)的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序

  11. 基数排序

    • 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前

    • 步骤:

      1. 取得数组中的最大数,并取得位数;

      2. arr为原始数组,从最低位开始取每个位组成bucket数组;

      3. 对bucket进行计数排序(利用计数排序适用于小范围数的特点);

    •  public static void main(String[] args) {
           int[] arr ={44,256,77,2,89,60,456};
           sort(arr);
           System.out.println(Arrays.toString(arr));
       }
       ?
       public static void sort(int[] arr){
           int[][] bucket = new int[10][arr.length];
           int[] Effectiveindex = new int[10];
           //找出数组最大的数,得出最大数的位数,来确定循环次数
           int max = arr[0];
           for (int i=1;i<arr.length;i++){
               if (arr[i]>max){
                   max = arr[i];
              }
          }
           int max_length = (max +" ").length();//计算max的位数
           for (int k=0,n=1;k<max_length;k++,n *=10){
               //按基数放数据;记录存放次数
               for (int i=0;i<arr.length;i++){
                   int Remainder = arr[i] /n % 10;
                   bucket[Remainder][Effectiveindex[Remainder]] = arr[i];
                   Effectiveindex[Remainder]++;
              }
               int index = 0;
               //将桶里的数依次放入原数组
               for (int j=0;j<Effectiveindex.length;j++){
                   if (Effectiveindex[j]!=0){//存放进j桶的次数
                       for (int p=0;p<Effectiveindex[j];p++){
                           arr[index++] = bucket[j][p];
                      }
                  }
                   Effectiveindex[j]=0;
              }
          }
       }
  12.  

经典排序算法

标签:数值   线性   选择排序   遇到   基数排序   array   nlog   映射关系   java   

原文地址:https://www.cnblogs.com/hehell/p/14860760.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!