常见排序算法

/*
 * 排序算法:
 *      交换排序:快速排序(O(NlogN),不稳定)、冒泡排序(O(N^2),稳定)
 *      插入排序:直接插入排序(O(N^2),稳定)、希尔排序(O(N^1.3)不稳定)
 *      选择排序:直接选择排序(O(N^2),不稳定),堆排序(O(NlogN),不稳定)
 *      归并排序(O(NlogN),稳定)
 */
public class Sort {
    /*
     * 1.快速排序,该方法有三个参数,数组arr,需要进行排序的部分数组(由low和high截取),然后找
     * 一个基准值(一般为需要排序的数组的第一个元素),确定基准值所在的位置(start=end时),再使用
     * 递归对基准值两边的元素继续进行快排。
     * 
     * 简言之,快排第一步就是确定基准值的位置,然后再进行递归求解。
     */
    public static void quicklySort(int arr[], int low, int high) {
        int key = arr[low];
        int start = low;
        int end = high;
        while (start < end){
            while (arr[end] >= key && start < end){
                end--;
            }
            arr[start] = arr[end];
            while (arr[start] <= key && start < end){
                start++;
            }
            arr[end] = arr[start];
        }
        arr[start] = key; // 将基准值填到相应位置
        if (start > low)
            quicklySort(arr, low, start - 1);
        if (end < high)
            quicklySort(arr, end + 1, high);
    }

    /*
     * 2.冒泡排序,遇见比当前数小的就交换顺序
     */
    public static void bubbleSort(int arr[]) {
        int temp;
        for (int i = 0; i < arr.length; i++){
            for (int j = arr.length - 1; j > i; j--){ //从后往前冒,当然也可以从前往后沉
                if (arr[j] < arr[j - 1]){
                    temp = arr[j];
                    arr[j] = arr[j - 1];
                    arr[j - 1] = temp;
                }
            }
        }
    }
    /*
     * 3.直接插入排序,假设数组第一个元素自成一个有序序列,从第二个元素起,依次与前面的元素进行
     * 比较,插入到正确的位置以构成有序序列,直到最后一个元素插入到正确位置从而使得整个数组有序。
     */
    public static void insertionSort(int arr[]) {
        int temp;
        for (int i = 1; i < arr.length; i++){ //i表示从哪个位置的元素开始与它之前的元素进行比较
            int j = i;
            while (j > 0 && arr[j] < arr[j - 1] ){//这里不用for循环是因为使用for循环则无论arr[j]是否小于arr[j-1],都要进行j--的操作
                temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
                j--;
            }
        }
    }

    /*
     * 4.希尔排序,改进的直接插入排序,先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行
     * 直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入
     * 排序。因为直接插入排序在元素基本有序的情况下(接近最好情况),效率是很高的,因此希尔排序在时间效率上比前两种方法有
     * 较大提高。步长的选择是希尔排序的重要部分。只要最终步长为1任何步长序列都可以工作。
     */
    public static void shellSort(int arr[]) {
        int increment;
        for (increment = arr.length / 2; increment > 0; increment /= 2){
            //增量之后进行直接插入排序
            for (int j = increment; j < arr.length; j++){
                if (arr[j] < arr[j - increment]){
                    int temp = arr[j];
                    int k = j - increment;
                    while (k >= 0 && arr[k] > temp){
                        arr[k + increment] = arr[k];
                        k -= increment;
                    }
                    arr[k + increment] = temp;
                }
            }
        }
    }

    /*
     * 5.直接选择排序,思想就是从第一个元素开始遍历数组,找到数组中的最小元素跟第一个元素交换
     * 位置,然后接着从第二个元素开始重复刚才的过程,直到最后一个元素,跟冒泡不同,直接选择排序
     * 是每一次遍历只交换一次元素,而冒泡则是只要发现当前元素比前面的元素小就要交换位置。
     */
    public static void selectionSort(int arr[]) {
        int min;//记录最小元素的索引位置
        int temp;
        for (int i = 0; i < arr.length - 1; i++){
            min = i;
            for (int j = i + 1; j < arr.length; j++){
                if (arr[j] < arr[min]){
                    min = j;
                }
            }
            temp = arr[i];
            arr[i] = arr[min];
            arr[min] = temp;
        }
    }

    /*
     * 6.堆排序,升序构建最大堆(父大于子),
     * 首先,构建最大堆buildMaxHeap();需要借助筛选函数heapScreen();
     * 其次,将堆顶元素跟堆得最后一个元素交换位置(最大值放后边)
     * 
     */
    //n为构建堆的节点总数
    public static void buildMaxHeap(int arr[], int n) {
        //1.构建最大堆
        for (int i = (n - 1) / 2; i >= 0; i--){//从最后一个非叶子结点开始筛选 i = (n - 1) / 2
            heapScreen(arr, i, n);
        }
    }
    //筛选,即调整元素位置,使之满足最大堆的性质,i为开始节点,n为节点总数 
    public static void heapScreen(int arr[], int i, int n) {
        int temp = arr[i];
        int j = 2 * i + 1;//左孩子
        while (j < n){
            if (j + 1 < n && arr[j] < arr[j + 1])
                j++;
            if (arr[j] <= temp)
                break;
            arr[i] = arr[j];
            i = j;
            j = 2 * i + 1;
        }
        arr[i] = temp;
    }

    public static void heapSort(int arr[]) {
        for (int i = arr.length; i > 0; i-- ){
            buildMaxHeap(arr,i);
            System.out.println(arr[0]);
            //注意:这里交换元素不能用swap函数,这涉及到引用传递的问题。详情见博客
            int temp = arr[0];
            arr[0] = arr[i - 1];
            arr[i - 1] = temp;

        }
    }

    /*7、归并排序
     * 步骤:先递归拆分(sort),然后合并(merge),排序在合并中实现
     */
    public static void mergeSort(int arr[]){
        sort(arr, 0, arr.length - 1);
    }

    public static void sort(int arr[], int low, int high) {
        if (low < high){
            int mid = (low + high) / 2;
            sort(arr, 0, mid);
            sort(arr, mid + 1, high);
            merge(arr, low, mid, high);
        }
    }

    public static void merge(int arr[], int low, int mid, int high) {
        int i = low;
        int j = mid + 1;
        int temp[] = new int[arr.length];//定义长度为arr.length的数组是为了下标能跟arr对上
        int k = low;//临时数组temp的下标
        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 n = low; n <= high; n++)
            arr[n] = temp[n];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值