java排序算法之堆排序,快速排序,归并排序

一:堆排序

       算法思想:首先了解什么是堆,这里对于堆的定义有两种,一种为最大堆,即父节点都大于子节点,如图一所示;另一种为最小堆,即父节点都小于子节点,如图二所示。

                                       

       用堆排序进行升序排序, 我们使用大堆来完成。我们将数组初始化成最大堆, 记录数组长度为 len, 只需将堆顶元素与 len-1 位置元素调换位置, 这样此时堆中最大元素就确定了, 此时最大值已经确定, 只需要比较剩余的, 即 len--, 再次调用adjust(arr,0,len),直到 len 等于 0 上述操作执行完毕, 整个排序也就结束了。

       如图所示即为一次调整最大堆:

代码实现:

//堆排序
    public static void adjust(int[] arr,int start, int end){//一次调整大根树
        int tmp = arr[start];
        for (int i = 2 * start + 1; i <= end; i = 2*i + 1) {
            //1.找到左右孩子最大值的下标

            if( (i < end) && (arr[i] < arr[i + 1])){
                    i++;                                  //nlog2n(以二为底N)
                }
            if(arr[i] > tmp){
                    arr[start] = arr[i];
                    start = i;
            }else if(arr[i] < tmp){
                    break;
            }
        }
        arr[start] = tmp;
    }


    public static void heapSort(int[] arr){         //nlog2n(以二为底N)   // 空间复杂O(1)
        for (int i = (arr.length - 1 - 1)/2; i >= 0; i--) {
            adjust(arr,i,arr.length - 1);
        }

        for (int i = 0; i < arr.length - 1; i++) {//交换根节点与孩子节点
            int temp = arr[arr.length - 1 - i];
            arr[arr.length - 1 - i] = arr[0];
            arr[0] = temp;
            //length - 1 - i - 1 有序之后,不需要调整最后一个有序数据
            adjust(arr,0,arr.length - 1 - i - 1);
        }
    }

二:快速排序

       基本思想:设置两个搜索指针 low 和 high, 它们分别指向首尾, 一般将 low 位置元素设置为支点元素, 从 high 位置开始搜索比支点小的记录, 并将其交换到 low 位置处, low 向后移动一个位置, 然后从 low 位置开始搜索比支点大的位置, 并将其交换到 high 位置处,high 向前移动一个位置如此继续, 直到 low 和 high 相等结束, 这时支点前面的数全小于它, 后面全比它大, 然后将支点前面和后面的序列继续进行排序, 直到完成排序。

一次快排过程如图所示:

代码实现:

//时间复杂度 logN

    //一次快速排序(递归实现) 时间复杂度N
    public static int partion(int[] arr,int low,int hight){
        int temp = arr[low];
        while(low < hight){
            while (low < hight && arr[hight] >= temp){
                hight--;
            }
            if(low == hight){
                break;
            }else{
                arr[low] = arr[hight];
            }

       while(low < hight && arr[low] <= temp){
                low++;
            }
            if(low == hight){
                break;
            }else{
                arr[hight] = arr[low];
            }
        }

        arr[low] = temp;
        return low;
    }

    public static void quick(int[] arr,int start,int end){

        if(end - start + 1 <= 16){
            insert1(arr,start,end);
        }
        //三数取中法大大减少递归次数
        //meedofThree(arr,start,end);


        int par = partion(arr,start,end);

        //找左边是否有两个数据以上
        if(par > start + 1){
            quick(arr,start,par - 1);
        }
        //找右边是否有两个数据以上
        if(par < end - 1){
            quick(arr,par + 1,end);
        }
    }

    //空间复杂度为N   时间复杂度N * logN
    public static void quickSort(int[] arr){

        quick(arr,0,arr.length -1);
    }

非递归代码实现:

//快排非递归实现(使用栈完成)
    public static void quickUnRecursion(int[] arr){
        int[] stack = new int[arr.length * 2];
        int top = 0;
        int low = 0;
        int high = arr.length - 1;
        //先进行一次快排
        int par = partion(arr,low,high);
        //1.判断当前par左右两边是否有两个数据以上
        if(par > low + 1){
            stack[top++] = low;
            stack[top++] = par - 1;
        }
        if(par < high - 1){
            stack[top++] = par + 1;
            stack[top++] = high;
        }
        //以上代码执行完毕,两边的数对已将全部入栈
        //判断栈是否为空,不为空取出两个数对,进行partion()
        while(top > 0){
            high = stack[--top];
            low = stack[--top];
            par = partion(arr,low,high);
            if(par > low + 1){
                stack[top++] = low;
                stack[top++] = par - 1;
            }
            if(par < high - 1){
                stack[top++] = par + 1;
                stack[top++] = high;
            }
        }
    }

三:归并排序

       基本思想: 分而治之(divide - conquer);每个递归过程涉及两个步骤。第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素。第二, 合并: 合并两个排好序的子序列,生成排序结果。

过程如下图:

代码实现:

//归并排序(使用分治算法)
    public static void mergeSort(int[] arr,int start,int end){
        if(start == end){
            return;
        }
        int mid = (start + end) / 2;
        mergeSort(arr,start,mid);
        mergeSort(arr,mid+1,end);
        //合并的过程,此时一定为一个有序序列
        merge(arr,start,mid,end);
    }

    public static void merge(int[] arr,int start,int mid,int end){
        int[] str = new int[arr.length];
        int index = start;
        int start2 = mid + 1;
        int i = start;
        while(start <= mid && start2 <= end){
            if(arr[start] <= arr[start2]){
                str[index++] = arr[start++];
            }else{
                str[index++] = arr[start2++];
            }
        }
        while(start <= mid){
            str[index++] = arr[start++];
        }
        while(start2 <= end){
            str[index++] = arr[start2++];
        }
        while(i <= end){
            arr[i] = str[i];
            i++;
        }
        System.out.println(Arrays.toString(arr));
    }

猜你喜欢

转载自blog.csdn.net/lin140611/article/details/90076082