【排序算法】八大排序算法的基本原理及其实现,带你掌握排序算法

排序Sort

排序算法比较

排序 稳定性 最坏 最好 平均
冒泡 n^2 n n^2
插入 n^2 n n^2
选择 × n^2 n^2 n^2
希尔 × n^2 n^1.5 n^1.3
快速 × n^2 n logn n logn
归并 n logn n logn n logn
× n logn n logn n logn
基数 d(n+r) d(n+r) d(n+r)

冒泡排序

重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成

实现:

 public static void bubbleSort(int[] arr) {
    
    
        //如果为空或者只有一个数据 则直接返回
        if (arr.length == 0 || arr.length == 1) {
    
    
            return;
        }
        //数组长度
        int length = arr.length;
        //用于中间的转换
        int temp = 0;
        //使用双重for循环 只用比较length-1次
        //外面的循环 记录比较的次数
        for (int i = 1; i < length; i++) {
    
    
            boolean flag = false;//如果其中一次没有交换 则证明直接就是有序的
            for (int j = 0; j < length - i; j++) {
    
    
                if (arr[j] > arr[j + 1]) {
    
    
                    flag = true;
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }

            if (!flag) {
    
    
                break;
            }
        }
    }

插入排序

简单来说,就是将要排序的元素,分为两部分,一部分为有序表,一部分为无序表,每次从无序表中取出一个元素插入到有序表中。
刚开始第一个元素我们认为他是有序的,把后面的元素逐个插入到前面的有序队列中

实现:

 public static void insertSort(int[] arr) {
    
    

        if (arr.length == 0 || arr.length == 1) {
    
    
            return;
        }

        //默认前面时有序的
        for (int i = 1; i < arr.length; i++) {
    
    

            int value = arr[i];//此处需要记录下来 因为可能会i出的元素会发生改变
            int index = i-1;//想给前一个位置插入

            while (index>=0 && arr[index]>value){
    
    //将大的往后移动
                arr[index+1] = arr[index];
                index--;
            }

            if (index+1!=i){
    
    //如果发生过交换
                arr[index+1] = value;
            }
        }
    }

选择排序

是一种简单直观的排序算法。它的工作原理是:第一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后再从剩余的未排序元素中寻找到最小(大)元素,然后放到已排序的序列的末尾。以此类推,直到全部待排序的数据元素的个数为零。选择排序是不稳定的排序方法

实现:

 /**
     * 选择排序
     * @param arr 要排序的数组
     */
    public static void  selectSort(int[] arr){
    
    

        if (arr.length==0||arr.length==1){
    
    
            return;
        }
        //得到数组的长度
        int length = arr.length;

        //外部for循环控制循环的次数
        for (int i =0;i<length;i++){
    
    
            int min = i; //最小的下标

            for (int j = i +1;j<length;j++){
    
    //得到后面最小的数的下标
                if (arr[j]<arr[min]){
    
    
                    min = j;
                }
            }
            //交换两个元素
            if (min!=i){
    
    
                int temp = arr[i];
                arr[i] =arr[min];
                arr[min] = temp;
            }
        }
    }

快速排序

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都小于或者等于另外一部分的所有数据,然后再按照此方法对这两部分数据分别进行快速排序,整个排序的过程可以递归进行,以此达到整个数据变成有序序列

代码实现:

 /**
     * 快速排序
     *
     * @param arr   要排序的数组
     * @param start 左边界
     * @param end   有边界
     */
    public static void quickSort(int[] arr, int start, int end) {
    
    
        if (arr.length == 0 || arr.length == 1) {
    
    
            return;
        }

        int l = start;
        int r = end;

        int base = arr[l];//这个数作为基准
        while (l < r) {
    
    

            while (arr[l]<base){
    
    //找到一个大于等于基准的值 将来替换到右边
                l++;
            }

            while (arr[r]>base){
    
    //找到一个小于等于基准的值 将来替换到左边
                r--;
            }

            if (l>=r){
    
    //如果l>=r 说明已经符合一次排序了
                break;
            }
            //否则进行交换
            int temp = arr[l];
            arr[l] = arr[r];
            arr[r]=temp;

            if (arr[l]==base){
    
    //此处时防止两个同时为基准值 则会一直死循环
                r--;
            }
        }

        if (l==r){
    
    
            l++;
            r--;
        }

        //对左右两边继续进行快速排序
        if (start<r){
    
    
            quickSort(arr, 0,r );
        }
        if (l<end){
    
    
            quickSort(arr, l, end);
        }


    }

希尔排序

希尔排序是记录按下标的一定增量分组,对分组使用直接插入排序)算法排序;随着增量分组逐渐减少,每组包含的关键词越来越多。当增量分组减至1时,整个文件恰被分为一组,算法便终止。

方法的实质其实时分组插入排序算法,就是对每个每组进行插入排序

 public static void shellSort(int[] arr) {
    
    
        if (arr.length!=0) {
    
    

            //用来存储临时变量
            int temp;
            //首先分为n/2组,即每2个为一组。则每组元素之间的间隔为n/2。用step来表示步长,即同组之间的间隔。
            for (int step = arr.length / 2; step > 0; step /= 2) {
    
    
                //分为了n/2组,则前n/2个元素都是不同组的元素,默认第一个元素都是有序的,从每组的第二个数进行插入排序。跟同组前面有序的进行比较
                //直到遍历到最后一个数
                for (int i = step; i < arr.length; i++) {
    
    
                    //每次跟前面同组的元素进行比较
                    for (int j = i - step; j >= 0; j -= step) {
    
    
                        if (arr[j] > arr[j + step]) {
    
    
                            temp = arr[j];
                            arr[j] = arr[j + step];
                            arr[j + step] = temp;
                        }
                    }
                }

            }
        }
    }


归并排序

归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略,将问题分成小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案修补在一起,即分而治之。

public class MergeSort {
    
    
    public static void mergeSort(int[] arr, int left, int right) {
    
    

        //数组的中轴
        int mid = (left + right) / 2;

        //如果分的数组的长度大于1
        if (left < right) {
    
    
            //向左递归排序
            mergeSort(arr, left, mid);
            //向右递归排序
            mergeSort(arr, mid + 1, right);

            //排序
            merge(arr, left, right); //合并 排序的过程
        }
    }

    public static void merge(int[] arr, int left, int right) {
    
    

        int[] temp = new int[arr.length]; //建立一个等长的数组用来存储有序的数组
        //中轴
        int mid = (left + right) / 2;

        int l = left;//左边序列的起时
        int r = mid + 1; //右边序列的起时
        int index = 0;

        //将有序的值存储到临时数组中 直到左边或者右边存储完
        while (l <= mid && r <= right) {
    
    
            if (arr[l] <= arr[r]) {
    
    
                temp[index] = arr[l];
                l++;
                index++;
            } else {
    
    
                temp[index] = arr[r];
                index++;
                r++;
            }
        }

        //将没存储玩的另一边存储到临时数组
        while (l <= mid) {
    
    
            temp[index] = arr[l];
            l++;
            index++;
        }
        while (r <= right) {
    
    
            temp[index] = arr[r];
            index++;
            r++;
        }

        
        index = 0;
        int tempLeft = left;
        //将有序数拷贝到原来的数组中 
        while (tempLeft <= right) {
    
    
            arr[tempLeft] = temp[index];
            index++;
            tempLeft++;
        }
//        System.out.println(Arrays.toString(arr));
    }


}

基数排序

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlogm),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法

 public static void radixSort(int[] arr) {
    
    
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
    
    
            if (arr[i] > max) {
    
    
                max = arr[i];
            }
        }
        //记录最大的位数。
        int maxLength = (max + "").length(); //记录位数
        //System.out.println(maxLength);
        //定义一个二维数组,长度为10,代表0-9,每个数组的长度为arr.length,
        int[][] bucket = new int[10][arr.length];
     
     
        //定义一个数组,用来存储每个数组实际存储数字的个数;
        int[] bucketSize = new int[10];



        //将数据装入数组中
        // i 代表的是位数 先比较个位 然后是十位 .....
        for (int i = 0,n=1; i < maxLength; i++,n*=10) {
    
    
            //对数组中的元素进行处理
            for (int value : arr) {
    
    
				//得到每位代表的数字
                int num = value / n % 10;
				//存入桶中
                bucket[num][bucketSize[num]] = value;

                bucketSize[num]++;
            }

            int index = 0;
			//重新放入数组中
            for (int k = 0; k < 10; k++) {
    
    
                if (bucketSize[k] != 0) {
    
    
                    for (int j = 0; j < bucketSize[k]; j++) {
    
    
                        arr[index] = bucket[k][j];
                        index++;
                    }

                    bucketSize[k] = 0;
                }
            }
        }
        //用来给arr中存排序的数据


    }

猜你喜欢

转载自blog.csdn.net/qq_45795744/article/details/125362975
今日推荐