十大经典排序算法

冒泡排序
排序(假设从小到大)的步骤如下:

  • 从头开始,比较相邻的两个数,如果第一个数比第二个数大,那么就交换它们位置。
  • 从开始到最后一对比较完成,一轮结束后,最后一个元素的位置已经确定。
  • 除了最后一个元素以外,前面的所有未排好序的元素重复前面两个步骤。
  • 重复前面 1 ~ 3 步骤,直到所有元素都已经排好序。
    在这里插入图片描述
package com.ty;

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr= {1,10,5,6,3,8,2,0};
        bubbleSort(arr);
        printArr(arr);

    }

    public static void bubbleSort(int[] arr){
        int n=arr.length;
        for(int i=n-1;i>=0;i--){
            for(int j=0;j<i;j++){
                if(arr[j]>arr[j+1]){
                    swap(arr,j,j+1);
                }
            }
        }

    }
    public static void swap(int[] arr,int i,int j){
        int temp;
        temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }
}

选择排序
排序的步骤如下:

  • 从第一个元素开始,遍历其后面的元素,找出其后面比它更小的且最小的元素,若有,则两者交换,保证第一个元素最小。
  • 对第二个元素一样,遍历其后面的元素,找出其后面比它更小的且最小的元素,若存在,则两者交换,保证第二个元素在未排序的数中(除了第一个元素)最小。
  • 依次类推,直到最后一个元素,那么数组就已经排好序了。
package com.ty;

/**
 * @description:  选择排序
 */
public class SelectSort {
    public static void main(String[] args) {
        int[] arr={1,10,5,6,3,8,2,0};
        printArr(arr);
        System.out.println();
        selectSort(arr);
        printArr(arr);
    }
    public static void selectSort(int[] arr){
        int n=arr.length;
        for(int i=0;i<n;i++){
            int minValueIndex=i;
            for(int j=i;j<n;j++){
                minValueIndex=arr[minValueIndex]<arr[j]?minValueIndex:j;
            }
            swap(arr,minValueIndex,i);
        }
    }
    public static void swap(int[] arr,int i,int j){
        int temp;
        temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }


}

插入排序

选择排序是每次选择出最小的放到已经排好的数组后面,而插入排序是依次选择一个元素,插入到前面已经排好序的数组中间,确保它处于正确的位置,当然,这是需要已经排好的顺序数组不断移动。步骤描述如下:

步骤描述如下:

  • 从第一个元素开始,可以认为第一个元素已经排好顺序。
  • 取出后面一个元素 n,在前面已经排好顺序的数组里从尾部往头部遍历,假设正在遍历的元素为 nums[i],如果 num[i] > n,那么将 nums[i] 移动到后面一个位置,直到找到已经排序的元素小于或者等于新元素的位置,将 n 放到新腾空出来的位置上。如果没有找到,那么 nums[i] 就是最小的元素,放在第一个位置。
  • 重复上面的步骤 2,直到所有元素都插入到正确的位置。

在这里插入图片描述

package com.ty;

public class InsertSort {
    public static void main(String[] args) {
        int[] arr={1,7,5,4,3,2,9};
        printArr(arr);
        System.out.println();
        insetSort(arr);
        printArr(arr);
    }
    public static void insetSort(int[] arr){
        int n=arr.length;
        for(int end=1;end<n-1;end++){
           for(int pre=end-1;pre>=0&&arr[pre]>arr[pre+1];pre--){
               swap(arr,pre,pre+1);
           }
        }
    }
    public static void swap(int[] arr,int i,int j){
        int temp;
        temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }
}

希尔排序

希尔排序(Shell’s Sort)又称“缩小增量排序”(Diminishing Increment Sort),是插入排序的一种更高效的改进版本,同时该算法是首次冲破 O(n^2n 2 ) 的算法之一

希尔排序基本步骤如下:

  • 选择一个增量 gap,一般开始是数组的一半,将数组元素按照间隔为 gap 分为若干个小组。
  • 对每一个小组进行插入排序。
  • 将 gap 缩小为一半,重新分组,重复步骤 2(直到 gap 为 1 的时候基本有序,稍微调整一下即可)。
public class ShellSort {
    public static void shellSort(int[] nums) {
        int times = 1;
        for (int gap = nums.length / 2; gap > 0; gap /= 2) {
            System.out.print(
                    "第" + (times++) + "轮希尔排序, gap= " + gap + " ,结果:"
            );
            for (int i = gap; i < nums.length; i++) {
                int j = i;
                int temp = nums[j];
                while (j - gap >= 0 && temp < nums[j - gap]) {
                    // 移动法
                    nums[j] = nums[j - gap];
                    j -= gap;
                }
                nums[j] = temp;
            }
            printf(nums);
        }
    }
    public static void printf(int[] nums) {
      for (int num : nums) {
          System.out.print(num + " ");
      }
      System.out.println("");
    }
}

快速排序
快速排序比较有趣,选择数组的一个数作为基准数,一趟排序,将数组分割成为两部分,一部分均小于/等于基准数,另外一部分大于/等于基准数。然后分别对基准数的左右两部分继续排序,直到数组有序。这体现了分而治之的思想,其中还应用到挖坑填数的策略。

package com.ty;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr={101,109,1,10,5,6,3,8,2,0,-1,99};
        printArr(arr);
        System.out.println();
        quickSort(arr,0,arr.length-1);
        printArr(arr);
    }
    public static void quickSort(int[] arr,int left, int right){
        int pivot =arr[(left+right)/2];
        int l=left,r=right;
        // 让值比pivot 小的放在左边,比pivot 大的放在右边
        while(l<r){
            while (arr[l]<pivot){
                l++;
            }
            while (arr[r]>pivot){
                r--;
            }
            //此时pivot 左边的数字都比他小,右边的数字都比他大
            if(l>=r){
                break;
            }
            //进行交换
            swap(arr,l,r);
            //如果两个数交换的其中有一个的等于pivot
            if(arr[l]==pivot){
                r--;
            }
            if(arr[r]==pivot){
                l++;
            }

        }
        if(l==r){
            l++;
            r--;
        }
        //对排序好的左边部分进行递归
        if(left<r){
            quickSort(arr,left,r);
        }
        //对排序好的右边部分进行递归
        if(l<right){
            quickSort(arr,l,right);
        }

    }
    public static void swap(int[] arr,int i,int j){
        int temp;
        temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }

}

身份证排序

安全局搜索到了一批 (n 个) 身份证号码,希望按出生日期对它们进行从大到小排序,如果有相同日期,则按身份证号码大小进行排序。身份证号码为 18 位的数字组成,出生日期为第 7 到第 14 位。

package com.ty.test01;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class CartId {
    public static void main(String[] args) {
        BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(System.in));
        PrintWriter printWriter=new PrintWriter(new OutputStreamWriter(System.out));
        List<String> strings=new ArrayList<>();
        try(bufferedReader;printWriter) {
            int n = Integer.parseInt( bufferedReader.readLine());
            for (int i = 0; i < n; i++) {
                strings.add(bufferedReader.readLine());
            }
            strings.sort((str1, str2) -> {
                String sub1 = str1.substring(6, 14);
                String sub2 = str2.substring(6, 14);
                if (!sub1.equals(sub2)) {
                    return sub2.compareTo(sub1);
                }
                return str2.compareTo(str1);
            });
            for (String str : strings) {
                printWriter.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


5
466272307503271156
215856472207097978
234804580401078365
404475727700034980
710351408803093165
404475727700034980
234804580401078365
215856472207097978
710351408803093165
466272307503271156


归并排序

前面学的快速排序,体现了分治的思想,但是不够典型,而归并排序则是非常典型的分治策略。归并的总体思想是先将数组分割,再分割 … 分割到一个元素,然后再两两归并排序,做到局部有序,不断地归并,直到数组又被全部合起来。

package com.ty;

public class MergeSort {
    public static void merge(int[]arr,int left,int mid,int right){
        int[]temp=new int[right-left+1];
        int l=left;
        int r=mid+1;
        int t=0;
        // 比较左右两部分的元素,哪个小,就把那个元素填入temp中
        while(l<=mid&&r<=right){
            if(arr[l]<=arr[r]){
                temp[t]=arr[l];
                t++;
                l++;
            }else {
                temp[t] = arr[r];
                t++;
                r++;
            }
        }
        // 如果左边还有元素剩下,则全部合并过去
        while (l<=mid){
            temp[t]=arr[l];
            t++;
            l++;

        }
        // 如果右边有元素剩下,则把右边元素合并过去
        while (r<=right){
            temp[t]=arr[r];
            t++;
            r++;
        }
        //把最后的排序结果复制到原数组
        for(int i=0;i<temp.length;i++){
            arr[left+i]=temp[i];
        }
    }
    public static void sort(int[]arr,int left,int right){
        if(left==right){
            return;
        }
        int mid=(left+right)/2;
        sort(arr,left,mid);
        sort(arr,mid+1,right);
        merge(arr,left,mid,right);
    }

    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }
    public static void main(String[] args) {
        int[] arr={101,109,1,10,5,6,3,8,2,0,-1,99};
        printArr(arr);
        System.out.println();
        sort(arr,0,arr.length-1);
        printArr(arr);
    }
}

计数排序

计数排序,不是基于比较,而是基于计数,比较适合元素数值相近且为整数的情况。

  • 遍历数组,找出最大值和最小值。
  • 根据最大值和最小值,初始化对应的统计元素数量的数组。
  • 遍历元素,统计元素个数到新的数组。
  • 遍历统计的数组,按照顺序输出排序的数组元素。

首先先遍历一遍,找出最小的 min 和最大的元素 max,创建一个大小为 max - min + 1 的数组,再遍历一次,统计数字个数,写到数组中。

然后再遍历一次统计数组,将每个元素置为前面一个元素加上自身,为什么这样做呢?

这是为了让统计数组存储的元素值等于相应整数的最终排序位置,这样我们就可以做到稳定排序,比如下面的 15 对应的是 8,也就是 15 在数组中出现是第 8 个元素,从后面开始遍历,我们就可以保持稳定性。

public class CountSort {

  public static void countSort(int[] nums) {
    int max = nums[0];
    int min = nums[0];
    for (int i = 1; i < nums.length; i++) {
      if (nums[i] > max) {
        max = nums[i];
      }
      if (nums[i] < min) {
        min = nums[i];
      }
    }
    System.out.println("min:" + min + ",max:" + max);
    int count = max - min;
    int[] countNums = new int[count + 1];
    for (int i = 0; i < nums.length; i++) {
      countNums[nums[i] - min]++;
    }
    System.out.print("countNums: ");
    printf(countNums);
    int sum = 0;
    // 后面的元素等于前面元素加上自身
    for (int i = 0; i < count + 1; i++) {
      sum += countNums[i];
      countNums[i] = sum;
    }
    System.out.print("countNums: ");
    printf(countNums);
    int[] newNums = new int[nums.length];
    for (int i = nums.length - 1; i >= 0; i--) {
      /**
       * nums[i] - min 表示原数组 nums 里面第i位置对应的数在统计数组里面的位置索引
       */
      newNums[countNums[nums[i] - min] - 1] = nums[i];
      countNums[nums[i] - min]--;
    }
    printf(newNums);
  }
  public static void printf(int[] nums) {
    for (int num : nums) {
        System.out.print(num + " ");
    }
    System.out.println("");
  }
}

桶排序
桶排序,是指用多个桶存储元素,每个桶有一个存储范围,先将元素按照范围放到各个桶中,每个桶中是一个子数组,然后再对每个子数组进行排序,最后合并子数组,成为最终有序的数组。这其实和计数排序很相似,只不过计数排序每个桶只有一个元素,而且桶存储的值为该元素出现的次数。

桶排序的具体步骤:

  • 遍历数组,查找数组的最大最小值,设置桶的区间(非必需),初始化一定数量的桶,每个桶对应一定的数值区间。
  • 遍历数组,将每一个数,放到对应的桶中。
  • 对每一个非空的桶进行分别排序(桶内部的排序可以选择 JDK 自带排序)。
  • 将桶中的子数组拼接成为最终的排序数组。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class BucketSort {

  public static void bucketSort(int[] nums) {
    // 遍历数组获取最大最小值
    int max = Integer.MIN_VALUE;
    int min = Integer.MAX_VALUE;
    for (int i = 0; i < nums.length; i++) {
      max = Math.max(max, nums[i]);
      min = Math.min(min, nums[i]);
    }

    // 计算桶的数量
    int bucketNum = (max - min) / nums.length + 1;
    System.out.println(
      "最小:" + min + ",最大:" + max + ",桶的数量:" + bucketNum
    );
    List<List<Integer>> buckets = new ArrayList<List<Integer>>(bucketNum);
    for (int i = 0; i < bucketNum; i++) {
      buckets.add(new ArrayList<Integer>());
    }

    // 将每个元素放入桶
    for (int i = 0; i < nums.length; i++) {
      int num = (nums[i] - min) / (nums.length);
      buckets.get(num).add(nums[i]);
    }

    // 对每个桶内部进行排序
    for (int i = 0; i < buckets.size(); i++) {
      Collections.sort(buckets.get(i));
    }

    // 将桶的元素复制到数组中
    int index = 0;
    for (int i = 0; i < buckets.size(); i++) {
      for (int j = 0; j < buckets.get(i).size(); j++) {
        nums[index++] = buckets.get(i).get(j);
      }
    }
  }

  public static void printf(int[] nums) {
    for (int num : nums) {
      System.out.print(num + " ");
    }
    System.out.println("");
  }
}

堆排序
排序的思路为:

  • 将无序的数组构建出一个大顶堆,也就是上面的元素比下面的元素大。
  • 将堆顶的元素和堆的最末尾的元素交换,将最大元素下沉到数组的最后面(末端)。
  • 重新调整前面的顺序,继续交换堆顶的元素和当前末尾的元素,直到所有元素全部下沉。
package com.ty;

public class HeapSort {
    public static void heaptrify(int[] arr,int cur,int length){
        int leftNode=cur*2+1;
        int rightNode=cur*2+2;
        int maxNode=cur;
        if(leftNode<length&&arr[maxNode]<arr[leftNode]){
           maxNode=leftNode;
        }
        if(rightNode<length&&arr[maxNode]<arr[rightNode]){
            maxNode=rightNode;
        }
        if(maxNode!=cur){
            swap(arr,maxNode,cur);
            heaptrify(arr,maxNode,length);
        }
    }
    public static void buildHeap(int[]arr){
        int lastNode=arr.length-1;
        int curNode=(lastNode-1)/2;
        for (int i = curNode; i >=0 ; i--) {
            heaptrify(arr,i, arr.length);
        }
    }

    public static void heapSort(int[]arr){
        buildHeap(arr);
        int k=arr.length-1;
        while(k>=0){
            swap(arr,0,k);
            heaptrify(arr,0,k);
            k--;
        }
    }

    public static void swap(int[] arr,int i,int j){
        int temp;
        temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void printArr(int[] arr){
        for(int i:arr){
            System.out.print(i+" ");
        }
    }

    public static void main(String[] args) {
        int[] arr= {1,10,5,6,3,8,2,0,100,45};
        printArr(arr);
        heapSort(arr);
        System.out.println();
        printArr(arr);
    }
}

基数排序

假设有一串数字,12,12, 10, 45, 32, 56, 677, 93, 22, 22, 30。

先准备一个盒子,里面有0到9的数据。

第一步、根据个位的数字将按照顺序排列到盒子里:10, 30, 12, 12, 32, 22, 22, 93, 45, 56, 677

第二步、根据十位的数字将按照顺序排列到盒子里:10, 12, 12, 22, 22, 30, 32, 45, 56, 677, 93

第三步、根据百位的的数字按照顺序排列到盒子里:10, 12, 12, 22, 22, 30, 32, 45, 56, 93, 677

1、判断这一串数字中最大数的位数。
2、因为每次排序只有位数不一样,所以排序的代码基本相同,用一个循环实现排序。
3、打印排序好的数。

import java.util.Arrays;

public class Paix {
    public static void main(String[] args) {
        int[] arr = new int[]{12,12, 10, 45, 32, 56, 677, 93, 22, 22, 30};  //定义一个数组
        int max = 0;
        for (int k : arr) {       //得到这些数里面最大数的长度
            if ((k + "").length() > max) {
                max = (k + "").length();
            }
        }

        for (int x = 0; x < max; x++) {
            int[][] temp = new int[10][arr.length];
            int[] tempcount = new int[10];
            int n = (int) Math.pow(10, x);
            for (int k : arr) {
                int number = (((k / n) % 10));
                temp[number][tempcount[number]] = k;   //temp[number]默认值为0
                tempcount[number]++;
            }

            int result = 0;
            for (int i = 0; i < tempcount.length; i++) {
                for (int j = 0; j < tempcount[i]; j++) {
                    arr[result] = temp[i][j];
                    result++;
                }
            }

            System.out.println(Arrays.toString(arr));
        }
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值