用java实现的10种排序算法

排序算法

选择排序

public static void main(String[] args) {
        int[] arr = {4, 5, 76, 3, 73, 67546, 734, 56, 4, 324, 36, 3, 44, 234, 36, 54, 6, 242, 35, 3};

        //选择排序
        //从小到大
        int len = arr.length;
        int k = 0;
        int temp = 0;
        for (int i = 0; i < len - 1; i++) {
            k = i;
            for (int j = i + 1; j < len; j++) {
                //每次找最小 假如k第几小数的下标
                if (arr[j] < arr[k]) {
                    //加入arr i 是最小的 如果有比arr i还要小的 先记录 为 k
                    k = j;
                }
            }
            if (k == i) {
                //不用发生交换
                continue;
            } else {
                //找第小 需要交换
                temp = arr[i];
                arr[i] = arr[k];
                arr[k] = temp;
            }

        }

        System.out.println("after sorted " + Arrays.toString(arr));
    }

插入排序

public static void main(String[] args) {
        int[] arr = {14, 5, 716, 3, 73, 67546, 734, 56, 44, 324, 36, 38, 44, 234, 36, 54, 6, 242, 35, 3};

        //4
        //4  5
        //4  5  76
        //3  4  5  76
        //插入排序
        //从小到大
        int length = arr.length;
        for (int i = 1; i < length; i++) {
            int j = i - 1;
            /*while (arr[i] < arr[j]) {
                //后面数大于前面的数 尽可能的找小于该数的下标 下标 j 前移 直到移到-1
                j--;
                if (j == -1) {
                    break;
                }
            }*/
            while (j != -1 && arr[i] < arr[j]) {
                //后面数大于前面的数 尽可能的找小于该数的下标 下标 j 前移 直到移到-1
                j--;
            }

            if (j + 1 == i) {
                //没有发生移动 break
                continue;
            } else {
                //发送了移动 记录要插入的数为temp 找到的下标+1 (j+1) 往后移腾出位置 给temp
                int temp = arr[i];
                for (int k = i - 1; k >= j + 1; k--) {
                    arr[k + 1] = arr[k];
                }
                //找到位置后 插入temp
                arr[j + 1] = temp;
            }
        }
        System.out.println("after sorted " + Arrays.toString(arr));
    }

交换排序(冒泡排序)

public static void main(String[] args) {
        int[] arr = {4, 5, 76, 3, 73, 67546, 734, 56, 4, 324, 36, 3, 44, 234, 36, 54, 6, 242, 35, 3};

        //冒泡排序
        //从小到大
        int length = arr.length;
        int temp = 0;
        for (int i = 0; i < length-1; i++) {
            for (int j = 0; j < length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

        System.out.println("after sorted " + Arrays.toString(arr));
    }

归并排序

public static void main(String[] args) {
        int[] arr = {12, 5, 6, 82, 54, 62, 67, 82, 23, 54, 763, 52};

        System.out.println("before sorted: "+Arrays.toString(arr));

        mergeSort(arr, 0, arr.length - 1, new int[arr.length]);

        System.out.println("after sorted: "+Arrays.toString(arr));

    }

    //拆分
    /**
     * @param arr   传入的要排序的数组
     * @param left  起始下标
     * @param right end下标
     * @param temp  辅助数组
     */
    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);

        }
    }

    public static void merge(int[] arr, int left, int mid, int right, int[] temp) {
        int i = left;
        int j = mid + 1;
        int t = 0;
        while (i <= mid && j <= right) {
            if (arr[i] < arr[j]) {
                temp[t++] = arr[i++];
            } else {
                //(arr[i] >= arr[j]
                temp[t++] = arr[j++];
            }
        }
        while (i <= mid) {
            temp[t++] = arr[i++];
        }
        while (j <= right) {
            temp[t++] = arr[j++];
        }
        t = 0;
        int tempLeft = left;
        while (tempLeft <= right) {
            arr[tempLeft++] = temp[t++];
        }
    }

快速排序

public static void main(String[] args) {
        int[] arr = {145, 46, 67, 625, 3435, 436, 36, 546, 85, 65, 35, 323, 432, 56, 4476, 25, 76846, 34, 54, 725, 75436};

        System.out.println("before sorted: " + Arrays.toString(arr));
        quickSort(arr, 0, arr.length - 1);
        System.out.println("after sorted: " + Arrays.toString(arr));

    }

    private static void quickSort(int[] arr, int left, int right) {
        if (left > right) {
            return;
        }

        //key为基准
        int key = arr[left];
        //i 和 j 为哨兵  arr[j]大于等于key j左移  j--
        // arr[i]小于等于key 右移 i++
        int i = left;
        int j = right;
        while (i < j) {
            //注意: 必须要先充右到左 在重左到右
            //j移动
            while (arr[j] >= key && i < j) {
                j--;
            }
            //i移动
            while (arr[i] <= key && i < j) {
                i++;
            }
            if (i < j) {
                //左边大于等于key的 和 右边小于等于key的交换位置
                //构成 左边的都是小于等于key的 右边的都是大于等于key的
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        //出了循环 说明 已经构成了
        //构成 左边的都是小于等于key的 右边的都是大于等于key的
        //基准的下标和 i和j相等时的下标交换位置
        arr[left] = arr[i];
        arr[i] = key;
        System.out.println("sorting: " + Arrays.toString(arr));

        //这时候基准是真的已经确定了 用基准左右两边的值进行递归找基准
        quickSort(arr, left, i - 1);
        quickSort(arr, i + 1, right);
    }

希尔排序(插入排序改进)

//希尔排序 改善的插入排序
    //参考插入排序 把-1 该为 -gap 外面加一层循环  for (; gap > 0; gap = gap / 2)  即可
    public static void main(String[] args) {
        int[] arr = {145, 46, 67, 625, 3435, 436, 36, 546, 85, 65, 35, 323, 432, 56, 4476, 25, 76846, 34, 54, 725, 75436};
        //步长 按/2来循环 步长到1就和正常插入排序一样了
        //前面的大于1的步长插入尽力的把数组往有序的靠近
        System.out.println("before sorted: " + Arrays.toString(arr));
        int gap = arr.length / 2;
        int len = arr.length;
        for (; gap > 0; gap = gap / 2) {
            for (int i = gap; i < len; i+=gap) {
                int j = i - gap;
                while (j >= 0 - gap) {
                    if (arr[i] < arr[j]) {
                        j -= gap;
                        if (j != (0 - gap)) {
                            continue;
                        }

                    }

                    if (j + gap == i) {
                        //直接是后一位 什么都不用移动
                        break;
                    } else {
                        //要移动
                        int temp = arr[i];
                        for (int k = i - gap; k >= j + gap; k -= gap) {
                            //按步长 一个个 往后移动
                            arr[k + gap] = arr[k];
                        }
                        arr[j + gap] = temp;
                        break;
                    }
                }
            }
            System.out.println("when gap: " + gap + Arrays.toString(arr));
        }
        System.out.println("after sorted: " + Arrays.toString(arr));
    }

堆排序

public static void main(String[] args) {
        //堆排序
        int[] arr = {13, 12, 54, 76, 57, 5, 34, 3, 5, 76, 8, 8, 79, 8, 22, 645, 6, 57, 68, 5, 35, 47, 58, 6, 52};

        System.out.println("before sorted: "+ Arrays.toString(arr));
        if (arr == null || arr.length == 0) {
            return;
        }

        //开始构建大顶堆
        int len = arr.length;
        buildMaxHeap(arr, len);
        System.out.println("sorting: "+Arrays.toString(arr));

        //开始交换 把树的根节点和数组的最后一个元素进行交换
        //这种交换要发生len -1次
        for (int i = len - 1; i > 0; i--) {
            swap(arr, 0, i);
            // 交换之后 大顶堆不存在 重新构建大顶堆 由于只是少了数的根节点
            // 树本身原来就是大顶堆 所有对 根节点下标为0的子树 大顶堆化
            // 如果发生交换 其他子树大叔大顶堆 由heapify方法自行进行控制 对要交换的元素递归调用heapify
            // 把树的根节点移到数组最后(也就是len-1的位置) 把它当做数之外的元素 树的大小减一
            len--;
            heapify(arr, 0, len);
        }

        System.out.println("after sorted: "+ Arrays.toString(arr));

    }

    /**
     * @param arr 数组
     * @param len 所用数组中元素的个数
     *            0
     *            1   2
     *            3  4  5  6
     *            7  8   9
     *            <p>
     *            0 1 2 3 4 5 6 7 8 9
     */
    private static void buildMaxHeap(int[] arr, int len) {
        //从最后一个非叶子节点开始向前遍历 调整节点性质 使其变为大顶堆
        //公式计算该节点下标 i = (int) Math.floor(len /2) -1
        int i = (int) Math.floor(len / 2) - 1;
        for (; i >= 0; i--) {
            heapify(arr, i, len);
        }
    }

    /**
     * 使根节点下标为i的子树变为大顶堆
     * 大顶堆化
     *
     * @param arr 数组
     * @param i   子树根节点下标
     * @param len 可用数组中元素的个数 也就是整个数的大小
     */
    private static void heapify(int[] arr, int i, int len) {
        //堆的性质 计算左右节点对象的下标
        int left = 2 * i + 1;
        int right = 2 * i + 2;

        //默认当前节点为最大值
        int largestIndex = i;
        //知道该父节点的左右孩子的下标 根据right < len 和 left < len
        //判断左右节点是否真的存在 存在则比较
        if (left < len && arr[left] > arr[largestIndex]) {
            largestIndex = left;
        }
        if (right < len && arr[right] > arr[largestIndex]) {
            largestIndex = right;
        }
        //找到最大 然后发送交换
        if (i != largestIndex) {
            // 如果不是自己才去交换
            swap(arr, i, largestIndex);

            //交换之后 子节点的值发送变化 为了保证还是个大顶堆 再次通过方法进行大顶堆化
            heapify(arr, largestIndex, len);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

基数排序

public static void main(String[] args) {
        int[] arr = {145, 6, 5, 37, 344, 347, 59, 58, 300, 45,
                3654, 25, 322, 4, 46, 57, 54, 3, 2, 354, 67, 65, 4, 345, 644, 7265, 7, 3, 5, 235, 67};
        System.out.println("before sorted: "+ Arrays.toString(arr));
        //基数排序 0--9 典型的空间换时间
        //思路:构造一个二位数组 10行arr.length列 (为了防止数组的元素都是一个下标越界)
        // 先拿各位进行排序 把各位的排序结果 按找二维数组 列优先的遍历方式 把不为空为元素放到arr数组里面 有的话依次十位 百位 千位
        // 让构造的新数组参与下一轮排序 直到排到最高为 arr必然已经是一个有序的了 (一位前人总结的这个经验,仅限于正整数)
        int[][] data = new int[10][arr.length]; //也可以用结合 更省内存
        int[] digitElement = new int[10];

        //要找最大的数 也就是要就算这个数组arr 的最大数有几位 最外层要进行几层循环才能得到完全有序
        int max = -1;
        for (int num : arr) {
            if (max < num) {
                max = num;
            }
        }
        //得到位数 最外层循环次数
        int bit = (max + "").length();

        for (int i = 0; i < max; i++) {
            int temp = (int) Math.pow(10, i);
            for (int num : arr) {
                int index = num / temp % 10;
                data[index][digitElement[index]] = num;
                digitElement[index]++;

            }
            //没一次外循环构建的是一个新的序列的数组
            int j = 0;
            for (int k = 0; k < digitElement.length; k++) {
                if (digitElement[k] != 0) {
                    //不为0说明至少是有一个元素的 挨个赋值给arr 新的序列
                    for (int l = 0; l < digitElement[k]; l++) { //某位元素不止一个的都要都取到放arr里面去 不能少
                        arr[j++] = data[k][l];
                    }
                }
                //是通过 digitElement数组里面元素是否为0判断有无元素 有几个元素
                //为了保证下次循环数组正确 使用完要置为0
                digitElement[k] = 0;

            }
        }

        System.out.println("after sorted: "+ Arrays.toString(arr));

    }

计数排序

public static void main(String[] args) {
        int[] arr = {13, 12, 54, 76, 57, 5, 34, 32, 45, 76, 84, 58, 79, 8, 22, 645, 6, 57, 68, 65, 35, 47, 58, 61, 52};
        System.out.println("before sorted: "+ Arrays.toString(arr));
        //计数排序 典型的空间还时间
        //思想:原则上数组里面最大值为n 就构造一个n+1的数组 数组的下标天然有序 分别表示存储这些元素
        //元素的下标就是表示该数 然后该元素的值就表示该元素的多少 然后遍历这各构造的函数 有值(值不为0)
        //说明存在至少一个元素 构造的数组的下标就是这个元素 依次遍历构造的数组 挨个取值就是一个有序的数组了
//        countSortOrigin(arr);
        //优化:考虑构造的数组太大的原因这里可以取出数组的最大值和最小值 构造一个max-min+1的大小的数组 用于存储元素
        int max = arr[0]; //找最大值
        int min = arr[0]; //找最小值
        for (int num : arr) {
            if (max < num) {
                max = num;
            }
            if (min > num) {
                min = num;
            }
        }
        int[] tempArr = new int[max-min+1]; //初始值每个都为0
        for (int num : arr) {
            tempArr[num-min]++;  //这里一个巧妙的操作是num-min
        }
        int t = 0;
        for (int i = 0; i < tempArr.length; i++) {
            if (tempArr[i] != 0) {
                for (int j = 0; j < tempArr[i]; j++) {
                    arr[t++] = i+min; //这里用到了那个巧妙的操作是i+min
                }
            }
        }
        System.out.println("after sorted: "+ Arrays.toString(arr));


    }

    private static void countSortOrigin(int[] arr) {
        int max = arr[0]; //找最大值
        for (int num : arr) {
            if (max < num) {
                max = num;
            }
        }
        int[] tempArr = new int[max+1]; //初始值每个都为0
        for (int num : arr) {
            tempArr[num]++;
        }
        //把新数组挨个放到原数组里面
        int t = 0;
        for (int i = 0; i < tempArr.length; i++) {
            if (tempArr[i] != 0) {
                for (int j = 0; j < tempArr[i]; j++) {
                    arr[t++] = i;
                }
            }
        }
        System.out.println("after sorted: "+ Arrays.toString(arr));

    }

桶排序

public static void main(String[] args) {

        int[] arr = {13, 12, 54, 76, 57, 5, 34, 32, 45, 76, 84, 58, 79, 8, 22, 645, 6, 57, 68, 65, 35, 47, 58, 61, 52};
        System.out.println("before sorted: " + Arrays.toString(arr));
        //桶排序 空间换时间 把空间相对再缩小一点 用桶中不会有序的来补充
        //某种意义上 计数排序就是特殊的桶排序 桶的数量达到了最大 并且每个桶里面都是排好序的
        //思路:类别计数排序 每个桶挨个是有序的 桶内不一定有序 保证桶内元素有序 挨个取出挨个赋值到原数组 必然有序了
        //总之 用计数排序来理解桶排序是很好理解的
        int max = arr[0]; //找最大值
        int min = arr[0]; //找最小值
        for (int num : arr) {
            if (max < num) {
                max = num;
            }
            if (min > num) {
                min = num;
            }
        }
        //首先要确定桶的数量 计数排序的桶的数量就是max-min+1
        //这里要空间相对再缩小一点 设置一个因子来缩小桶 factor
        //默认的话使用数组的长度arr.length作为factor 也可以用其他的
        int factor = arr.length;
        int bucketCount = (max - min) / arr.length + 1; //这里直接就max - min 部跟计数排序那样谈优化了
        //桶数量 加1t同样是防止数组下标越界
        //拿计数排序举例 元素下标0开始最大元素为n 下标最大值为n-1 越界 计数排序优化同样是这个道理

        //这里与计数排序不同的是 桶里面的元素不一样 只是一个区间里的 而且不一定有序
        //所以至少需要一个二维的空间 可以选数组 可以选集合 前面的9个排序首先考虑都是选数组 这里选集合吧
        ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketCount); //bucketCount 桶的大小
        //防止空指针异常 桶中集合初始化
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<Integer>());
        }
        for (int num : arr) {
            //获取小标 factor是那个因子 这里factor就是arr.length 因为这个factor不一定必须是length 两个分开来说
            int index = (num - min) / factor;
            buckets.get(index).add(num);
        }
        //然后就是桶内元素排序 随便选用一个排序算法 这里用jdk的api
        for (ArrayList<Integer> bucket : buckets) {
            Collections.sort(bucket);
        }
        //最后挨个取值赋值给原数组 排序就完成了
        int t = 0;
        for (ArrayList<Integer> bucket : buckets) {
            int size = bucket.size();
            if (size != 0) {
                for (int i = 0; i < size; i++) {
                    arr[t++] = bucket.get(i);
                }
            }
        }
        System.out.println("after sorted: " + Arrays.toString(arr));
    }

排序算法分析

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值