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

    一、冒泡排序

    常用的也是简单的排序算法
    个人理解:

    • 步骤:往后对比、找最值、换最值
      第一层i循环次数就是要排序数组的个数
      第二层j循环可以每次都从第一个数开始往后对比,如果大小于就交换,保证对比值一直都是最值

    第二层循环条件中可以减去i,因为i每次循环后都会得一个最值往后面冒泡,即i下标后面的数已经是排序好的了不用再次对比了

    //冒泡排序
    public class BubbleSort {
        
        public static void main(String[] args){
            int[] arr = {3,9,-1,10,20};
            System.out.println("原数组:"+Arrays.toString(arr));
            bubbleSort(arr);
        }
        
        public static void bubbleSort(int[] arr){
            int temp = 0;
            boolean flag = false;//标识变量,表示一轮对比中是否发生交换
    
            for (int i=0;i<arr.length;i++){
                //j为什么要减i,因为第i次循环时,已经有i个最大的数在后面从小到大排好了。
                // 为什么要减1:因为需要留出一个,让当前数和后面的对比。不减1,当当前元素即j到达最后一个,由于后面没有元素则会溢出
                for (int j=0;j<arr.length-i-1;j++){
                    if (arr[j]>arr[j+1]){ //即通过前后两个数对比,大于就交换,让当前一直保持最大直到比到最后,
                        temp =arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
        }
    }
    

    二、插入排序

    个人理解:

    • 步骤:往前对比,找合适插入位置、记录当前值、移位、当前值插入合适位置
      第一层i循环次数也是要排序数组的个数
    public class InsertSort {
        public static void main(String[] args){
            int[] arr = {3,9,-1,10,20};
            System.out.println("原数组:"+ Arrays.toString(arr));
            insertSort(arr);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
        
        public static void insertSort(int[] arr){
            int preIndex;
            int current;
            for (int i = 1; i < arr.length; i++) {
                preIndex = i; //当前元素下标
                current = arr[i];//当前元素值
                while (preIndex>0  && arr[preIndex-1] > current){
                    arr[preIndex] = arr[preIndex-1];//把数往前移动一位
                    preIndex--;
                }
                //移动完后把当前值插入到对应位置
                arr[preIndex] = current;
            }
        }
        
    }
    

    三、选择排序

    • 步骤:往后对比,一轮循环记录最小值和最小值的下标,直接交换最小值到前面
      第一层i循环次数也是要排序数组的个数
    //选择排序
    public class SelectSort {
        
        public static void main(String[] args){  
            int[] arr = {3,9,-1,10,20};
            System.out.println("原数组:"+Arrays.toString(arr));
            selectSort(arr);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        public static void selectSort(int[] arr) {
            if (arr.length<2){
                return;
            }
            int minIndex; //假定最小数下标
            int min;      //存储最小值
    
            for (int i = 0; i < arr.length-1; i++) {
                minIndex = i; //假定最小值下标等于循环时第一个元素的下标
                min = arr[i]; //假定最小值为循环中的第一个元素
                for (int j = i+1; j < arr.length; j++) {
                    if (arr[j] < min){ //arr[i] 相当于是最小值
                        min = arr[j];
                        minIndex = j;
                    }
                }
                //把最小值交换到前面。
                if (minIndex != i){
                    arr[minIndex] = arr[i];
                    arr[i] = min;
                }
            }
        }
    }
    

    四、归并排序

    //归并排序
    public class MergetSort {
    
        public static void main(String[] args) {
            int[] arr = {8, 4, 5, 7, 1, 3, 6, 2};
            System.out.println("原数组:"+ Arrays.toString(arr));
            int[] temp = new int[arr.length];
            mergetSort(arr,0,arr.length-1,temp);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        //分+合的方法
        public static void mergetSort(int[] arr,int left,int right,int[] temp){
            if (left<right){
                int mid = (left+right)/2;
                //向左递归分解
                mergetSort(arr,left,mid,temp);
                //向右递归分解
                mergetSort(arr,mid+1,right,temp);
    
                //分解一次就合并一次
                merget(arr,left,mid,right,temp);
            }
        }
    
        //合并两个有序数组的方法
        /**
         *
         * @param arr  数组原始索引
         * @param left 左边有序数组的初始索引
         * @param mid  中间索引
         * @param right 右边数组索引
         * @param temp 中转数组--即合并两个数组的有序数组
         */
        public static void merget(int[] arr,int left,int mid,int right ,int[] temp){
    
            int l = left; //初始化i,左边初始索引
            int r = mid+1; //右边初始索引
            int t = 0;
    
            //先把左右两边(有序)数组按照规则填充打temp
            //左右两边有序数组,有一边处理完成,则把另一边的直接拷贝就行了
            while (l  <= mid && r<=right){
                if (arr[l] <= arr[r]) { //左数组元素比右数组元素小
                    temp[t] = arr[l];  //左边元素加入数组
                    t+=1; //有序数组下标加1
                    l+=1; //左边数组下标加1
                }else { //反之,右边数组元素比左数组元素小
                    temp[t] = arr[r];  //左边元素加入数组
                    t+=1; //有序数组下标加1
                    r+=1; //左边数组下标加1
                }
            }
    
            //右边数组遍历完,但是左边没有遍历完
            while (l <= mid){
                temp[t] = arr[l];  //左边元素加入数组
                t+=1; //有序数组下标加1
                l+=1; //左边数组下标加1
            }
            //左边数组遍历完,但是右边没有遍历完
            while (r <= right){
                temp[t] = arr[r];  //左边元素加入数组
                t+=1; //有序数组下标加1
                r+=1; //左边数组下标加1
            }
    
            //把temp数组元素拷贝到arr
            t = 0;
            int tempLeft = left;
            while (tempLeft <= right){ //把排序好的数组拷贝回原数组
                arr[tempLeft] = temp[t];
                t += 1;
                tempLeft += 1;
            }
        }
    }
    

    五、快速排序

    选择一个中轴值,小在左,大在右,一直分治

    public class QuickSort2 {
        public static void main(String[] args){
            int[] arr = {101,34,119,1,-1,90,123};
            System.out.println("原数组:"+ Arrays.toString(arr));
            quickSort(arr,0,arr.length-1);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        public static void quickSort(int[] arr,int left,int right){
            if(left>=right){
                return;
            }
            int l = left;//记录最右边
            int r = right;//记录最左边
    
            // 1-基于基准值交换----快速排序就是找一个基准值,把小的放基准值前面,大的放基准值后面
            int pivot = arr[l];//获取基准值=第一个元素
            int temp = 0;//临时变量,交换使用
            while (l<r){
                //由于是在同一个数组操作,所以需要左右两边一起操作
                //由于要把基准值交换,所以右边最后一定是小于基准值的,所以需要优先判断,即从右边走
                while (arr[r] >= pivot && l<r){
                    //右边如果小于基准值,下标减1
                    r--;//保证下标r的值小于基准值
                }
                while (arr[l] <= pivot && l<r){
                    //左边如果小于基准值,下标加1
                    l++; //保证下标l的值大于基准值
                }
                //因为找到了左边大于基准值,右边小于基准值的两个值,所有左右两边值进行交换
                if (l<r){
                    temp = arr[l];
                    arr[l] = arr[r];
                    arr[r] = temp;
                }
            }
    
            //2-基准值归位-----循环结束后l肯定等于r,并且由于是从右边开始走的所以最后下标r的值一定小于基准值,直接交换即可
            arr[left] = arr[r];
            arr[r] = pivot;
    
            //3-递归----最后左右递归一直分治,基准值已经在合适的位置了就不用参与排序了
            //左递归
            quickSort(arr,left,r-1);
            //右递归
            quickSort(arr,r+1,right);
        }
    }
    

    六、基数排序

    //基数排序
    public class RadixSort {
        public static void main(String[] args){  
            int[] arr = {53,3,542,748,14,214};
            System.out.println("原数组:"+ Arrays.toString(arr));
            radixSort(arr);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        //基数排序方法
        public static void radixSort(int[] arr){
    
            //1-得到最大位数
            int max = arr[0];
            for (int i = 1; i < arr.length; i++) {
                if (arr[i] > max){
                    max = arr[i];
                }
            }
            //2-得到最大数是几位数
            int maxLength = (max+"").length();
    
            //定义一个二维数组,表示10个桶.每一行即一维数组表示一个桶
            // 为了防止放入数的时候,数据溢出,则每个一维数组(),大小定位arr.length
            // 明确:基数排序是使用空间换时间。
            int[][] bucket = new int[10][arr.length];
            //为了记录每个桶中实际存放多少个数据,定义一个一维数组来记录各个桶放入数据的个数
            int[] bucketElementCounts = new int[10]; //对应存放十个桶中,最后一个元素的下标,即桶存储了几个数据
    
            //3-循环
            for (int i = 0,n=1; i < maxLength; i++,n*=10) {
                //针对每个元素对应位进行排序处理 ,第一是个位,第二是百位,第三是千位 .......
                for (int j = 0; j < arr.length; j++) {
                    //取出每个元素个位数,相当于要存放桶的下标
                    int digitaOfElement = arr[j]/n % 10;
                    //放入对应的桶中
                    //bucketElementCounts[digitaOfElement] 即存放在一行(桶)中的哪个位置
                    bucket[digitaOfElement][bucketElementCounts[digitaOfElement]] = arr[j];
                    //对应桶元素下标后移一位,也相当于对应桶记录元素个数数组加1
                    bucketElementCounts[digitaOfElement]++;
    
                }
                //按照桶的顺序依次取出数据放入原来的数组
                int index = 0;
                for (int k = 0; k < bucketElementCounts.length; k++) {
                    //如果桶中有数据,才放入原数组中
                    if (bucketElementCounts[k] != 0){ //桶对应记录!=0,即记录的下标不为0,即该桶不为空
                        for (int l = 0; l < bucketElementCounts[k]; l++) {
                            //取出元素放入到原数组
                            arr[index++] = bucket[k][l];
                        }
                    }
                    //一轮处理后,需要将每个bucketElementCounts[k] = 0,即指向每个桶对应记录数组的下标都置会0,即初始
                    bucketElementCounts[k] = 0;
                }
            }
        }
    }
    

    七、桶排序

    八、希尔排序

    //希尔排序
    public class ShellSort {
        public static void main(String[] args){
            int[] arr = {8,9,1,7,4,2,3,5,4,6,0};
            System.out.println("原数组:"+ Arrays.toString(arr));
            shellSort2(arr);
            System.out.println("排序后:"+Arrays.toString(arr));
        }
    
        //希尔排序----交换法
        public static void shellSort(int[] arr){
            int temp;
            for (int gap = arr.length/2; gap > 0; gap /= 2) { // 分组,每组一半
                for (int i = gap; i < arr.length ; i++) { //从gap开始往前对应一个元素对比  这里是gap开始
                    for (int j = i-gap; j >= 0; j-=gap) { //这里是gap对应的元素
                        //如果当前元素大于加上步长后的那个元素,就要交换
                        if (arr[j] > arr[j+gap]){
                            temp = arr[j];
                            arr[j] = arr[j+gap];
                            arr[j+gap] = temp;
                        }
                    }
                }
            }
        }
    
        //希尔排序----移位法
        public static void shellSort2(int[] arr){
            int temp;
            for (int gap = arr.length/2; gap > 0; gap /= 2) { // 分组,每组一半
                // 从gap个元素,逐个对其所在的组进行直接插入排序
                for (int i = gap; i < arr.length ; i++) {
                    int j = i;
                    temp = arr[j]; //存放当前值
    //                if (arr[i] < arr[j-gap]){
                        while (j-gap >= 0 && arr[j-gap] > temp){
                            //移动
                            arr[j] = arr[j-gap];
                            j-=gap;
                        }
                        //当退出循环,说明找到插入位置
                        arr[j] = temp;
    //                }
                }
            }
        }
    }
    
  • 相关阅读:
    Python小白的数学建模 ---- 系列课程
    Maven学习笔记
    JavaScript 中的 Var,Let 和 Const 有什么区别
    (鸡汤文)搞懂了 JavaScript 定时器 setTimeout() 的 this 指向!
    setTimeout返回值的验证,(〒︿〒) 请原谅我一直以来对你的忽视
    终于把初中到大学的数学知识梳理完了(学习算法必备数学知识)
    最简单入门深度学习
    机器学习基本流程
    Vue.js源码解析-Vue初始化流程
    最大公约数&最小公倍数
  • 原文地址:https://www.cnblogs.com/xiaoaiying/p/14033694.html
Copyright © 2011-2022 走看看