排序算法之8种排序

排序算法

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

8种排序

内部排序:

  1. 插入排序:直接插入排序、希尔排序
  2. 选择排序:简单选择排序、堆排序
  3. 交换排序:冒泡排序、快速排序
  4. 归并排序
  5. 基数排序

外部排序:

冒泡排序

/**
 * 冒泡排序
 * @author qb
 * @version 1.0
 * @since 2022/2/23 13:55
 */
public class BubbleSort {

    public static void main(String[] args) {

        int[] array = {3,9,-1,10,-2};
        //临时变量
        int temp = 0;
        //冒泡排序时间复杂度为  O(n^2)
        for (int i = 0; i < array.length - 1; i++) {
            //第一趟排序,就是将最大的数排到后面
            for (int j = 0; j < array.length - 1 - i; j++) {
                //如果前面的数大于后面的数,则交换
                if (array[j] > array[j+1]) {
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            System.out.println("第"+(i+1)+"趟排序后的数组");
            System.out.println(Arrays.toString(array));

        }
        /*
        //第一趟排序,就是将最大的数排到后面
        for (int j = 0; j < array.length - 1; j++) {
            //如果前面的数大于后面的数,则交换
            if (array[j] > array[j+1]) {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第一趟排序后的数组");
        System.out.println(Arrays.toString(array));

        //第二趟排序
        for (int j = 0; j < array.length - 2; j++) {
            //如果前面的数大于后面的数,则交换
            if (array[j] > array[j+1]) {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第二趟排序后的数组");
        System.out.println(Arrays.toString(array));

        //第三趟排序
        for (int j = 0; j < array.length - 3; j++) {
            //如果前面的数大于后面的数,则交换
            if (array[j] > array[j+1]) {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第三趟排序后的数组");
        System.out.println(Arrays.toString(array));

        //第四趟排序
        for (int j = 0; j < array.length - 4; j++) {
            //如果前面的数大于后面的数,则交换
            if (array[j] > array[j+1]) {
                temp = array[j];
                array[j] = array[j+1];
                array[j+1] = temp;
            }
        }
        System.out.println("第四趟排序后的数组");
        System.out.println(Arrays.toString(array));*/
    }

}

冒泡排序优化

 public static void main(String[] args) {

        int array[] = {3,9,-1,10,20};
        //临时变量
        int temp = 0;
        //标识变量,是否进行过交换
        boolean flag = false;
        //冒泡排序时间复杂度为  O(n^2)
        for (int i = 0; i < array.length - 1; i++) {
            //第一趟排序,就是将最大的数排到后面
            for (int j = 0; j < array.length - 1 - i; j++) {
                //如果前面的数大于后面的数,则交换
                if (array[j] > array[j+1]) {
                    flag = true;
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
            System.out.println("第"+(i+1)+"趟排序后的数组");
            System.out.println(Arrays.toString(array));
            if(!flag){
                //在一趟排序中一次交换都没有发生
                break;
            }
            else{
                flag = false;
            }
        }
    }

选择排序

在这里插入图片描述

/**
 * 选择排序
 * @author qb
 * @version 1.0
 * @since 2022/2/23 14:52
 */
public class SelectSort {
    public static void main(String[] args) {
        int[] arr = {101,34,119,1};
        selectSort(arr);
    }

    public static void selectSort(int[] arr){
        for (int i = 0; i < arr.length - 1; i++) {
            int minIndex = i;
            int min = arr[i];
            for (int j = i; j < arr.length ; j++) {
                if(arr[j] < min){
                    minIndex = j;
                    min = arr[j];
                }
            }
            if(minIndex != i){
                arr[minIndex] = arr[i];
                arr[i] = min;
            }
            System.out.println("第"+(i+1)+"轮后~~~");
            System.out.println(Arrays.toString(arr));
        }

    }
}

插入排序

在这里插入图片描述
执行速度没有选择排序快,比冒泡速度快

/**
 * 插入排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/2/23 16:36
 */
public class InsertSort {

    public static void main(String[] args) {

        int[] arr = {101,34,119,1,-1,89};
        insertSort(arr);

    }

    public static void insertSort(int[] arr){

        for (int i = 1; i < arr.length; i++) {
            //定义待插入的数
            int insertVal = arr[i];
            //待插入数的前一个数的索引 1-1
            int insertIndex = i-1;
            //给insertVal 找到插入的位置
            //1. insertIndex >=0 保证给insertVal找插入位置时不越界
            //2. insertVal < arr[insertIndex] 待插入的数还没找到插入位置
            //3. 需要将arr[insertIndex] 后移
            while(insertIndex >=0 &&  insertVal < arr[insertIndex]){
                arr[insertIndex + 1] = arr[insertIndex];
                insertIndex--;
            }
            //退出循环说明插入的位置找到,insertIndex+1的位置
            if(insertIndex+1 != i){
                arr[insertIndex + 1] = insertVal;
            }
            System.out.println("第"+i+"轮后");
            System.out.println(Arrays.toString(arr));
        }

        /*//第一轮
        //定义待插入的数
        int insertVal = arr[1];
        //待插入数的前一个数的索引 1-1
        int insertIndex = 1-1;
        //给insertVal 找到插入的位置
        //1. insertIndex >=0 保证给insertVal找插入位置时不越界
        //2. insertVal < arr[insertIndex] 待插入的数还没找到插入位置
        //3. 需要将arr[insertIndex] 后移
        while(insertIndex >=0 &&  insertVal < arr[insertIndex]){
            arr[insertIndex + 1] = arr[insertIndex];
            insertIndex--;
        }
        //退出循环说明插入的位置找到,insertIndex+1的位置
        arr[insertIndex + 1] = insertVal;
        System.out.println("第一轮后");
        System.out.println(Arrays.toString(arr));

        //第二轮
        //定义待插入的数
        insertVal = arr[2];
        //待插入数的前一个数的索引 1-1
        insertIndex = 2-1;
        //给insertVal 找到插入的位置
        //1. insertIndex >=0 保证给insertVal找插入位置时不越界
        //2. insertVal < arr[insertIndex] 待插入的数还没找到插入位置
        //3. 需要将arr[insertIndex] 后移
        while(insertIndex >=0 &&  insertVal < arr[insertIndex]){
            arr[insertIndex + 1] = arr[insertIndex];
            insertIndex--;
        }
        //退出循环说明插入的位置找到,insertIndex+1的位置
        arr[insertIndex + 1] = insertVal;
        System.out.println("第二轮后");
        System.out.println(Arrays.toString(arr));

        //第三轮
        //定义待插入的数
        insertVal = arr[3];
        //待插入数的前一个数的索引 1-1
        insertIndex = 3-1;
        //给insertVal 找到插入的位置
        //1. insertIndex >=0 保证给insertVal找插入位置时不越界
        //2. insertVal < arr[insertIndex] 待插入的数还没找到插入位置
        //3. 需要将arr[insertIndex] 后移
        while(insertIndex >=0 &&  insertVal < arr[insertIndex]){
            arr[insertIndex + 1] = arr[insertIndex];
            insertIndex--;
        }
        //退出循环说明插入的位置找到,insertIndex+1的位置
        arr[insertIndex + 1] = insertVal;
        System.out.println("第三轮后");
        System.out.println(Arrays.toString(arr));*/
    }


}

希尔排序

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

交换法 时间复杂度是O(n^3)

/**
 * 希尔排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/2/24 8:44
 */
public class ShellSort {

    public static void main(String[] args) {

        int[] arr = {8,9,1,7,2,3,5,4,6,0};
        shellSort(arr);
    }

    public static void shellSort(int[] arr) {
        int temp = 0;
        int count = 0;
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                //遍历各组中所有的元素(共gap组,每组有2个元素),步长gap
                for (int j = i-gap;j>=0;j -= gap){
                    System.out.println(gap + "---" + i +"----"+ j);
                    //如果当前元素大于加上步长后的哪个元素说明交换
                    if(arr[j] > arr[j+gap]){
                        temp = arr[j];
                        arr[j] = arr[j+gap];
                        arr[j+gap] = temp;
                    }
                }
            }
            System.out.println("希尔排序第"+(++count)+"轮: "+Arrays.toString(arr));
        }


        //希尔排序的第一轮
        //因为第一轮排序,是将10个数据分成了5组
       /* for (int i = 5; i < arr.length; i++) {
            //遍历各组中所有的元素(共5组,每组有2个元素),步长5
            for (int j = i-5;j>=0;j -= 5){
                //如果当前元素大于加上步长后的哪个元素说明交换
                if(arr[j] > arr[j+5]){
                    temp = arr[j];
                    arr[j] = arr[j+5];
                    arr[j+5] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

        //第二轮
        for (int i = 2; i < arr.length; i++) {
            //遍历各组中所有的元素(共5组,每组有2个元素),步长5
            for (int j = i-2;j>=0;j -= 2){
                //如果当前元素大于加上步长后的哪个元素说明交换
                if(arr[j] > arr[j+2]){
                    temp = arr[j];
                    arr[j] = arr[j+2];
                    arr[j+2] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

        //第二轮
        for (int i = 1; i < arr.length; i++) {
            //遍历各组中所有的元素(共5组,每组有2个元素),步长5
            for (int j = i-1;j>=0;j -= 1){
                //如果当前元素大于加上步长后的哪个元素说明交换
                if(arr[j] > arr[j+1]){
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));*/
    }

}

位移式 速度快 8万 1s

 /**
     * 交换法
     * @param arr 数组
     */
    public static void shellSort2(int[] arr) {
        int count = 0;
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                //保存当前的下标
                int j = i;
                //储存需要比较的值(需要位移的值)
                int temp = arr[j];
                //向前查找 与 当前当前的i进行比较
                if(arr[j] < arr[j-gap]){
                    //前面的大,就向后移,移到i的位置
                    while (j - gap >= 0 && temp < arr[j-gap]){
                        //移动
                        arr[j] = arr[j-gap];
                        j -= gap;
                    }
                    //退出循环后,就找到了插入的位置
                    arr[j] = temp;
                }
            }
            System.out.println("希尔排序第"+(++count)+"轮: "+Arrays.toString(arr));
        }

    }

快速排序

在这里插入图片描述



/**
 * 快速排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/2/24 10:11
 */
public class QuickSort {

    public static void main(String[] args) {

        int[] arr = {-9,78,0,23,-567,70};
        quickSort(arr,0,arr.length-1);
        System.out.println(Arrays.toString(arr));
    }

    public static void quickSort(int[] arr,int left,int right){
        int l = left;
        int r = right;
        //中轴
        int pivot = arr[(l + r) /2];
        //临时变量
        int temp = 0;
        //只要左边的索引还小于右边的索引就一直循环
        while (l < r){
            //左边的索引大于中间值就退出
            while (arr[l] < pivot){
                l += 1;
            }
            while (arr[r] > pivot){
                r -=1;
            }
            //如果 l >= r 说明pivot 的左右两边,已经安全左边全部是小于等于pivot值
            //右边就是大于等于pivot
            if(l >= r){
                break;
            }
            //交换
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            //如果交换完后,发现arr[l] = pivot,r往前再走一步(l--)
            if(arr[l] == pivot){
                r -= 1;
            }
            if(arr[r] == pivot){
                l += 1;
            }
        }
        if(l == r){
            l+= 1;
            r -=1;
        }
        //向左递归
        if(left < r){
            quickSort(arr,left,r);
        }
        if(right > l){
            quickSort(arr,l,right);
        }
    }

}

归并排序

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

时间复杂度 线性对数阶 n-1

/**
 * 归并排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/2/24 11:54
 */
public class MergeSort {

    public static void main(String[] args) {
        int[] arr = {8,4,5,7,1,3,6,2};
        int[] temp = new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后的结果:"+ Arrays.toString(arr));
    }


    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){
        //初始化i 左边有序队列的初始索引
        int i = left;
        //初始化j 右边有序队列的初始索引
        int j = mid+1;
        //指向temp数组的当前索引
        int t = 0;
        //1.先把左右两边(有序)的数据,按照规则填充到temp数组,直到左右两边的有序序列又一遍处理完毕
        while(i <= mid && j<= right){
            // 如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素,
            // 即将左边的当前元素,拷贝到temp数组
            //t后移,i后移
            if(arr[i] <= arr[j]){
                temp[t] = arr[i];
                t +=1;
                i +=1;
            }
            else{
                //反之,将右边的当前元素移到temp数组
                temp[t] = arr[j];
                t +=1;
                j +=1;
            }
        }
        //2.把剩余数据的一边的数据一次全部填充到temp
        while(i <= mid){
            //说明左边的有序序列还有剩余的,就全部填充到temp
            temp[t] = arr[i];
            t+=1;
            i+=1;
        }
        while(j <= right){
            //说明右边的有序序列还有剩余的,就全部填充到temp
            temp[t] = arr[j];
            t+=1;
            j+=1;
        }
        //3.将temp数组的元素拷贝到arr
        //注意,并不是每次都拷贝所有
        t = 0;
        int tempLeft = left;
        while(tempLeft <= right){
            arr[tempLeft] = temp[t];
            t +=1;
            tempLeft +=1;
        }

    }

}

基数排序

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


/**
 * 基数排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/2/24 14:28
 */
public class RadixSort {

    public static void main(String[] args) {
        int[] arr = {53,3,542,748,14,214};
        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];
            }
        }
        //得到的最大数是几位数
        int maxLength = (max + "").length();
        int[][] bucket = new int[10][arr.length];
        int[] bucketElementCounts = new int[10];

        for (int i = 0,n=1; i < maxLength; i++,n *= 10) {
            //针对每个元素的对应位进行排序处理,
            for (int j = 0; j < arr.length; j++) {
                //取出每个元素的位
                int digitOfElement = arr[j] / n % 10;
                //放入对应的捅中
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
                bucketElementCounts[digitOfElement] ++;
            }
            //按照这个捅的顺序(一维数组的下标一次取出数据,放入原来的数组)
            int index = 0;
            //遍历每一个捅,并将捅中的数据放入到元素中
            for (int k = 0; k < bucketElementCounts.length; k++) {
                //如果捅中有数据,我们才放入到原数组
                if(bucketElementCounts[k] != 0){
                    //循环该捅,即第k个一维数组
                    for (int l = 0; l < bucketElementCounts[k]; l++) {
                        //取出元素放入到arr
                        arr[index] = bucket[k][l];
                        index ++;
                    }
                }
                //第一轮处理后将 bucketElementCounts[k] 清0;
                bucketElementCounts[k] = 0;

            }
            System.out.println("第"+(i+1)+"轮处理结果: "+Arrays.toString(arr));
        }

        /*//第一轮
        //定义一个二位数组 表示10个捅,每一个捅就是一个一维数组
        //1.二维数组包含10个一维数组
        //2.为了防止在放入的时候,数据溢出,则每一个数组(捅),大小定为arr.length
        //3.很明确 基数排序是空间换时间的经典算法
        int[][] bucket = new int[10][arr.length];

        //为了记录每个捅中实际存放了多少数据,定义一个一维数组来记录各个捅每次放入的数据个数
        int[] bucketElementCounts = new int[10];
        //第一轮根据个位进行排序
        for (int j = 0; j < arr.length; j++) {
            //取出每个元素的个位
            int digitOfElement = arr[j] % 10;
            //放入对应的捅中
            bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
            bucketElementCounts[digitOfElement] ++;
        }
        //按照这个捅的顺序(一维数组的下标一次取出数据,放入原来的数组)
        int index = 0;
        //遍历每一个捅,并将捅中的数据放入到元素中
        for (int k = 0; k < bucketElementCounts.length; k++) {
            //如果捅中有数据,我们才放入到原数组
            if(bucketElementCounts[k] != 0){
                //循环该捅,即第k个一维数组
                for (int l = 0; l < bucketElementCounts[k]; l++) {
                    //取出元素放入到arr
                    arr[index] = bucket[k][l];
                    index ++;
                }
            }
            //第一轮处理后将 bucketElementCounts[k] 清0;
            bucketElementCounts[k] = 0;

        }

        //第二轮
        for (int j = 0; j < arr.length; j++) {
            //取出每个元素的十位
            int digitOfElement = arr[j] / 10 % 10;
            //放入对应的捅中
            bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
            bucketElementCounts[digitOfElement] ++;
        }
        //按照这个捅的顺序(一维数组的下标一次取出数据,放入原来的数组)
         index = 0;
        //遍历每一个捅,并将捅中的数据放入到元素中
        for (int k = 0; k < bucketElementCounts.length; k++) {
            //如果捅中有数据,我们才放入到原数组
            if(bucketElementCounts[k] != 0){
                //循环该捅,即第k个一维数组
                for (int l = 0; l < bucketElementCounts[k]; l++) {
                    //取出元素放入到arr
                    arr[index] = bucket[k][l];
                    index ++;
                }
            }
            //第一轮处理后将 bucketElementCounts[k] 清0;
            bucketElementCounts[k] = 0;
        }

        //第三轮
        for (int j = 0; j < arr.length; j++) {
            //取出每个元素的百位
            int digitOfElement = arr[j] / 100 % 10;
            //放入对应的捅中
            bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
            bucketElementCounts[digitOfElement] ++;
        }
        //按照这个捅的顺序(一维数组的下标一次取出数据,放入原来的数组)
        index = 0;
        //遍历每一个捅,并将捅中的数据放入到元素中
        for (int k = 0; k < bucketElementCounts.length; k++) {
            //如果捅中有数据,我们才放入到原数组
            if(bucketElementCounts[k] != 0){
                //循环该捅,即第k个一维数组
                for (int l = 0; l < bucketElementCounts[k]; l++) {
                    //取出元素放入到arr
                    arr[index] = bucket[k][l];
                    index ++;
                }
            }
        }*/

    }

}

堆排序

时间复杂度 n的对数阶在这里插入图片描述
在这里插入图片描述

/**
 * 堆排序
 *
 * @author qb
 * @version 1.0
 * @since 2022/3/2 16:41
 */
public class HeapSort {

    public static void main(String[] args) {
        //数组升序排列
        int[] arr = {4,6,8,5,9,0,10,3};
        heapSort(arr);

    }

    public static void heapSort(int[] arr){
        System.out.println("堆排序");
        int temp = 0;
       /* //分步完成
        adjustHeap(arr,1,arr.length);
        //4,9,8,5,6
        System.out.println("第一次调整:"+ Arrays.toString(arr));

        adjustHeap(arr,0,arr.length);
        //9,6,8,5,4
        System.out.println("第二次调整:"+Arrays.toString(arr));*/
        //1.将无序序列构建成一个堆,根据升序将去需求选择大顶堆或小丁堆
        for (int i =arr.length / 2 -1; i >=0; i--) {
            adjustHeap(arr,i,arr.length);
        }
        //2.将堆定元素与末尾元素交换,将最大的元素 沉到数组末端
        //3.重新调整机构,使其满足堆定义,然后继续交换顶元素与当前末尾元素,反复执行调整 + 交换步骤,
        // 直到整个序列有序
        for (int j = arr.length-1; j > 0; j--) {
            //交换
            temp = arr[j];
            arr[j] = arr[0];
            arr[0] = temp;
            adjustHeap(arr,0,j);
        }
        System.out.println(Arrays.toString(arr));

    }

    /**
     *  将一个数组(二叉树),调整成一个大顶堆
     *  完成将以 i对应的非叶子结点的数调整成大顶堆
     * @param arr 待调整的数组
     * @param i 表示非叶子结点在数组中的索引
     * @param length 表示对多少个元素进行调整
     */
    public static void adjustHeap(int[] arr,int i,int length){
        //先取出当前元素的值
        int temp = arr[i];
        //开始调整
        //k指向 i是左子节点
        for (int k = i * 2+1;k<length;k = k*2+1){
            //说明左子节点的值小于右子节点的值
            if((k+1) < length && arr[k] < arr[k+1]){
                k++;
            }
            //子节点大于父节点
            if(arr[k] > temp){
                //把较大的值赋给当前节点
                arr[i] = arr[k];
                // !!! i 指向k,继续循环比较
                i=k;
            }
            else{
                break;
            }
        }
        //当for循环结束后,我们已经将以i为父节点的最大值放在了 最顶上
        //将temp值放在调整后的位置
        arr[i] = temp;


    }


}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值