排序算法:冒泡排序,选择排序,插入排序,希尔排序,快速排序,堆排序,归并排序,桶排序,计数排序,基数排序

一:冒泡排序

在这里插入图片描述

public class BubbleSort {

    //冒泡排序:从位置0到n-1,位置0循环和后面的元素比较,比位置0小的就交换,一次循环下来位置0是最小的。
    public int[] bubbleSortTwoMine(int[] nums){
        //  2 , 5 , 3 , 7      length=4
        //  0   1   2   3
        int len = nums.length;
        //小的放前面
        for (int i=0;i<len-1;i++){
            for (int j=i+1;j<len;j++){
                if (nums[j]<nums[i]){
                    int tem = nums[i];
                    nums[i] = nums[j];
                    nums[j] = tem;
                }
            }
        }
        return nums;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{2,5,3,7};
        BubbleSort b = new BubbleSort();
        int[] resultArr = b.bubbleSortTwoMine(arr);
        for (int i=0;i<resultArr.length;i++){
            System.out.println(resultArr[i]);
        }
    }
}

二:选择排序

在这里插入图片描述

public class SelectionSort {
    //选择排序:从位置0到n-1,位置0循环和后面的元素比较,比位置0小的先不交换,而是记录minIndex和minValue,一次循环下来再交换位置0和最小元素的下标minIndex。
    //相当于一次循环选择最小的元素下标
    public int[] selectSort(int[] arr) {
        // 2 5 3 7    length=4
        // 0 1 2 3
        int len = arr.length;
        for (int i=0;i<len-1;i++){
            int minIndex = i;
            int minValue = arr[i];
            for (int j=i+1;j<len;j++){
                if (arr[j]<minValue) {
                    minIndex = j;
                    minValue = arr[j];
                }
            }
            int tmp = arr[i];
            arr[i] = arr[minIndex];
            arr[minIndex] = tmp;
        }

        return arr;
    }

    public static void main(String[] args){
        SelectionSort s = new SelectionSort();
        int[] arr = new int[]{2,5,3,7,15,12,11,19,16};
        int[] resultArr = s.selectSort(arr);
        for (int i=0;i<resultArr.length;i++){
            System.out.println(resultArr[i]);
        }
    }
}

三:插入排序

在这里插入图片描述

public class InsertSort {
    //插入排序:从位置1开始,把1前面的当作排好序的,位置1及后面的为没有排序的,循环没有排序的,一个一个插入到排序好的里面。
    public int[] insertSort(int[] arr){
        // 2 5 3 7  length=4
        // 0 1 2 3
        //     i

        //下标i=1开始的是未排序的序列
        //下标i前的是排序好的序列
        int len = arr.length;
        for (int i=1;i<len;i++) {//2
            int j = i;
            while (j>0&&arr[j]<arr[j-1]){
                int tmp = arr[j];
                arr[j] = arr[j-1];
                arr[j-1] = tmp;
                j--;
            }
        }
        return arr;
    }

    public static void main(String[] args) {
        InsertSort in = new InsertSort();
        int[] arr = new int[]{2,5,1,7,15,16,8,3};
        int[] resultArr = in.insertSort(arr);
        for (int i=0;i<resultArr.length;i++){
            System.out.println(resultArr[i]);
        }
    }
}

四:希尔排序

在这里插入图片描述

//希尔排序:多个步长,每个步长分对应的子序列。每个步长中的子序列进行插入排序
public class ShellSort {

    public int[] shellSort(int[] arr){

        //3   1   5    7   2     length=5
        //0   1   2    3   4     5/2=2   2/2 =1  1/2=0
        //       gap
        //        j
        int len = arr.length;
        for (int gap=len/2;gap>0;gap=gap/2){//多个步长,每个步长分对应的子序列。每个步长中的子序列进行插入排序
            for (int i=gap;i<len;i++){
                int j = i;
                //此处循环条件不能是j>0,因为j是大于0了,但是j-gap可能不大于等于0,就会下标越界。即条件应为j-gap>=0
                while (j-gap>=0&&arr[j]<arr[j-gap]){
                    swap(arr,j,j-gap);
                    j= j-gap;
                }
            }
        }

        return arr;
    }

    public void swap(int[] arr,int m,int n){
        int tmp = arr[m];
        arr[m] = arr[n];
        arr[n] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{2,5,1,7,15,16,8,3,3};
        //int[] arr = new int[]{3,1,5,7,2};
        ShellSort sh = new ShellSort();
        int[] resultArr = sh.shellSort(arr);
        for (int i=0;i<resultArr.length;i++){
            System.out.println(resultArr[i]);
        }
    }
}

五:归并排序

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

//归并排序:排序当前数组,要先排序左半边子数组和右半边数组
//当left=right,两个子数组都只有一个必定有序,直接返回排序好的数组。
//当前方法中,将获取到两个排序的子数组,有序的放到一个当前需要返回的长度数组中,最后返回
public class MergeSort {

    public int[] mergeSort(int[] arr) {
        // left           right
        //  5    1    3    7    length=4
        //  0    1    2    3

        int[] returnArr = recursion(arr,0,arr.length-1);
        return returnArr;

    }


    public int[] recursion(int[] arr,int left,int right){

        int len = right-left+1;
        int[] resultArr = new int[len];
        if (left==right) {
            resultArr[0] = arr[left];
            return resultArr;
        }
        //这个是关键:当右边的子数组是两个元素时,如果用len/2+1,那位置就错乱了
        int mid =  (right-left)/2 + left+1;
        int[] leftArr = recursion(arr,left,mid-1);  //排好序的   1   5
        int[] rightArr = recursion(arr,mid,right);         //排好序的   3   7
        int l_len = leftArr.length;
        int r_len = rightArr.length;
        int m = 0;
        int n = 0;
        int k = 0;
        while (m<l_len || n<r_len){
            if (m>=l_len){
                while (n<r_len){
                    resultArr[k] = rightArr[n];
                    n++;
                    k++;
                }
            }else if(n>=r_len){
                while (m<l_len){
                    resultArr[k] = leftArr[m];
                    m++;
                    k++;
                }
            }else {
                resultArr[k] = leftArr[m]<rightArr[n] ? leftArr[m++] : rightArr[n++];
                k++;
            }
        }

        return resultArr;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{2, 5, 1, 7, 15, 16, 8, 3, 3};
        //int[] arr = new int[]{5,1,3,7};
        //Solution so = new Solution();
        //int[] resultArr = so.mergeSort(arr);
        MergeSort me = new MergeSort();
        int[] resultArr = me.mergeSort(arr);
        for (int i = 0; i < resultArr.length; i++) {
            System.out.println(resultArr[i]);
        }
    }
}

六:快速排序

在这里插入图片描述

//快排的两种思想交换、挖坑: https://blog.csdn.net/m0_62171658/article/details/124313424
public class QuickSort {
    //快速排序:以第一个元素作为基准,把数组分成两半,左边的都比基准元素小,右边的都比基准元素大。然后递归调这个分两半的函数
    public int[] quickSort(int[] arr) {
        //  2 5 3 1 7   length=5
        //  0 1 2 3 4
        //  l       r

        // 2 1  3  5 7
        //      lr
        // 1 2 3 5 7
        recursion(arr, 0, arr.length - 1);
        return arr;
    }

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

        if (left >= right) return;
        //基准是第一个元素,left位置的
        //l初始指向left边界:因为当数组是 2,1时,l如果初始指向left+1,下面的循环条件l不会++,总的循环结束之后要交换两个的位置
        int l = left + 1;
        int r = right;
        while (l <= r) {
            //从left开始一直找,直到找到比基准位置x的元素大的位置
            while (arr[l] < arr[left]) {
                l++;
                if (l > right) break;
            }
            //从right开始一直找,直到找到比基准位置x的元素小的位置
            while (arr[r] >= arr[left]) {
                r--;
                if (r < 0) break;
            }
            //交换l和r的位置
            if (l < r) swap(arr, l, r);
        }
        //循环结束:l>=r,此时l的位置的元素比位置left大,所以位置left要交换位置l-1的,就可以把整个数组以基准位置的值分左右两半,左:left->l-2  右:l->right
        swap(arr, l - 1, left);

        recursion(arr, left, l - 2);
        recursion(arr, l, right);
    }

    public void swap(int[] arr, int m, int n) {
        int tmp = arr[m];
        arr[m] = arr[n];
        arr[n] = tmp;

    }

    public static void main(String[] args) {
        int[] arr = new int[]{2, 1, 17, 31, 17, 17, 17};
        SolutionAscMine sm = new SolutionAscMine();
        int[] resultArr = sm.quickSort(arr);
        for (int i = 0; i < resultArr.length; i++) {
            System.out.println(resultArr[i]);
        }
    }
}

七:堆排序

得益于完全二叉树的结构,下标为index的节点,
它的父节点下标是 (index - 1) / 2,
左子节点下标是 2 * index + 1,
右子节点下标是 2 * index + 2

在这里插入图片描述

//堆排"完全二叉树中的位置”:https://blog.csdn.net/yldmkx/article/details/109669261
//堆排"完全二叉树中的位置”:节点下标m,父节点下标为 (m-1)/2  ; 父节点下标为m,左孩子下标为 2m+1 ,右孩子下标为2m+2
//堆排就是从树的最下层最右边节点的父节点开始,构建堆,构建时是递归的。循环下一个每个父节点构建堆
public class HeapSort {

    public int[] heapSort(int[] arr){
        //  3 5 7 4 2   length=5
        //  0 1 2 3 4

        //               3(0)
        //        5(1)         7(2)
        //  4(3)       2(4)
        int len = arr.length;
        int firstParent = (len-1-1)/2;
        for (int i=firstParent;i>=0;i--){
            recursion(i,arr,len);
        }

        for (int i=len-1;i>0;i--){
            swap(arr,0,i);
            recursion(0,arr,i);
        }

        return arr;
    }
    //len决定"完全二叉树最小层,最右边节点的位置"
    //adj是需要调整的父节点的下标
    //最大堆
    public void recursion(int adj,int[] arr,int len){
        if (adj*2+1>=len) return;
        int left = adj*2+1;
        int max = left;
        int right = adj*2+2;
        if (right<len && arr[right] > arr[left]){
            max = right;
        }
        if (arr[max]>arr[adj]) {
            swap(arr,max,adj);
            recursion(max,arr,len);
        }


    }

    public void swap(int[] arr, int m,int n){
        int tmp =  arr[m];
        arr[m] = arr[n];
        arr[n] = tmp;
    }


    public static void main(String[] args) {
        HeapSort heap = new HeapSort();
        //int[] arr = new int[]{3,5,7,4,2};
        int[] arr = new int[]{2, 1, 17, 31, 17, 17, 17};
        int[] resultArr = heap.heapSort(arr);
        for (int i=0;i<resultArr.length;i++){
            System.out.println(resultArr[i]);
        }
    }
}

八:计数排序

在这里插入图片描述

//计数排序:计算需要排序的数组中的最大值和最小值,新建一个可以存下这个范围内所有数值的数组,用来计数需要排序数组中的值出现的次数。
//循环计数数组,下标+min就是需要排序数组中的元素原原来的值,加入到返回数组中。
public class CountingSort {
    public int[] countingSort(int[] arr){
        // 3   1   5    length = 3
        // 0   1   2       min:1   max:5       新的数组的长度len=max-min+1;  len=5
        int min = arr[0];
        int max = arr[0];
        for (int i=0;i<arr.length;i++){
            int tmp = arr[i];
            min = tmp < min ? tmp :min;
            max = tmp >max ? tmp :max;
        }
        int len = max-min+1;
        int[] countArr = new int[len];//下标从0开始,即值为5下标就是5-min,所以对应下标的值就是:下标+min
        for (int j=0;j<arr.length;j++){ //循环所有的数组,根据值,放到countArr对应的下标中,重复的就+1
            int value = arr[j];
            int index = value-min;
            countArr[index] +=1;
        }
        int[] resultArr = new int[arr.length];
        int m = 0;
        for (int k=0;k<countArr.length;k++){//循环计数数组,根据下标计算值,计数数组中下标对应的值>1说明原数组中出现两次值,循环放入返回数组中
            while (countArr[k]>0){
                resultArr[m] = k+min;
                m++;
                countArr[k] -=1;
            }
        }
        return resultArr;
    }

    public static void main(String[] args) {
        int[] arr = new int[]{2, 5, 1, 7, 15, 16, 8, 3, 3};
        //int[] arr = new int[]{5,1,3,7};
        CountingSort co = new CountingSort();
        int[] resultArr = co.countingSort(arr);
        for (int i = 0; i < resultArr.length; i++) {
            System.out.println(resultArr[i]);
        }
    }
}

九:桶排序

在这里插入图片描述

//桶排序:根据需要排序的数组中的最大值和最小值除以桶数+1,决定这个桶存的哪个范围值的元素。
// 二维数组的第一个下标是具体的哪个桶,桶是一个一维数组,存在这个范围的元素,然后对这个桶进行插入排序。最后循环所有桶,循环桶里面的元素加到返回数组中。
//数组在方法中是值传递,传的相当于是副本,有点奇怪
public class BucketSort {

    public int[] bucketSort(int[] arr){
        //  5   1   3   7   9   12   15    length=7     minValue=1  maxValue = 15
        //  0   1   2   3   4   5   6
        //定义桶个数为5
        int bucket = 5;
        int[][] bucketArr = new int[bucket][0];//每次插入到具体的桶要扩容桶的大小
        //获取数组中的最大值和最小值
        int minValue = arr[0];
        int maxValue = arr[0];
        for (int i=0;i<arr.length;i++){
            minValue = arr[i]<minValue ? arr[i] : minValue;
            maxValue = arr[i]>maxValue ? arr[i] : maxValue;
        }
        //每个桶的值的范围: 1-3,4-6,7-9,10-12,13-15
        //                0   1   2    3     4
        int range = (maxValue-minValue)/bucket+1;  //3
        //可以根据数组元素值确定哪个桶: x-minValue /range

        for (int j=0;j<arr.length;j++){
            int ele = arr[j];
            int index = (ele-minValue)/ range;
            //数组在方法中是值传递,传的相当于是副本,有点奇怪。
            //加入到对应的桶中,并返回扩容后的数组
            bucketArr[index] = addBucket(bucketArr[index],ele);
        }
        int[] resultArr = new int[arr.length];
        int result_index = 0;
        //对每个桶进行插入排序
        for (int m=0;m<bucketArr.length;m++){
            int[] insertArr = bucketArr[m];
            // 1 3   length=2
            // 0 1
            //因为
            for (int n=1;n<insertArr.length;n++){
                int k=n;
                while (k>0&&insertArr[k]<insertArr[k-1]){
                    swap(insertArr,k,k-1);
                    k--;
                }
            }

            //对一个桶插入排序好后,将insertArr中的数据循环放入返回数组中
            for (int p=0;p<insertArr.length;p++){
                resultArr[result_index] = insertArr[p];
                result_index++;
            }
        }

        return resultArr;
    }

    //给桶中插入元素并扩容,并返回新的数组
    public int[] addBucket(int[] array,int value){
        int len = array.length;
        int[] tmpArr = new int[len+1];
        int k=0;
        for (int i=0;i<array.length;i++){
            tmpArr[k] = array[i];
            k++;
        }
        tmpArr[len]= value;
        //将扩容的数组赋值给array
        return tmpArr;
    }
    public void swap(int[] arr,int m,int n){

        int tmp = arr[m];
        arr[m] = arr[n];
        arr[n] = tmp;

    }

    public static void main(String[] args) {
        int[] arr = new int[]{5,1,3,7,9,12,15};
        //int[] arr = new int[]{5,1,3,7};
        BucketSort bu = new BucketSort();
        int[] resultArr = bu.bucketSort(arr);
        for (int i = 0; i < resultArr.length; i++) {
            System.out.println(resultArr[i]);
        }

        System.out.println("---------");

        int[] arr1 = new int[]{1,2,3};
        int[] arr2 = new int[]{4,5,6};
        arr1 = arr2;
        System.out.println(arr1);
        //二维数组第一个下标对应的是一个一维数组  :书里的一页
        //三维数组的第一个下标对应的是一个二维数组 :一本书
        //四维数组的第一个下标对应的是三维数组: 书架
        //五维数组的第一个下标对应的是四维数组: 图书馆
        int[][] twoArr = new int[][]{{1,2},{7,8}};
        twoArr[0] = arr2;
        System.out.println(twoArr);
    }
}

十:基数排序

在这里插入图片描述

//基数排序:计算需要排序的数组中最大的值,得到最大的位数 ,123最大位数是3。三层循环根据个、十、百排序
// 考虑到有负数,所以需要20个桶装不同位的基数的元素,循环个、十、百 。分别排序放到放到对应的基数桶中,然后循环桶,放到返回数组(即原数组)中。
// 个、十、百每层的桶要是新桶,切循环的数据是上一位拍排序好的数组。
//最后百位排序好的就是有序数组
public class RadixSort {
    //  5  11  3  123  1  length = 5
    //  0  1   2   3   4
    public int[] radixSort(int[] arr){

        int maxValue = arr[0];
        for(int i=0;i<arr.length;i++){
            maxValue = arr[i] > maxValue ? arr[i] : maxValue;
        }
        //计算最大值的位数 123  12  1 0
        int k = 0;   // 最大位数为3
        while (maxValue>0){
            k++;
            maxValue /=10;
        }
        //根据个、十、百位,放入长度为20的桶中,下标0-9为负数,10-19为整数
        //  -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1   2  3   4   5   6   7   8    9
        //   0  1  2  3  4  5  6  7  8 9 10  11

        int step = 9;
        int divisor = 1;
        for (int j=0;j<k;j++){
            int poi = 0;
            //桶,不同基数,桶要清空,要不然会有上一次桶中的数据
            int[][] bucketArr = new int[20][0];
            for (int m=0;m<arr.length;m++){
                int radix = (arr[m]/divisor)%10;//如果个位是1,则放入下标10的桶中
                int index = radix+step;
                //扩对应桶的长度,因为刚开始是0;
                bucketArr[index] = addBucket(bucketArr[index],arr[m]);
            }
            divisor *=10;

            for (int n=0;n<bucketArr.length;n++){
                int[] tmpArr = bucketArr[n];
                for (int y=0;y<tmpArr.length;y++){
                    arr[poi] = tmpArr[y];
                    poi++;
                }
            }


        }
        return arr;

    }

    public int[] addBucket(int[] arr,int value){
        int len = arr.length;
        int[] resultArr = new int[len+1];
        int k=0;
        for (int i=0;i<arr.length;i++){
            resultArr[k] = arr[i];
            k++;

        }
        resultArr[len] = value;
        return resultArr;

    }

    public static void main(String[] args) {
        //int[] arr = new int[]{5,1,3,7,9,12,15};
        int[] arr = new int[]{5,1,3,17,-1};
        RadixSort ra = new RadixSort();
        int[] resultArr = ra.radixSort(arr);
        for (int i = 0; i < resultArr.length; i++) {
            System.out.println(resultArr[i]);
        }

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值