排序算法总结(冒泡排序、简单选择排序、直接插入排序、希尔shell排序、快速排序、归并排序、基数排序)

四、排序(Sort Algorithm)

1、概念

排序的概念:排序是将一组数据按照指定的顺序进行排列的过程。

排序可以分为内部排序和外部排序,内部排序是将处理的所有数据都加载到内部存储器中进行排序。

若数据量过大,无法全部加载到内存中,需要借助于外部存储进行排序。

1.1、内部排序

  • 插入排序

直接插入排序、希尔排序

  • 选择排序

简单选择排序、堆排序

  • 交换排序

冒泡排序、快速排序

  • 归并排序
  • 基数排序

1.2外部排序

2、排序算法

2.1冒泡排序

概念:冒泡排序是一种交换排序,它的基本思想是:按照某种排序规则,两两比较相邻的元素的关键字,如果是反序则交换,直到没有反序的记录为止。

  • 普通的冒泡算法

    for (int i = 0; i < arr.length - 1; i++) {
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    if (arr[j] > arr[j + 1]) {
                        swap(arr, j, j + 1);
                    }
                }
                System.out.println(Arrays.toString(arr));
            }
    
  • 优化排序算法

    存在这样一种情况,没有数据交换时,即说明此序列已经有序了,即不再需要判断后面的数据了,我们需要优化代码,即当序列已经有序时,不再对后面的数据进行判断。

     boolean flag = true;
            for (int i = 0; i < arr.length - 1&&flag; i++) {
                flag=false;
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    if (arr[j] > arr[j + 1]) {
                        swap(arr, j, j + 1);
                        flag = true;
                    }
                }
                System.out.println(Arrays.toString(arr));
            }
    

2.2简单选择排序

概念:即通过n-i次关键字间的比较,从n-i+1(包括自己)个记录中选出关键字最小的记录,并和第i个记录交换。

for (int i = 0; i < arr.length - 1; i++) {
            int minSize = i;
            int min = arr[minSize];
            for (int j = i + 1; j <= arr.length - 1; j++) {
                if(min>arr[j]){
                    minSize=j;
                    min=arr[j];
                }
            }
            if(i!=minSize){
                arr[minSize]=arr[i];
                arr[i]=min;

            }
        }

2.3直接插入排序

概念:把n个待排序的元素成一个有序列表和一个无序表,开始时有序表只包含一个元素,无序表中包含n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表。

int insertScrpt=0;//要插入的位置
        int insertValue=0;//插入的值
        for(int i=1;i<=arr.length-1;i++){
            insertScrpt=i-1;
            insertValue=arr[i];
            while (insertScrpt>=0&&insertValue<arr[insertScrpt]){
                arr[insertScrpt+1]=arr[insertScrpt];//向后移
                insertScrpt--;
            }
            if(insertScrpt+1!=i){
                arr[insertScrpt+1]=insertValue;
            }
        }

2.4希尔排序

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

  • 交换法(时间复杂度为17s左右)

    int temp = 0;
            for (int increment = arr.length / 2; increment > 0; increment = increment / 2) {
                for (int i = increment; i < arr.length; i++) {
                    for (int j = i - increment; j >= 0; j -= increment) {
                        if (arr[j] > arr[j + increment]) {
                            temp = arr[j];
                            arr[j] = arr[j + increment];
                            arr[j + increment] = temp;
                        }
                    }
                }
                System.out.println(Arrays.toString(arr));
            }
    
  • 移位法(时间复杂度为1s左右)

    for (int increment = arr.length / 2; increment > 0; increment = increment / 2) {
    
                for (int i = increment; i < arr.length; i++) {
                    int j = i;
                    int temp = arr[j];
                    if (arr[j] < arr[j - increment]) {
                        while (j - increment >= 0 && temp < arr[j - increment]) {
                            arr[j] = arr[j - increment];
                            j -= increment;
                        }
                        arr[j] = temp;
                    }
                }
                System.out.println(Arrays.toString(arr));
            }
    

2.5快速排序

思想:快速排序是对冒泡排序的一种改进,通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有的数据比另一部分的所有数据都要小,然后按此方法对这个两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

public static void quickSort(int[] arr,int left,int right){
        int l=left;
        int r=right;
        int temp=0;
        int privot=arr[(right+left)/2];
       while (l<r){
           while (arr[l]<privot){
                l++;
           }
           while (arr[r]>privot){
               r--;
           }
           if(l>=r){
               break;
           }
           temp=arr[l];
           arr[l]=arr[r];
           arr[r]=temp;

           if(arr[l]==privot){
               r--;
           }
           if(arr[r]==privot){
               l++;
           }
       }
       if(l==r){
           l+=1;
           r-=1;
       }
       //左递归
        if (left<r){
            quickSort(arr,left,r);

        }
        //向右递归
        if(right>l){
            quickSort(arr,l,right);
        }
    }

2.6归并排序(MergeSort)

归并排序是利用归并的思想进行排序的方法,采用经典的分治策略(分治是将问题分解成一些小问题然后递归求解,然后就将各个阶段的答案修补在一起)

网上找的图解
在这里插入图片描述
这种结构很想一个完全二叉树,我们采用递归的方法去实现,也可以采用迭代方法去实现,分阶段可以理解为递归拆分子序列的过程。

  • 序列的拆分

        public static void mergeSort(int[] arr, int left, int right, int[] temp) {
            if (left < right) {
                int mid = (left + right) / 2;
                //向左递归分解
                mergeSort(arr, left, mid, temp);
                //向右递归分解
                mergeSort(arr, mid + 1, right, temp);
                //合并
                 merge(arr, left, mid, right, temp);
            }
        }
    
  • 序列的合并

    /**
         * 合并
         *
         * @param arr   原始数组,待排序的数组
         * @param left  数组的左边坐标
         * @param mid   数组的中间坐标
         * @param right 数组的右边坐标
         * @param temp  临时数组
         */
        public static void merge(int[] arr, int left, int mid, int right, int temp[]) {
            int i = left;//初始化i,左边序列的初始索引
            int j = mid + 1;//初始化j,右边序列的初始索引
            int t = 0; //临时变量的索引
            //1、将拆开的左右数组中的元素分别比较大小,并放入临时数组,直至某一数组被放完
            while (i <= mid && j <= right) {
                if (arr[i] < arr[j]) {
                    temp[t] = arr[i];
                    i++;
                    t++;
                } else {
                    temp[t] = arr[j];
                    j++;
                    t++;
                }
            }
    
            //2、将剩下数组的元素全部移动到临时数组中
            while (i <= mid) {
                temp[t] = arr[i];
                i++;
                t++;
            }
            while (j <= right) {
                temp[t] = arr[j];
                j++;
                t++;
            }
            //3 将临时数组的元素合更新到原数组
            t = 0;
            int tempLeft = left;
            while (tempLeft <= right) {
                arr[tempLeft] = temp[t];
                t++;
                tempLeft++;
            }
    
        }
    

2.7基数排序(桶排序的扩展)

算法描述:基数排序就是分离出数字的每一位,根据每一位的大小放入指定的桶中,桶用数组来表示,共分成编号为0-9的桶。如249,分离个位时,249放入编号为9的桶中,分离十位时,246放入编号为4的桶中,分离千位时,249放入编号为0的桶中。存在负数的序列不能使用基数排序。

基本思想:将所有待比较数值统一为同样的数位长度,数位较短的数前面补零,然后,从最低位开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

 public static void radisSort(int[] arr){
        //找出最大数并确定位数
        int max=arr[0];
        for(int i=1;i<arr.length;i++){
            if(max<arr[i]){
                max=arr[i];
            }
        }
        int maxLength=(max+"").length();
        //定义桶,为了防止元素溢出,需要将每个桶的容量都定义为:arr.length
        int[][] bucket=new int[10][arr.length];
        //定义一个数组bucketElementCount[],用来记录每个桶中放入的元素的数量
        int[] bucketElementCount=new int[10];
        /**
         * 将数据元素放入桶中
         */
        for(int l=0,n=1;l<maxLength;n=n*10,l++){
            for(int i=0;i<arr.length;i++){
                int endDigital=arr[i]/n%10;
                bucket[endDigital][bucketElementCount[endDigital]]=arr[i];
                bucketElementCount[endDigital]++;
            }
            /**
             * 取出元素
             */
            int index=0;
            for(int i=0;i<bucket.length;i++){
                if(bucketElementCount[i]!=0){
                    for(int j=0;j<bucketElementCount[i];j++){
                        arr[index]=bucket[i][j];
                        index++;
                    }
                }
            //将bucketElemnetCount清零
                bucketElementCount[i]=0;
            }
            System.out.println(Arrays.toString(arr));
        }

    }

2.8排序算法总结

在这里插入图片描述

发布了71 篇原创文章 · 获赞 42 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/dreame_life/article/details/104131645