排序算法总结

Published: 29 Mar 2016 Category: 技术
package com.coolrandy;
import java.util.Random;

/**
 * Created by admin on 2016/3/29.
 */
public class BaseSort {

    public static class Node{
        int data;
        Node next;

        public Node(int data) {
            this.data = data;
            this.next = null;
        }
    }

    /**
     * 冒泡排序
     * @param a
     */
    public static void bubbleSort(int[] a){
        int length = a.length;
        boolean flag = true;
        for (int i = 0; i < length-1 && flag; i++){
            flag = false;
            for (int j = 0; j < length-1-i; j++){

                if(a[j] > a[j+1]){
                    int temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp;

                    flag = true;
                }
            }

            if (!flag){
                return;
            }
        }
    }

    /**
     * 对于快排,如果采用固定枢轴值,比如取第一个元素,那么如果输入的序列是随机的,处理时间可以接受,但是如果数组已经有序
     * 无论是升序还是降序,以及重复数组,这样的分割都不好   因为每次划分只能使待排序序列减一,此时为最坏情况,
     * 快速排序沦为起泡排序,时间复杂度为Θ(n^2)  所以对于输入数据有序或部分有序的情况,应避免使用第一个元素作为枢轴值
     *
     * 可以采用示例所示的随机化处理取枢轴值,这样对于有序的情况效果基本不错,但是对于大量重复值的数组效果依然很糟糕,接近Θ(n^2)
     * 实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。
     *
     * 三数取中 使用左端、右端和中心位置上的三个元素的中值作为枢纽元  但依然处理不了重复数组问题
     * 对待排序序列中low、mid、high三个位置上数据进行排序,取他们中间的那个数据作为枢轴,并用0下标元素存储枢轴
     *
     * 优化1、当待排序序列的长度分割到一定大小后,使用插入排序
     * 对于很小和部分有序的数组,快排不如插排好
     * 截止范围:待排序序列长度N = 10,虽然在5~20之间任一截止范围都有可能产生类似的结果,这种做法也避免了一些有害的退化情形
     *
     * @param a
     * @param low
     * @param high
     * @return
     */
    public static int partition(int[] a, int low, int high){

//        int pivot = a[low];//采用数组第一个元素作为枢轴值
        int arr = low + (new Random().nextInt(high-low+1));//随机化生成一个枢轴值下标
        System.out.println(arr);

        int temp = a[low];
        a[low] = a[arr];
        a[arr] = temp;

        int pivot = a[low];

        while (low < high){

            while (low < high && a[high] > pivot){
                high--;
            }
            a[low] = a[high];

            while (low < high && a[low] < pivot){
                low++;
            }
            a[high] = a[low];
        }
        a[low] = pivot;
        return low;
    }

    public static void quickSort(int[] a, int low, int high){

        if (low < high){
            if (high - low + 1 < 10) {//采用插排
                insertSort(a);
                return;
            }else {
                int pivot = partition(a, low, high);
                quickSort(a, low, pivot-1);
                quickSort(a, pivot+1, high);
            }
        }
    }

    /*函数作用:取待排序序列中low、mid、high三个位置上数据,选取他们中间的那个数据作为枢轴*/
    int SelectPivotMedianOfThree(int arr[],int low,int high)
    {
        int mid = low + ((high - low) >> 1);//计算数组中间的元素的下标

        //使用三数取中法选择枢轴
        if (arr[mid] > arr[high])//目标: arr[mid] <= arr[high]
        {
            swap(arr, mid, high);
        }
        if (arr[low] > arr[high])//目标: arr[low] <= arr[high]
        {
            swap(arr, low, high);
        }
        if (arr[mid] > arr[low]) //目标: arr[low] >= arr[mid]
        {
            swap(arr, mid, low);
        }
        //此时,arr[mid] <= arr[low] <= arr[high]
        return arr[low];
        //low的位置上保存这三个位置中间的值
        //分割时可以直接使用low位置的元素作为枢轴,而不用改变分割函数了
    }

    public static void  swap(int[] arr, int a, int b){

        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;

    }

    /**
     * 插入排序
     * @param a
     */
    public static void insertSort(int[] a){

        int i = 0, j = 0;
        int temp = 0;
        for (i = 1; i < a.length; i++){
            temp = a[i];
            j = i;
            while (j > 0 && temp < a[j-1]){
                a[j] = a[j-1];
                j--;
            }
            a[j] = temp;
        }
    }

    /**
     * 希尔排序  在插入排序的基础上的改进
     * @param a
     */
    public static void shellSort(int[] a){

        int i = 0, j = 0;
        int length = a.length;
        int temp = 0;
        int k = length / 2;//增量由1变为length/2
        while (k > 0){

            for (i = k; i < length; i += k){
                temp = a[i];
                j = i;
                while (j > k && temp < a[j - k]){

                    a[j] = a[j-k];
                    j = j - k;
                }
                a[j] = temp;
            }

            k = k / 2;
        }

    }

    /**
     * 选择排序
     * @param a
     */
    public static void selectSort(int[] a){

        int length = a.length;
        for (int i = 0; i < length-1; i++){

            int min = i;
            for (int j = i; j < length; j++){

                if (a[j] < a[min]){
                    swap(a, j, min);
                }
                if (min != i){
                    swap(a, min, i);
                }
            }
        }
    }

    /**
     * 堆排序  思路比较简单:1、采用下沉的方式移动节点
     * @param a
     * @param k  注意:k从0开始和从1开始时不一样的,要注意
     * @param length
     */
    public static void adjustDown(int[] a, int k, int length){

        int left = getLeftChildIndex(k);
        int right = getRightChildIndex(k);
        int largest = k;
        if (left < length && a[k] < a[left]){
            largest = left;
        }

        if (right < length && a[largest] < a[right]){
            largest = right;
        }

        if (largest != k){
            int temp = a[k];
            a[k] = a[largest];
            a[largest] = temp;
            adjustDown(a, largest, length);
        }

    }

    /**
     * 建最大推
     * @param
     */
    public static void buildMaxHeap(int[] a){

        int index = getParentIndex(a.length-1);
        for (int i = index; i >= 0; i--){

            adjustDown(a, i, a.length);
        }
    }


    public static void heapSort(int[] a){

        buildMaxHeap(a);
        for (int i = a.length-1; i > 0; i--){
            int temp = a[0];
            a[0] = a[i];
            a[i] = temp;
            adjustDown(a, 0, i);
        }
    }

    public static int getParentIndex(int current){
        return (current - 1) >> 1;
    }

    public static int getLeftChildIndex(int current){

        return (current << 1) + 1;
    }

    public static int getRightChildIndex(int current){

        return (current << 1) + 2;
    }

    private static int[] sort = new int[]{1,0,10,20,3,5,6,4,9,8,12,17,34,11};
    public static void main(String[] args){

        int[] a = new int[]{2, 7, 5, 19, 24, 15, 13, 20};

//        bubbleSort(a);
//        quickSort(a, 0, 7);
//        insertSort(a);
//        shellSort(a);
//        selectSort(a);
        heapSort(sort);
        for (int temp: sort){
            System.out.print(temp + " ");
        }
    }

}

comments powered by Disqus

About me

面朝大海,春暖花开。哈喽,大家好,我是Randy!