堆排和快排比较 为什么在同样空间复杂度下快排相对更快

其实在比较排序的情况下  所有的下界都是O(nlogn)

而为什么 在相同的空间复杂度的情况下  快排的速度要比堆排快呢?

因为所有的空间复杂度都砍掉了常系数    如果一个1*nlongn  一个 1000*nlongn   谁快谁慢一目了然

为什么堆排的常系数高呢?

首先堆排先建立大根堆 (小根堆)   建立好之后最顶元素是最大(最小)

第二步 让最顶元素与末尾位置元素进行交换 ,之后排除末尾元素 再建立大根堆 找出次大元素。以此类推直至最后

那么让堆排降速的远洋就出现在第二步,快排每一次排序都是让目标元素向正确位置逼近(分治方法),而堆排一旦交换

元素之后,可以想象产生了多少无用的比较(无用的比较指的是:你末尾位置元素基本可以肯定比你的根的左右孩子元素中的一个小),这样交换后,再次建立大根堆(小根堆)时并没有使得你的目标元素靠近真确位置,反而增加了无用比较。

 //堆排序
    //空间复杂度 O(nlbn)
    //时间复杂度 O(1)
    //不稳定
    public static void  heapSort(int[] array){
        buildMaxHeap(array);
        for (int i = 0; i < array.length; i++){
            int tmp = array[0];
            array[0] = array[array.length-1-i];
            array[array.length-1-i] = tmp;
            adjust(array,0,array.length-1-i);
        }
    }
    private static void buildMaxHeap(int[] array){
        for (int i = array.length/2 - 1; i >=0; i--){
            adjust(array,i,array.length);
        }
    }

    private static void adjust(int[] array,int start,int length){
        int tmp = array[start];
        int i;
        for ( i = start*2+1; i < length; i = i*2+1) {
            if (i < length-1 && array[i+1] > array[i]){
                i++;
            }
            if (array[i] <= tmp){
                break;
            }else {
                array[start] = array[i];
                start = i;
            }
        }
        array[start] = tmp;
    }
   
    //快排
    //时间复杂度O(nlbn)
    //空间复杂度O(lbn)
    //不稳定
    public static void quickSort1(int[] array){
        quick(array,0,array.length-1);
    }

    private static int selectPivot(int[] array, int low, int high){
        int tmp = array[low];
        while (low < high){
            while (low < high && array[high] >= tmp){
                high--;
            }
            if (low == high){
                break;
            }else {
                array[low] = array[high];
            }
            while (low < high && array[low] <= tmp){
                low++;
            }
            if(low == high){
                break;
            }else {
                array[high] = array[low];
            }
        }
        array[low] = tmp;
        return low;
    }
    private static void swap(int[] array, int low, int high){
        int tmp = array[low];
        array[low] = array[high];
        array[high] = tmp;
    }
    private static void medianOfThree(int[] array, int low, int high){
        int mid = (low + high)/2;
        // array[mid] < array[low] < array[high]
        if (array[low] > array[high]){
            swap(array,low,high);
        }
        if (array[mid] > array[high]){
            swap(array,mid,high);
        }
        if (array[low] < array[mid]){
            swap(array,low,mid);
        }
    }
    private static void quick(int[] array,int low, int high){
        //尾递归的形式  递归只要分支庞大
        /*从时间和空间效率上看,尾递归和传统递归差不多。递归运算效率低主要是分支巨大,像阶乘这类单分支的递归,效率并不低。递归运算的深度和运算总量大致成指数关系,return多次并不会造成显著的性能损失。
        一言以蔽之,传统递归越深,距离目标越近;尾递归越深,距离起点越远。
        尾递归适用于运算对当前递归路径有依赖的问题,传统递归适用于运算对更深层递归有依赖的问题。*/
        int par;
        while(low < high){
            par = selectPivot(array, low, high);
            quick(array, low, par - 1);
            low = par + 1;
        }
/*        if (low >= high){
            return;
        }
        //优化 三数取中法
        medianOfThree(array,low,high);
        int par = selectPivot(array, low,high);
        if (low < par-1){
            quick(array,low,par-1);
        }
        if (par < high-1){
            quick(array,par+1,high);
        }*/
    }

猜你喜欢

转载自blog.csdn.net/qq_42381855/article/details/89762347