七种基于比较的排序算法

一、直接插入排序

	/**
     * 直接插入排序,时间复杂度最好为O(N),最坏为O(N^2),空间复杂度为O(1)
     * 数组里的哪一个值大就把该值赋给arr[j+1]
     * 数据越有序,时间效率越高
     * 属于稳定排序
     * @param arr
     */
    public void insertSort1(int[] arr){
        for (int i = 1; i < arr.length; i++) {
            int val = arr[i];
            int j = i-1;
            //谁大把谁赋值给arr[j+1];
            for (; j >= 0 && arr[j]>val; j--) {
                arr[j+1] = arr[j];
            }
            arr[j+1] = val;
        }
    }

二、希尔排序

	/**
     * 希尔排序,时间复杂度最好为O(N),最坏是O(N^2),空间复杂度为O(1)
     * 循环分组,当gap>1时候,使用直接插入排序来使数组趋于有序,循环结束之后在使用一次直接插入排序完成这次希尔排序
     * 稳定性:这是不稳定排序
     * @param arr
     */
    public void shellSort(int[] arr){
        int gap = arr.length;
        while (gap>1){
            inserSorth(arr,gap);
            gap = (gap/3)+1;
        }
        inserSorth(arr,gap);
    }
    private void inserSorth(int[] arr,int gap){
        for (int i = 1; i < arr.length; i++) {
            int val = arr[i];
            int j = i -gap;
            for (; j >= 0 && arr[j] > val; j -= gap) {
                arr[j+gap] = arr[j];
            }
            arr[j+gap] = val;
        }
    }

三、选择排序

	/**
     * 选择排序,时间复杂度最好为O(N^2),空间复杂度为O(1)
     * 从无序区间选出最大的值放到有序区间,知道无序区间走完则循环结束,排序完成
     * 稳定性:不稳定
     * @param arr
     */
    public void selectSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            int max = 0;
            for (int j = 1; j < arr.length -i; j++) {
                if(arr[j] > arr[max]){
                    max = j;
                }
            }
            int tmp = arr[max];
            arr[max] = arr[arr.length -i -1];
            arr[arr.length -i -1] = tmp;
        }
    }

四、堆排序

/**
     * 堆排序,时间复杂度,最好和最坏都为O(N*logN);空间复杂度为O(1).
     * 向下调整:首先计算index下标左孩子下标left,判断下标left是否小于堆中元素个数,小于则进入循环,
     * 然后判断index又孩子下标是否小于size,在比较左右孩子下标所对应的值,把值大的下表给MAX;
     * 然后判断arr[max]与arr[index]的大小关系,后者大则跳出循环,否则将两者的值调换,然后让index指向MAX,left指向2*index+1;
     * 稳定性:不稳定
     * @param arr
     */
    public void heapSort(int[] arr){
        createHeap(arr);
        for (int i = 0; i < arr.length-1; i++) {
            swap(arr,arr.length-i-1,0);
            shiftDown(arr,arr.length-i-1,0);
        }

    }
    public void swap(int[] arr,int i,int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    //建一个小堆
    public void createHeap(int[] arr){
        for (int i = (arr.length-1)/2; i>= 0; i--) {
            shiftDown(arr,arr.length,i);
        }
    }
    public void shiftDown(int[] arr,int size,int index){
        int left = 2*index +1;
        while(left<size){
            int max = left;
            int right = 2*index+2;
            if(right < size){
                if(arr[left] < arr[right]){
                    max = right;
                }
            }
            if(arr[index] >= arr[max]){
                break;
            }

            int tmp = arr[index];
            arr[index] = arr[max];
            arr[max] = tmp;

            index = max;
            left = 2*index +1;
        }
    }

五、冒泡排序

/**
     * 冒泡排序:时间复杂度最好和最坏都为O(N^2),空间复杂度为O(1);
     * 将最大的值冒泡到数组最后,直到数组走完,排序结束;
     * 稳定性:稳定
     * @param arr
     */
    public void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if (arr[j]>arr[j+1]){
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
    }

    /**
     * 优化冒泡排序:时间复杂度最好为O(N),最坏都为O(N^2),空间复杂度为O(1);
     * 在循环过程中加入一个boolean变量来检验排序是否完成;
     * 稳定性:稳定
     */
    public void optimizeBubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            boolean flg = false;
            for (int j = 0; j < arr.length-1-i; j++) {
                if (arr[j]>arr[j+1]){
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                    flg = true;
                }
            }
            if (flg == false){
                break;
            }
        }
    }

六、快速排序

/**
     *
     * 快速排序:时间复杂度最好为O(N*logN),最坏为O(N^2),空间复杂度最好为O(logN),最坏为O(N);
     * 从待排序区间选择一个数,作为基准值(index);
     * Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
     * 稳定性:不稳定
     * @param arr
     */
    public void quickSort(int[] arr) {
        quickSortInternal(arr,0,arr.length-1);
    }
    private void quickSortInternal(int[] arr,int left,int right){
        if(left == right){
            return;
        }
        if(left > right){
            return;
        }
        int index = partition(arr,left,right);
        quickSortInternal(arr,left,index -1);
        quickSortInternal(arr,index +1,right);
    }
    private int partition(int[] arr, int left, int right){
        int i = left;
        int j = right;
        int value = arr[left];
        while (i < j){
            while (i<j && arr[j]>=value){
                j--;
            }
            arr[i] = arr[j];
            while (i<j && arr[i] <= value){
                i++;
            }
            arr[j] = arr[i];
        }
        arr[i] = value;
        return i;
    }

    /**
     * 快速排序的非递归实现
     * 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。
     * 稳定性:不稳定
     * @param arr
     */
    public void quickSortH(int[] arr) {
        Stack<Integer> stack = new Stack<>();
        stack.push(arr.length - 1);
        stack.push(0);
        while (!stack.isEmpty()) {
            int left = stack.pop();
            int right = stack.pop();
            if (left >= right) {
                continue;
            }
            int index = partition(arr, left, right);
            stack.push(right);
            stack.push(index + 1);
            stack.push(index - 1);
            stack.push(left);
        }
    }

七、归并排序

/**
     * 归并排序:最好和最坏时间复杂度都为O(N*logN),空间复杂度为O(N);
     * 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。
     * 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
     * 稳定性:稳定
     * @param array
     */
    public void mergeSort(int[] array) {
        for (int i = 1; i < array.length; i = i * 2) {
            for (int j = 0; j < array.length; j = j + 2 * i) {
                int low = j;
                int mid = j + i;
                if (mid >= array.length) {
                    continue;
                }
                int high = mid + i;
                if (high > array.length) {
                    high = array.length;
                }
                merge(array, low, mid, high);
            }
        }
    }
    private void merge(int[] array, int low, int mid, int high) {
        int i = low;
        int j = mid;
        int length = high - low;
        int[] extra = new int[length];
        int k = 0;
        while (i < mid && j < high) {
            if (array[i] <= array[j]) {
                extra[k++] = array[i++];
            } else {
                extra[k++] = array[j++];
            }
        }
        while (i < mid) {
            extra[k++] = array[i++];
        }
        while (j < high) {
            extra[k++] = array[j++];
        }
        for (int t = 0; t < length; t++) {
            array[low + t] = extra[t];
        }
    }

七种基于比较的排序算法_第1张图片

你可能感兴趣的:(java,算法)