算法基础部分-排序总结


public class Sort {
    //    冒泡排序 稳定的排序 每次内层循环将最小值推到左边,终点往右移
    public static void maopao(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            boolean b = false;
//            从最后一个数开始比较内层循环一次就会找到最小值然后放在最左边
            for (int j = arr.length - 1; j > i; j--) {
                if (arr[j] < arr[j - 1]) {
                    swap(arr, j, j - 1);
                    b = true;
                }
            }
            if (!b) break;
        }
    }

    //    选择排序 每次内层循环找到最小值的索引然后跟i交换
    public static void xuanze(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int min = i;
//            内层循环每次找到最小值的索引然后跟外层循环的i进行交换
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) {
                    min = j;
                }
            }
            swap(arr, i, min);
        }
    }

    //    归并找最大值 递归到只有一个数然后结果不断返回比较得到整个的最大
    public static int prosecc(int[] arr, int L, int R) {
        if (L == R) {
            return arr[L];
        }
        int mid = L + ((R - L) >> 1);
        int leftmax = prosecc(arr, L, mid);
        int rigtmax = prosecc(arr, mid + 1, R);
        return Math.max(leftmax, rigtmax);
    }

    //    插入排序
    /*
     *  1325476
     * 1
     * 13
     * 123
     * 1235
     * 12345
     * 123457
     * 1234567
     * */
    public static void charu(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
//            内层循环从i开始每次内层循环保证左边的都是排序好了的
            for (int j = i + 1; j >= 1; j--) {
                if (arr[j] < arr[j - 1]) {
                    swap(arr, j, j - 1);
                } else if (arr[j] > arr[j - 1]) {
                    break;
                }
            }
        }
    }

    //    堆排序
    /*
     * 157324
     * 51
     * 715
     * 7351
     *
     * */
    public static void dui(int[] arr) {
        //首先将数组变成大根堆
        heapInsert(arr);
        int size = arr.length;
//        size-1>0  size>1
        while (size > 1) {
//            使得最大根在最后面
            swap(arr, 0, size - 1);
//            弹出最大数
            size--;
//            对剩下的数组再次进行大根堆
            heapfily(arr, 0, size);
        }
    }

    //    一进来就进行的大根堆(循环向上)定义孩子节点求父节点
    public static void heapInsert(int[] arr) {
//        定义孩子节点
        int index = 0;
//        定义父节点
        int father = 0;
//        循环
        for (int i = 0; i < arr.length; i++) {
//            从第一个索引开始
            index = i;
//            计算父节点的位置
            father = (index - 1) / 2;
            //当叶子节点大于父节点时候
            while (index > father) {
                //如果叶子节点的值大于父节点的值则交换 然后将父节点变成叶子节点
                if (arr[index] > arr[father]) {
                    swap(arr, index, father);
                    index = father;
                    father = (index - 1) / 2;
//                    如果父节点大于了孩子节点则退出循环
                } else if (arr[index] < arr[father]) {
                    break;
                }

            }
        }
    }

    //    向下求大根堆 定义父节点求左孩子节点
    public static void heapfily(int[] arr, int index, int heapsize) {
        //计算左孩子的索引
        int left = index * 2 + 1;
//        设置一个较大值的变量
        int lagerindex = 0;
//        当没有孩子了则退出循环
//        当左孩子的索引超过了heapsize则退出
        while (left < heapsize) {
//            首先比较左孩子和右孩子谁大 ,然后把索引赋值给lagerindex
            lagerindex = left + 1 < heapsize && arr[left] < arr[left + 1] ? left + 1 : left;
//            然后比较最大孩子和父节点的值,如果父节点比最大孩子大则说明现在就是大根堆则退出循环
            if (arr[lagerindex] < arr[index]) {
                break;
            }
//            否者将最大孩子的值与父节点的值进行互换
            swap(arr, lagerindex, index);
//            然后把原最大孩子的索引变成父节点
            index = lagerindex;
//            重新计算左孩子
            left = index * 2 + 1;

        }
    }

    //桶排序
    public static void radixSort(int[] arr, int L, int R, int weishu) {
        final int raidx = 10;//桶是0-9 的所以固定长度为10
        int i = 0, j = 0; //定义i和j
        int[] buket = new int[R - L + 1];//定义一个与arr L到R 等长度的数组
        for (int d = 1; d <= weishu; d++) { //位数就是arr中的数最大有几位数  有几位 就得进出桶几次 d =1表示个位,d=2表示十位...
            //首先定义一个count数组
            int[] count = new int[raidx];
            //进桶操作
            for (i = 0; i < arr.length; i++) {
                j = getnum(arr[i], d); //j= arr[i]的d位上的数
//                把d位数为j的个数 存到count[j] 中
                count[j]++;
            }
            //累加操作
            for (i = 1; i < count.length; i++) {
                //count[i] 就表示0~s中从右到左第d位小于s的数的汇总
                count[i] = count[i] + count[i - 1];
            }
            //出桶操作
            for (i = R; i >= L; i--) {
                j = getnum(arr[i], d);
//                词频-1的位置
                buket[count[j] - 1] = arr[i];
//                词频-1
                count[j]--;
            }
            //赋值操作
            for (i = L, j = 0; j < buket.length; j++, i++) {
                arr[i] = buket[j];
            }
        }

    }

    //计算i的从右往左第d位是多少
    public static int getnum(int i, int d) {
        //Math.pow(10,d-1) 的意思就是 10 的d-1次方
        // 例如i = 22  d = 1 则 22/10的0次方 = 22  然后再对10取余  = 2 所以 22的从右到左第一位上面的数是2
        return (i / ((int) Math.pow(10, d - 1))) % 10;
    }


    //    快排
    public static void kuaipai(int[] arr) {
        kuaip(arr, 0, arr.length - 1);
    }

    public static void kuaip(int[] arr, int L, int R) {
//        左边不小于右边了就返回
        if (!(L < R)) {
            return;
        }
        //第一步首先在R-L 中随机一个索引 这个步骤就使得快排时间复杂度从O(n2) 变成了O(N*logN);
        int rom = L + (int) (Math.random() * (R - L + 1));
        //将这个索引的值与最后一索引交换
        swap(arr, rom, R);
        //进行partation 对目前的大于最后一个数的弄到右边,小于最后一个数的弄到左边 最后把相等的第一个位置和最后一个位置返回成一个数组
        int[] partation = partation(arr, L, R);
//        根据区间然后对区间的左边和右边进行相同的操作
        kuaip(arr, L, partation[0] - 1);
        kuaip(arr, partation[1] + 1, R);
    }

    public static int[] partation(int[] arr, int L, int R) {
//        定义两个变量 less是<边界的起点 一开始小于边界的起点是没有的所以在L-1位置
        int less = L - 1;
        int more = R;
//        当L不小于>边界了就退出 L是指针
        while (L < more) {
//            从左往右开始与最后的位置进行比较
            if (arr[L] < arr[R]) {
//                如果小于的话则<边界扩大
                less++;
//                然后将L和less进行交换
                swap(arr, less, L);
//                然后指针向右移动一格
                L++;
//                否则的话 >边界向左扩建
            } else if (arr[L] > arr[R]) {
                more--;
//                然后交换指针指向的位置和more的位置
                swap(arr, L, more);
//            如果指针和最后的数相等则指针向右移动
            } else {
                L++;
            }
        }
//        交换>边界的最前面的数与最后的数进行交换
        swap(arr, more, R);
//        然后将<边界的后一个位置和>边界的边缘作为一个区间数组返回
        return new int[]{less + 1, more};
    }

    //    归并排序
    public static void guibingp(int[] arr, int L, int R) {
        //当左边不小于右边时候返回
        if (!(L < R)) {
            return;
        }
        //计算中点
        int mid = L + ((R - L) >> 1);
        //向左归并
        guibingp(arr, L, mid);
        //向右归并
        guibingp(arr, mid + 1, R);
        //比较左右两边
        merger(arr, L, R, mid);
    }

    private static void merger(int[] arr, int l, int r, int mid) {
        //定义一个r到l等长的数组
        int[] help = new int[r - l + 1];
        //定义左指针
        int p1 = l;
        //定义右指针
        int p2 = mid + 1;
        //为help数组定义一个初始索引
        int i = 0;
        //当左指针位置大于了中间点,或者是右指针大于r边界了就返回
        while (p1 <= mid && p2 <= r) {
            //对比左指针和右指针代表的arr的数组值 如果p1小就把arr[p1]加进去,反之就把arr[p2]加进去
            help[i++] = arr[p1] > arr[p2] ? arr[p2++] : arr[p1++];
        }
        //当有一边已经到达边界或者超过边界了,则另一个指针一定没有越界 就把这个指针的距离边界的所有的值从左到右全部存进去
        while (p1 <= mid) {
            help[i++] = arr[p1++];
        }
        while (p2 <= r) {
            help[i++] = arr[p2++];
        }

        for (int j = 0; j < help.length; j++) {
            arr[l++] = help[j];
        }
    }

    //    二分查找
    public static int erfenselect(int[] arr, int L, int R, int selectnum) {
        if (selectnum < arr[L] || selectnum > arr[R]) {
            return -1;
        }
        int mid = L + ((R - L) >> 1);
        if (arr[mid] == selectnum) return mid;
        return selectnum < arr[mid] ? erfenselect(arr, L, mid, selectnum) : erfenselect(arr, mid + 1, R, selectnum);
    }


    public static void main(String[] args) {
        int[] arr = {11, 17, 121, 33, 46, 22, 15, 19, 28, 44, 57};
//        int[] arr2 = {1,8,5,4,13,2,1};
//        int[] arr3 = {1,2,3,4,6,8,9,10};
//        int i1 = erfenselect(arr3, 0, arr3.length - 1, 10);
//        System.out.println(i1);
//        System.out.println(erfenselect(arr2, 0, arr2.length-1, 8));
//        maopao(arr);
        guibingp(arr, 0, arr.length - 1);
//        guibing(arr, 0, arr.length-1);
        for (int i : arr) {
            System.out.print(i + ",");
        }
    }


    public static void swap(int[] arr, int p1, int i) {
        int temp = arr[p1];
        arr[p1] = arr[i];
        arr[i] = temp;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值