基础的几个排序(Java实现)

直接上代码

package com.ydj.study.sort;

import java.util.Arrays;

/**
 * 冒泡排序
 */
public class Sort {

    //插入排序,O(n^2) insertSort > selectSort> bubbleSort
    public void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];//当前比较的值,如果当前值小于上一个位置的值,则将当前位置赋上一个位置的值
            int tempIndex = i - 1; //从后往前比
            while (tempIndex >= 0 && temp < array[tempIndex]) {
                array[tempIndex + 1] = array[tempIndex];
                tempIndex--;
            }
            array[tempIndex + 1] = temp;
            // print(array);
        }
    }

    //O(n^2)
    public void selectSort(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            int minIndex = i;
            int min = array[i];
            for (int j = i + 1; j < array.length; j++) {
                if (min < array[j]) {
                    min = array[j];
                    minIndex = j;
                }
                if (minIndex != i) {
                    array[minIndex] = array[i];
                    array[i] = min;
                }
            }

        }
    }

    /**
     * 优化 O(n^2)
     */
    public void bubbleSort2(int[] array) {
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = 0; j < array.length - 1 - i; j++) {
                if (array[j] > array[j + 1]) {
                    int a = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = a;
                }
            }
            // print(array);
        }

    }

    /**
     * shellSort 希尔排序
     * 希尔排序是将记录按下标的一定增量分组,对每组使用直接插入排序,
     * 随着增量逐渐减少,每组包含的关键词越来越多,
     * 当增量减少至1时,整个文件被分成1组,算法终止
     */

    /**
     * hillSort 转换法(时间复杂度 n^2 * log2N
     * 不建议
     *
     * @param array
     */
    public void shellSortSwap(int[] array) {
        int length = array.length / 10;
        int temp;
        while (length > 0) {
            for (int i = length; i < array.length; i++) {
                for (int j = i - length; j >= 0; j -= length) {
                    if (array[j] > array[j + length]) {
                        temp = array[j];
                        array[j] = array[j + length];
                        array[j + length] = temp;
                    }
                }
            }
            // print(array);
            length = length / 10;
        }
    }

    /**
     * shell排序插入法
     * 正确解法
     * 时间复杂度 O(n logn) 对数线性
     */
    public void shellSortInsert(int[] array) {
        for (int gap = array.length / 2; gap > 0; gap /= 2) {
            //从第gap个元素,逐个对其组进行直接插入排序
            for (int i = gap; i < array.length; i++) {
                int j = i;
                int temp = array[j];
                while (j - gap >= 0 && temp < array[j - gap]) {
                    //往前移动
                    array[j] = array[j - gap];
                    j -= gap;
                }
                array[j] = temp;
            }
        }
        //   print(array);
    }

    /**
     * 快排 时间复杂度
     * 快排的思路是:依据一个"中值"数据项来把数据表分成两半:小于中值的一半与大于中值的一半
     * 然后每部分分别进行快排(递归)
     * 如果希望这两半数据拥有相同数量的数据项,则应该找到数据表的中位值,但计算中位值也需要消耗
     * 所以随便找一个值来做中值就行,比如array[0]
     * 快排的递归算法三要素:
     * 1、结束条件:数据表仅有一个数据项时,自然是排序好的
     * 2、缩小规模:根据"中值",将数据表分为两半,最好是相同规模的两半
     * 3、调用自身:将两半分别调用自身进行排序(排序基本操作在分裂过程中)
     */


    //快排1
    //当以index/2为中值时
    public int[] quickSort1(int[] array, int first, int last) {
        if (first < last) {
            int splitpoint = partition(array, first, last);
            quickSort1(array, first, splitpoint - 1);
            quickSort1(array, splitpoint + 1, last);
        }
        return array;
    }

    private int partition(int[] array, int first, int last) {
        int pivot = (first + last) / 2;
        int left = first;
        int right = last;
        while (left < right) {
            while (left <= right && array[left] <= array[pivot]) left++;
            while (left <= right && array[right] >= array[pivot]) right--;
            if (left >= right) break;
            swap(array, left, right);
        }
        swap(array, left, pivot);
        // print(array);
        return right;
    }

    public void quickSort2(int[] array, int left, int right) {
        //当左指针与右指针指向同一数据时,就已经要退出了
        if (left < right) {
            int pivot = partition2(array, left, right);
            //找到中位值以后,是剩下的两组去接着快排,中位值不参与排序
            quickSort2(array, left, pivot - 1);
            quickSort2(array, pivot + 1, right);
        }
    }

    //快排2
    //当以第一个数字为中值时
    public int partition2(int[] array, int first, int last) {
        int pivot = array[first];
        int leftMark = first + 1;
        int rightMark = last;
        while (leftMark <= rightMark) {
            while (leftMark <= rightMark && array[leftMark] <= pivot) leftMark += 1;
            while (rightMark >= leftMark && array[rightMark] >= pivot) rightMark -= 1;
            //当l遇到了比中位值大的值,且r遇到了比中位值小的值,将这俩值交换
            if (leftMark >= rightMark) {
                break;
            }
            swap(array, leftMark, rightMark);
        }
        //替换当前l的值,与中位值
        //这个是为什么要把l的值与中位值替换
        //当跳出循环时,只会是l==r的时候,当l与r同一位置的时候,
        swap(array, rightMark, first);
        return rightMark;
    }

    public void quickSort3(int[] array, int left, int right) {
        if (left >= right) return;
        int mid = partition3(array, left, right);
        partition3(array, left, mid - 1);
        partition3(array, mid + 1, right);
    }

    private int partition3(int[] array, int first, int last) {
        int pivot = array[last];
        int leftMark = first;
        int rightMark = last - 1;
        while (leftMark < rightMark) {
            while (leftMark <= rightMark && array[leftMark] <= pivot) leftMark++;
            while (leftMark <= rightMark && array[rightMark] >= pivot) rightMark--;
            if (leftMark >= rightMark) {
                break;
            }
            swap(array, leftMark, rightMark);
        }
        swap(array, last, leftMark);
        return leftMark;
    }

    /*
    *   归并算法核心思想:将数组通过递归分为两个数字,然后排序,排序后再去合并成俩(长度为2的数组)继续去排序
    *  两个数组排序是双指针,从大到小放到temp数组中
     */
    public void mergeSort(int[] array,int left,int right,int[] temp){
        if (left < right) {
            int mid = (left + right) / 2;
            mergeSort(array,left,mid,temp);
            mergeSort(array,mid+1,right,temp);
            merge(array,left,mid,right,temp);
        }
    }

    /**
     * 归并算法
     *  合并
     * @param array 需要排序的数组
     * @param left  左索引
     * @param mid   中索引
     * @param right 右索引
     * @param temp  中转数组(做替换时使用,用于两个数组做替换)
     */
    public void merge(int[] array, int left, int mid, int right, int[] temp) {
        int i = left;//初始i,左边有序序列的初始索引
        int j = mid + 1; //一个数组以mid为界限分为俩数组,那么第二个数组的第一个元素下标为mid+1
        int t = 0; //可以理解为依次排序的索引,放完0,放1,2,3
        while (i <= mid && j <= right) {
            if (array[i] <= array[j]) {
                temp[t] = array[i];
                t += 1;
                i += 1;
            } else {
                temp[t] = array[j];
                t += 1;
                j += 1;
            }
        }
        //
        while (i <= mid) {
            temp[t] = array[i];
            t += 1;
            i += 1;
        }
        while (j <= right) {
            temp[t] = array[j];
            t += 1;
            j += 1;
        }
        //
        int t1 = 0;
        int leftMark = left;
        while (leftMark <= right) {
            array[leftMark] = temp[t1];
            t1 += 1;
            leftMark += 1;
        }
    }

    /**
     * 基数排序思想:将所有待比较数值统一为相同的数组长度,数位较短的数前面直接补零,然后从最低位
     * 开始,依次进行一次排序,这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序的数列
     * 放入桶中时,就已经对各个位置进行排序了
     * 当比较个位数的时候,个位数,完成排序(动动脑筋,数字1就放到了下标位1的桶中,数字2就放到下标位2的桶中),然后
     * 会有一个当前桶的数据依次覆盖给原数组的操作,这个操作完以后,只看个位数的话,他们是已经排好序了
     * 当比较十位数时,个位数全部丢到0,此时,下标位为0的桶中,就只会有个位数,以此类推,每次排序都把下一位的数字排序
     *
     * 核心思想:在把每个相同位的数字放入桶的这个过程就已经对这些位的数值排好序了
     * (比如1411,千位,在比较千位数据的时候所有xx千的数据,百、十、个位置的数据已经在之前排序好了
     */
    public void radixSort(int[] array) {
        int[][] bucket = new int[10][array.length];
        int[] bucketElementCounts = new int[10];

        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        int maxLength = (max +"").length();

        for (int i = 0 , n = 1; i < maxLength; i++,n *= 10) {
            for (int j = 0; j < array.length; j ++) {
                int digitOfElement = array[j] / n % 10;
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = array[j];
                bucketElementCounts[digitOfElement] += 1;
            }
            int index = 0;
            for (int k = 0; k < bucketElementCounts.length; k++) {
                if (bucketElementCounts[k] != 0) {
                    for (int j = 0; j < bucketElementCounts[k]; j++) {
                        array[index++] = bucket[k][j];
                    }
                }
                bucketElementCounts[k] = 0;
            }
        }
    }


    private void swap(int[] arr, int swap1, int swap2) {
        int temp = arr[swap1];
        arr[swap1] = arr[swap2];
        arr[swap2] = temp;
    }


    private void print(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int length = 100000000;
        int[] array = new int[length];
        for (int i = 0; i < length; i++) {
            array[i] = (int) (Math.random() * length);
        }

        int[] tempA = new int[array.length];
        Sort sort = new Sort();
        Long s = System.currentTimeMillis();
       // sort.quickSort2(array, 0, array.length - 1);
        //sort.shellSortInsert(array);
        //sort.mergeSort(array,0,array.length-1,tempA);
        sort.radixSort(array);
        //sort.print(array);

        System.out.println("time:" + (System.currentTimeMillis() - s));

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值