基础排序算法

基础排序算法实现,主要参照程序员小灰的《漫画算法》

性能分析

冒泡排序

	/**
     * O(n^2)
     * @param arr
     * @return
     */
    private static int[] bubbleSort(int[] arr) {
        int sortBorder = arr.length - 1;
        int lastChange = 0;
        for (int i=0; i<arr.length-1; i++) {
            boolean changeFlag = true;
            for (int j=0; j<sortBorder; j++) {
                if (arr[j] > arr[j+1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                    changeFlag = false;
                    //最后一个需要交换的元素,后面都已经有序
                    lastChange = j;
                }
            }
            sortBorder = lastChange;
            if (changeFlag) {
                break;
            }
        }
        return arr;
    }

桶排序

/**
     * O(n)
     * O(n*k) k个桶,每个桶里是逆序  ??
     * @param arr
     * @return
     */
    public static double[] bucketSort(double[] arr) {
        //1、获取最值
        double max = arr[0];
        double min = arr[0];
        for (int i=1, len=arr.length; i<len; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
            if (arr[i] < min) {
                min = arr[i];
            }
        }

        //2、初始化桶  简单设计桶的数量等于原始数据的数量
        int bucketNum = arr.length;
        ArrayList<LinkedList<Double>> bucketList = new ArrayList<>(bucketNum);
        for (int i=0; i<bucketNum; i++) {
            bucketList.add(new LinkedList<>());
        }

        //3、遍历数组 将原始数据放在合适的桶内
        //区间跨度 (max - min) / (bucketNum - 1)
        double d = max - min;
        for (int i=0, len=arr.length; i<len; i++) {
            int num = (int) ((arr[i] - min) * (bucketNum - 1) / d);
            bucketList.get(num).add(arr[i]);
        }

        //4、对每个桶排序
        for (int i=0, len=bucketList.size(); i<len; i++) {
            Collections.sort(bucketList.get(i));
        }

        //5、输出所有元素即可
        double[] sortArr = new double[arr.length];
        int index = 0;
        for (LinkedList<Double> linkedList : bucketList) {
            for (double e : linkedList) {
                sortArr[index++] = e;
            }
        }
        return sortArr;
    }

计数排序

/**
     * 元素都是比较小的数
     * @param arr
     * @return
     */
    private static int[] countSort1(int[] arr) {
        int max = arr[0];
        //遍历一遍,找到最大值,为了确定数组的长度
        for (int i=0,len=arr.length; i<len; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }

        //用来计数排序的数组
        int[] countArr = new int[max + 1];

        //遍历待排序数组,记录每个数出现的次数
        for (int i=0,len=arr.length; i<len; i++) {
            countArr[arr[i]]++;
        }

        //遍历countArr输出统计结果
        int index = 0;
        int[] sortArr = new int[arr.length];
        for (int i=0,len=countArr.length; i<len; i++) {
            for (int j=0; j<countArr[i]; j++) {
                sortArr[index++] = i;
            }
        }
        return sortArr;
    }

    /**
     * 元素比较大  按照最大元素分配 浪费空间
     * @param arr
     * @return
     */
    public static int[] countSort2(int[] arr) {
        //获得数组中的最值,确定统计数组的大小
        int max = arr[0];
        int min = arr[0];

        for (int i=1,len=arr.length; i<len; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
            if (arr[i] < min) {
                min = arr[i];
            }
        }

        int d = max - min + 1;
        //创建统计数组
        int[] countArr = new int[d];
        for (int i=0,len=arr.length; i<len; i++) {
            countArr[arr[i] - min]++;
            //元素-偏移量,例countArr[99 - 90]++;
        }

        // 对统计数组做变形 小于等于countArr[i]的数字出现的次数
        // 主要是为了稳定,计数排序本来是不稳定的排序算法
        for(int i=1,len=countArr.length; i<len; i++) {
            countArr[i]+=countArr[i - 1];
        }

        //倒序遍历原始数据,从统计数组找到该元素的正确位置
        int[] sortArr = new int[arr.length];
        for (int i=arr.length-1; i>=0; i--) {
            // countArr[arr[i]-min] 确定arr[i]前面有几个不大于它的元素
            //(包含它自己,这也就是确定arr[i]所在的位置)
            // countArr[arr[i]-min] - 1 例如:第三大的,应该放置在index为2的位置
            sortArr[ countArr[arr[i]-min] - 1] = arr[i];
            // 不大于它的数已经放置了一个,对应的数量减一
            countArr[arr[i]-min]--;
        }
        return sortArr;
    }
    // 基数排序  先以个位进行排序,之后十位,从低位到高位  稳定排序

堆排序

/**
     * 下沉操作
     * @param array
     * @param parentIndex
     * @param length
     */
    private static void downAdjust(int[] array, int parentIndex, int length) {
        int temp = array[parentIndex];
        int childIndex = 2 * parentIndex + 1;
        while (childIndex < length) {
            //有右孩子, 并且右孩子更大
            if(childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {
                childIndex++;
            }
            //父亲节点 不小于子节点 跳出
            if (temp >= array[childIndex]) {
                break;
            }
            array[parentIndex] = array[childIndex];
            parentIndex = childIndex;
            childIndex = 2 * childIndex + 1;
        }
        array[parentIndex] = temp;
    }

    /**
     * 不稳定
     * O(nlogN)
     *
     * 插入删除 logN  n个节点  nlogN
     * 很少和响铃元素进行比较交换  快排慢慢趋于有序,堆排则不然
     * @param array
     */
    public static void heapSort(int[] array) {

        // 构建大顶堆
        // 如果一个节点的两个子节点已经有序了,那么他的子节点的子节点是否有序,就不需要关心了,因此值调整一半即可
        for (int i=(array.length - 2) / 2; i>=0; i--) {
            downAdjust(array, i, array.length);
        }
        System.out.println("最大堆构建"+Arrays.toString(array));

        //循环删除堆顶元素
        for (int i=array.length-1; i>0; i--) {
            //最后一个元素与第一个交换
            int temp = array[i];
            array[i] = array[0];
            array[0] = temp;
            downAdjust(array, 0, i);
        }
    }

插入排序

/**
     * 第一个元素有序  后面的和前面已经有序的进行比较 逆序则调整
     * 稳定
     * O(n) O(n^2)
     * @param arr
     * @return
     */
    private static int[] insertSort(int[] arr) {

        for (int i=1; i<arr.length-1; i++) {
            for (int j=i; j>0; j--) {
                if (arr[j] < arr[j-1]) {
                    int temp = arr[j];
                    arr[j] = arr[j-1];
                    arr[j-1] = temp;
                }
            }
        }
        return arr;
    }

归并排序

private static void merge(int[] arr, int low, int mid, int high) {
        int[] temp = new int[arr.length];
        int i = low, j = mid + 1;
        int k = low;
        while (i <= mid && j <= high) {
            if(arr[i] < arr[j]) {
                temp[k++] = arr[i++];
            } else {
                temp[k++] = arr[j++];
            }
        }

        while (i <= mid) {
            temp[k++] = arr[i++];
        }

        while (j <= high) {
            temp[k++] = arr[j++];
        }

        for (int t=low; t<=high; t++) {
            arr[t] = temp[t];
        }
    }

    /**
     * 非原地
     * 稳定
     * O(nlogn)
     * @param arr
     * @param low
     * @param high
     */
    private static void sort(int[] arr, int low, int high) {

        if (low < high) {
            int mid = low + (high - low) / 2;
            sort(arr, low, mid);
            sort(arr, mid + 1, high);
            merge(arr, low, mid, high);
        }
    }

快排

/**
     * O(nlogN) 对半分
     * O(n^2) 每次切分都选择了最值元素作为基准元素
     * @param arr
     * @param startIndex
     * @param endIndex
     * @return
     */
    private static int partition(int[] arr, int startIndex, int endIndex) {
        //获取第一个元素,作为基准元素
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;

        while (left < right) {
            //控制right指针,比较并且左移
            while (left < right && arr[right] > pivot) {
                right--;
            }
            //控制left指针,比较并且右移
            while (left < right && arr[left] <= pivot) {
                left++;
            }
            //当right<=pivot  && left>pivot 停止移动,交换
            if (left < right) {
                int temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
            }
        }
        //左右指针重合了,与基准元素就行交换

        //基准元素 。。。。。。。小于 left == right 大运 基准元素 。。。。。
        arr[startIndex] = arr[left];
        arr[left] = pivot;
        //返回基准元素下标
        return left;
    }

    private static void quickSort(int[] arr, int startIndex, int endIndex) {
        //递归结束条件
        if (startIndex >= endIndex) {
            return;
        }

        //获得基准元素位置
        int pivotIndex = partition(arr, startIndex, endIndex);
        //根据基准元素,分治
        quickSort(arr, startIndex, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, endIndex);
    }

选择排序

/**
     * 不稳定
     * O(n^2)
     * 选择最小元素 与第一个元素交换
     * 选择第二小元素  与第二个元素进行交换
     * @param arr
     * @return
     */
    private static int[] selectSort(int[] arr) {
        for (int i=0; i<arr.length-1; i++) {
            for (int j=i+1; j<arr.length; j++) {
                if(arr[j] < arr[i]) {
                    int temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
            }
        }
        return arr;
    }

希尔排序

private static void shellSort(int[] arr) {
        int N = arr.length;
        int h = 1;
        while (h < N / 3) {
            h = 3 * h + 1;
        }
        while (h >= 1) {
            for (int i=h; i<N; i++) {
                for (int j=i; j>=h; j-=h) {
                    if(arr[j] < arr[j-h]) {
                        int temp = arr[j];
                        arr[j] = arr[j-h];
                        arr[j-h] = temp;
                    }
                }
            }
            h = h / 3;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值