基础排序算法 java 实现(冒泡、选择、插入、快排、归并、堆排)

package demo;

import java.util.Arrays;

public class SortUtil {
    private static void printArr(int[] arr) {
        System.out.println(Arrays.toString(arr));
    }

    private static void checkSort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                throw new RuntimeException("Sort Error!");
            }
        }
    }

    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 = {4, 3, 5};

        int[] arr = new int[50000 * 100];
        java.util.Random random = new java.util.Random();
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(arr.length);
        }

//        System.out.println("排序前:");
//        printArr(arr);

        long s = System.currentTimeMillis();

//        bubbleSort(arr);// 50000 数据 5000+ ms
//        selectSort(arr);// 50000 数据 1700+ ms
//        insertSort(arr);// 50000 数据 360+ ms

        quickSort(arr, 0, arr.length - 1);// 50000 * 100 数据 770 ms

//        mergeSort(arr);// 50000 * 100 数据 1300 ms
//        mergeSort(arr, 0, arr.length - 1);// 50000 * 100 数据 1300 ms

//        heapSort(arr);// 50000 * 100 数据 1650 ms

        long e = System.currentTimeMillis();
        System.out.println("耗时:" + (e - s));

        checkSort(arr);
        System.out.println("排序正确!");

//        System.out.println("排序后:");
//        printArr(arr);
    }

    private static void bubbleSort(int[] arr) {
        int len = arr.length;
        for (int i = 0; i < len - 1; i++) { //要放置正确元素的目标位置,最后一个不用放
            for (int j = len - 1; j > i; j--) { // 从后往前,把最小(大)的挪动到目标位置
                if (arr[j] < arr[j - 1]) { // 后面的大于前面
                    swap(arr, j, j - 1);//如果没有发送交互则表示排序已经完成,但会多n次判断
                }
            }
        }
    }

    private static void selectSort(int[] arr) {
        int len = arr.length;
        for (int i = 0; i < len - 1; i++) { //要放置正确元素的目标位置,最后一个不用放
            int min = i;

            for (int j = i + 1; j < len; j++) {
                if (arr[j] < arr[min]) { // 后面的大于前面
                    min = j;
                }
            }

            swap(arr, i, min);
        }
    }

    private static void insertSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {// 第一个不需要插入排序
            int temp = arr[i];
            int j = i - 1;
            while (j >= 0 && temp < arr[j]) {
                arr[j + 1] = arr[j];
                j--;
            }
            arr[j + 1] = temp;
        }
    }

    /*** quick ***/
    private static void quickSort(int[] arr, int left, int right) {
        if (left >= right) return;
        int pivotIndex = partition(arr, left, right);
        quickSort(arr, left, pivotIndex - 1);//排序 target 前面的
        quickSort(arr, pivotIndex + 1, right);//排序 target 后面的
    }

    private static int partition(int[] arr, int left, int right) {
        int pivot = arr[right];//堆排序是原地排序,这个额外空间可以省去的,这里为了语义明确在此声明
        int target = left;
        for (int i = left; i < right; i++) {
            if (arr[i] < pivot) {
                swap(arr, target++, i);
            }
        }
        swap(arr, target, right);// target 已经处在正确的位置
        return target;
    }

    /*** merge:递归实现 从外向里 ***/

    private static void mergeSort(int[] arr, int left, int right) {
        if (left == right) return;//待排序列长度为1
        int middle = (left + right) / 2;
        mergeSort(arr, left, middle);
        mergeSort(arr, middle + 1, right);
        merge(arr, left, middle, right);
    }

    /*** merge:迭代实现 从里向外 ***/
    private static void mergeSort(int[] arr) {
        int len = arr.length;
        int left;//需要归并的左坐标
        int middle;//需要归并的中坐标(定义为左侧的结束端坐标),也就是步长的最后一个
        int right;//需要归并的右坐标
        for (int mergeLen = 1; mergeLen < len; mergeLen *= 2) {
            left = 0;
            while (left + mergeLen < len) { // 有后面的数组需要归并
                middle = left + mergeLen - 1;
                right = middle + mergeLen < len ? middle + mergeLen : len - 1;
                merge(arr, left, middle, right);
                left = right + 1;
            }
        }
    }

    private static void merge(int[] arr, int left, int leftEnd, int right) {
        int len = right - left + 1;
        int[] temp = new int[len];//辅助空间
        int tempIndex = 0;//辅助空间指针
        int i = left;//左侧指针
        int j = leftEnd + 1;//右侧指针
        while (i <= leftEnd && j <= right) {
            if (arr[i] <= arr[j]) {// 带等号保证归并排序的稳定性
                temp[tempIndex++] = arr[i++];
            } else {
                temp[tempIndex++] = arr[j++];
            }
        }
        while (i <= leftEnd) {
            temp[tempIndex++] = arr[i++];//左侧数组未
        }
        while (j <= right) {
            temp[tempIndex++] = arr[j++];
        }
        for (int k = 0; k < len; k++) {
            arr[left + k] = temp[k];//将辅助空间内容替换至真实数组的 left-right 空间
        }
    }

    /*** heap ***/
    private static void heapSort(int[] arr) {
        buildHeap(arr);//初始化大顶堆
        int maxHeapIndex = arr.length - 1;
        while (maxHeapIndex > 0) {// 堆(无序区)元素个数大于1,未完成排序
            swap(arr, 0, maxHeapIndex--);// 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
            adjustHeap(arr, 0, maxHeapIndex);// 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
        }
    }

    private static void buildHeap(int[] arr) { // 建堆,时间复杂度O(n)
        int len = arr.length;
        for (int i = len / 2 - 1; i >= 0; i--) {//从最后一个非叶子节点开始,向上调堆,当i==0时,所有堆成为最大堆
            adjustHeap(arr, i, len - 1);
        }
    }

    private static void adjustHeap(int[] arr, int i, int maxIndex) {
        int leftChild = i * 2 + 1;
        int rightChild = i * 2 + 2;
        int max = i;
        if (leftChild <= maxIndex && (arr[leftChild] > arr[max])) {
            max = leftChild;
        }
        if (rightChild <= maxIndex && (arr[rightChild] > arr[max])) {
            max = rightChild;
        }
        if (max != i) {
            swap(arr, i, max);//把最大的换到当前堆顶,然后继续调剂被破坏的子堆
            adjustHeap(arr, max, maxIndex);// 保证被破坏的子堆继续维持大顶堆性质
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值