Java排序算法

左(少)右(多)
left(less)midright(more)
  • 排序:将数据元素按照从小到大或从大到小的顺序
  • 数据结构:存储数据的不同方式。
  • 算法(Algorithm):同一个问题的不同解决方法。(针对特定数据结构的)
  • 测算算法的优劣
  • 时间测算
    • 计算算法时间差 幅度不够循环来凑(for循环)
  • 空间测算
    • O表示时间复杂度
      • O(1):以不变应万变(查询数组中的某一个数字arr[1]和arr[100]所花费的时间是一样的)
      • O(n):随着查询规模的扩大,查询时间随之扩大 (for循环、数组平均数)

排序问题:
在这里插入图片描述

宋词记忆法:
选泡插,
快归堆希统计基,
恩方恩老恩一三,
对恩加K恩加K,
不稳稳稳不稳稳,
不稳不稳稳稳稳。

在这里插入图片描述

  • 稳定性是干什么用的
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/072a83c2bd7d43a989ce1f6922bed7ee.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA6Zu35Y-k5YuS5pav,size_20,color_FFFFFF,t_70,g_se,x_16

1.1 选择排序:(不稳)

最简单也最没用(时间复杂度高,且不稳)
在这里插入图片描述

/**
 * 选择排序
 *       有能想到minPos中间变量的思维进行中间变量的转换
 *       优化:
 *          如果一次遍历不仅能找到最小值还能找到最大值,则外循环就能减少一倍
 */
public class My1Selection {
    public static void main(String[] args) {
        int[] arr = new int[]{15, 68, 95, 25, 14};
        for (int i = 0; i < arr.length; i++) {
            int minPos = i;  //进行再一次替换最小值
            for (int j = i + 1; j < arr.length; j++) {
                minPos = arr[minPos] > arr[j] ? j : minPos;
            }
            new My1Selection().swap(arr,i,minPos);
            System.out.print("经过第" + (i+1) + "次循环后的结果");
            System.out.println(Arrays.toString(arr));
        }
    }
    public void swap(int[] arr,int i,int minPos){
        //将最小值的位置按顺序排列
        int temp = arr[i];
        arr[i] = arr[minPos];
        arr[minPos] = temp;
    }
}

时间复杂度
在这里插入图片描述

1.1.1 验证算法–(对数器)

产生足够多随机样本
比对被验证算法的结果是否准确
public class My1DataChecker {
    public static void main(String[] args) {
        check();
    }
    //产生随机数组
    static int[] random(){
        Random r = new Random();
        int[] arr1 = new int[1000];
        for (int i = 0; i < arr1.length; i++) {
            arr1[i] = r.nextInt(1000);  //100随机数产生的范围
        }
        return arr1;
    }
    //选择排序算法
    static void SelectionSort(int[] arr2){
        for (int i = 0; i < arr2.length; i++) {
            int isPos = i;
            for (int j = i+1; j < arr2.length; j++) {
                isPos = arr2[isPos]>arr2[j]?j:isPos;
            }
            new My1DataChecker().swap(arr2,i,isPos);
        }
    }
    //数组位置的交换
    static void swap(int[] arr2,int i,int isPos){
        int temp = arr2[i];
        arr2[i] = arr2[isPos];
        arr2[isPos] = temp;
    }

    //系统算法和选择排序结果比较(本节重点)
    static void check(){
        int[] arr1 = random();
        int[] arr2 = new int[arr1.length];
        System.arraycopy(arr1,0,arr2,0,arr1.length);//复制数组
        System.out.println("未排序前的数组:" + Arrays.toString(arr1));
        Arrays.sort(arr1);//系统排序
        SelectionSort(arr2);//采用选择算法进行排序
        System.out.println("arr1 = "+Arrays.toString(arr1));
        System.out.println("arr2 = "+Arrays.toString(arr2));
        boolean same = true;
        for (int i = 0; i < arr2.length; i++) {
            if(arr1[i] != arr2[i]){
                same = false;
            }
        }
        System.out.println(same == true?"true":"false");
    }

}

1.2 冒泡排序(太慢)

算法核心:比较相邻两个元素,将较大的元素互换。

关键代码实现

/**
 * 冒泡排序(方法一)
 *        注意内层循环的取值范围
 * 		  数组中的数据是否是顺序都要执行判断一遍
 */
public class My2Bubble {
    static void mySort(int[] arr1){
        for (int i = 0; i < arr1.length; i++) {//排序次数--共有几轮比较
            for (int j = 0; j < arr1.length-i-1; j++) { //交换次数(数组越界问题)
                if(arr1[j]>arr1[j+1]){
                    int temp = arr1[j];
                    arr1[j] = arr1[j+1];
                    arr1[j+1] = temp;
                }
            }
        }
    }
}
/**
 * 冒泡排序(方法二)
 *   时间复杂度减少
 *   当所给数组是按照顺序排列则只进行了arr.length次for循环
 */
public class My2Bubble {
    static void mySort(int[] arr1){
    boolean swaped=true;
    while(swaped){
        for (int i = 0; i < arr1.length-1; i++) {
            swaped=false;
            if(arr1[j]>arr1[j+1]){
                int temp = arr1[j];
                arr1[j] = arr1[j+1];
                arr1[j+1] = temp;
        
                swaped=true;
            }
        }
    }
}

检验算法

public class My2DataChecker {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {//重复查询10次以确保数据的准确性
            swap();
        }
    }
    //随机数组
    static int[] myRandom() {
        Random ran = new Random();//随机数的生成
        int[] arr = new int[100]; //设置数组的元素个数
        for (int i = 0; i < arr.length; i++) {
            arr[i] = ran.nextInt(100); //设置数组的取值范围
        }
        return arr;
    }

    //比对
    static void swap() {
        int[] arr = myRandom();
        int[] arr2 = new int[arr.length];
        System.arraycopy(arr, 0, arr2, 0, arr2.length); //数组的复制

        Arrays.sort(arr);
        new My2Bubble().mySort(arr2);

        System.out.println("arr "+Arrays.toString(arr));
        System.out.println("arr2"+Arrays.toString(arr2));

        boolean same1 = true;
        for (int i = 0; i < arr2.length; i++) {
            same1 = arr[i]==arr2[i]?true:false;
        }
        System.out.println(same1);

    }
}

在这里插入图片描述

1.3 插入排序(基本有序时效率高)

样本小且基本有序的时候效率比较高

在这里插入图片描述

核心代码:

 * 插入排序的方法
 *    注意:内层for循环的初始化设置
 */
public class My3Insertion {
    public void mySort(int[] arr){
        for (int i = 1; i < arr.length; i++) {//顺序排好的个数
            for (int j = i; j > 0; j--) {//未排序的数组
                if(arr[j]<arr[j-1]){
                    int temp = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1] = temp;
                }
            }
        }
    }
}

检验方法相同(冒泡排序)

1.4 希尔排序(改进的插入排序)

在这里插入图片描述

过程:

  • 给定一个间隔,跳着按插入排序进行运算
  • 以此类推,一轮拍完之后减少间隔再次排序
  • 直至间隔为1时,再次采用插入排序进行运算

间隔最佳方法

  • Knuth序列:h=3*h+1

核心代码:(验证方法冒泡排序)

/**
 * 希尔排序
 *      注意间隔的变化
 *      for循环的问题变化比较多
 */
public class My4Shell {
    public void mySort(int[] arr){
        int h = 1;//当h=1时就是插入排序
        while(h<= arr.length/3){   //判断数组的长度是否满足最佳间隔(Knuth序列)
            h = 3*h+1; //间隔个数
        }
        for (int i = h; i >0 ; i=(i-1)/3) {//i--可随自己的需求改变
            for (int j = i; j < arr.length; j++) {
                for (int k = j; k > i-1 ; k-=i) {
                    if(arr[k]<arr[k-i]){
                       int temp = arr[k];
                       arr[k] = arr[k-i];
                       arr[k-i] = temp;
                    }
                }
            }
        }
    }
}

1.5 归并排序(递归的扩展应用)

/**
 * 递归
 *     前10项和
 */
public class my5Merge_1 {
    public static void main(String[] args) {
        System.out.println(Recursion(10));
    }
    static int Recursion(int x){
        if(x<0){
            return -1;
        }
        if(x==0){
            return 0;
        }
        return x+(Recursion(x-1));
    }
}

归并排序(算法核心)

static void mySort(int[] arr,int left,int right){
    if(left == right) return;
    //分两份
    int l = left+(right-left)/2;
    //左边
    mySort(arr,0,l);
    //右边
    mySort(arr,l+1,right);

    myswap(arr,left,l+1,right);

}
static void myswap(int[] arr,int leftPrt,int rightPrt,int rightEnd){
    int initiation = leftPrt;
    int centre = rightPrt;
    int[] arr1 = new int[rightEnd-leftPrt+1];
    int i = 0;

    while(initiation < rightPrt && centre <= rightEnd){
        arr1[i++] = arr[initiation]<=arr[centre]?arr[initiation++]:arr[centre++];
        /*
        if (arr[begin] <= arr[centre]) {  //“=”代表稳定性的问题
            arr1[i] = arr[begin];
            begin++;
            i++;
        }
        else{
            arr1[i] = arr[centre];
            centre++;
            i++;
        }
         */
    }
    while(initiation<rightPrt)arr1[i++]=arr[initiation++];//(1,3,4,8 10),2,5
    while(centre<=rightEnd)arr1[i++]=arr[centre++];//1,3,5,(2,4,6,8,10)

    for (int j = 0; j < arr1.length; j++) {
        arr[leftPrt+j] = arr1[j];
    }
}

对象排序一般要求稳定

1.6 快速排序

在这里插入图片描述

过程:(拿到边缘的值时是最坏的情况)

  • 选中一个值作为目标(比他大的排在前面,比他小的排在后面)
  • 在第一轮的基础上,再在左边的序列中选择一个作为目标重复相同的操作
  • 直至选中值的左边只有一个数时直接输出(右边同理)

算法核心:

public class My6Quick {
   
    static void mySort(int[] arr,int left,int right) {
        if(left>=right) return;  //当只有一个数时
        int mid = myopinion(arr, left, right);
        mySort(arr, left,mid-1);
        mySort(arr, mid+1,right);
    }
    static int myopinion(int[] arr,int leftPrt,int rightPrt){
        int point = arr[rightPrt];
        int point1 = leftPrt;
        int point2 = rightPrt-1;
        while(point1<=point2){//"=",最后两个数的排序时进入循环
            while(point1<=point2 && arr[point1]<=point) point1++; //对数组左边的数进行比较判断(从第一个数到目标位置)
            while(point1<=point2 && arr[point2] >point) point2--; //对数组右边的数进行比较判断(从最后一个数到目标位置)

            if(point1<point2){   //两个目标位置比较大小{1,3,2,(8),5,6,(4),9,8}
                swap(arr,point1,point2);
            }
        }
        swap(arr,point1,rightPrt);
        return point1;
    }
    static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

1.7 计数排序(量大但范围小)

在这里插入图片描述

桶排序的个例之一
非比较排序
适用于特定问题,对源程序有要求。

  • 算法思想
    • 量大但范围小
      • 数万员工的年龄
      • 高考名

过程:

  • 首先统计某一个数出现的次数,
  • 在一个等长的数组中对其输出

算法核心

static int[] mySort(int[] arr){
    int[] result = new int[arr.length];
    int[] count = new int[5];
    for (int i = 0; i < arr.length; i++) {
        count[arr[i]]++;//出现的次数进行计算
    }
    System.out.println("result = "+Arrays.toString(count));
    //结果的输出
    /**
     * 方法一
     */
    /*
    for (int i = 0,j = 0; i < count.length; i++) {
        while(count[i]-->0) result[j++] = i;
    }
    System.out.println("排序后:" + Arrays.toString(result));
    */
    /**
     * 方法二
     */
    for (int i = 0; i < count.length; i++) {
        count[i]+=count[i-1];//统计数组的个数(每一个值-1就是相同数字的最后一个)比如([1, 1, 0, 2, 0, 3, 4, 4, 2, 3]
                                                                            // [2, 4, 6, 8, 10])2-1=1(最后一个0所在位置)
                                                                            //[0, 0, 1, 1, 2, 2, 3, 3, 4, 4]
    }
    for (int i = arr.length-1; i > 0 ; i--) {
        result[--count[arr[i]]] = arr[i];
    }
    return result;
}

以下排序算法很少用到知晓其工作原理即可。

1.8 基数排序

多关键字的排序
在这里插入图片描述

1.9 桶排序

在这里插入图片描述

1.10 堆排序

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值