常见的算法排序(2)

简介: 常见的算法排序(2)

🚄1 快速排序

🚅1.1 快排原理

1 从待排序区间选择一个数,作为基准值

2 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;

3 采用分治思想对左右两个小区间,对左右两个小区间按照同样的方式来处理,直到小区间的长度==1,那么表面已经有序,如果长度为零,则说明没有数据!


🚈1.2 递归实现

通过了解快排的原理,那么就可以编写如下代码(我们一开始以数列中第一个数为基准值,寻找基准在数列中所在的位置):

public class TestDemo1 {
    public static void main(String[] args) {
        int[] array = {67,7,32,98,1,0,45,23,234,6746,123};
        Quack(array);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 快排递归写法
     * 时间复杂度: 最好 O(N*logN) 最差(有序) O(N*N)
     * 空间复杂度: O(logN) 
     * 稳定性:不稳定
     * @param array 待排序数列
     */
    public static void Quack(int[] array){
        QuackSort(array,0,array.length-1);
    }
    public static void QuackSort(int[] array,int left,int right){
        //递归的终止条件,当左等于大于右时,说明此时序列有序
        if(left>=right){
            return;
        }
        //找基准
        int privot = getprivot(array,left,right);
        //递归左边
        QuackSort(array,left,privot-1);
        //递归右边
        QuackSort(array,privot+1,right);
    }
    public static int getprivot(int[] array,int start,int end){
        int tmp = array[start];
        while (start<end){
            while (start<end&&array[end]>=tmp){
                end--;
            }
            array[start]=array[end];
            while (start<end&&array[start]<=tmp){
                start++;
            }
            array[end]=array[start];
        }
        array[start]=tmp;
        return start;
    }
}

🚝1.3 对快排进行优化(三数取中法)

对于快排的优化,其实就是优化基准:

public class TestDemo1 {
    public static void main(String[] args) {
        int[] array = {67,7,32,98,1,0,45,23,234,6746,123};
        Quack(array);
        System.out.println(Arrays.toString(array));
    }

    /**
     * 快排递归写法
     * 时间复杂度: 最好 O(N*logN) 最差(有序) O(N*N)
     * 空间复杂度: O(logN)
     * 稳定性:不稳定
     * @param array
     */
    public static void Quack(int[] array){
        QuackSort(array,0,array.length-1);
    }
    public static void Swap(int[] array,int i,int j){
        int tmp = array[i];
        array[i]=array[j];
        array[j]=tmp;
    }
    public static int getMid(int[] array,int a,int b){
        int mid = a+((b-a)>>>1);
        if(array[a]>array[b]){
            if(array[mid]>array[a]){
                return a;
            }else if(array[mid]<array[b]){
                return b;
            }else{
                return mid;
            }
        }else{//array[a]<array[b]
            if(array[mid]<array[a]){
                return a;
            }else if(array[mid]>array[b]){
                return b;
            }else{
                return mid;
            }
        }
    }
    public static void QuackSort(int[] array,int left,int right){
        //递归的终止条件,当左等于大于右时,说明此时序列有序
        if(left>=right){
            return;
        }
        //获取三个值中间值的小标
        int mid = getMid(array,left,right);
        //在把中间值放到一开始的位置
        Swap(array,left,mid);
        //找基准
        int privot = getprivot(array,left,right);
        //递归左边
        QuackSort(array,left,privot-1);
        //递归右边
        QuackSort(array,privot+1,right);
    }
    public static int getprivot(int[] array,int start,int end){
        int tmp = array[start];
        while (start<end){
            while (start<end&&array[end]>=tmp){
                end--;
            }
            array[start]=array[end];
            while (start<end&&array[start]<=tmp){
                start++;
            }
            array[end]=array[start];
        }
        array[start]=tmp;
        return start;
    }
}

优化总结:

1 快排的优化实质上就是在对基准进行优化,所以这里采用了三数取中法进行优化

2 可以结合我们之前所学的直接插入排序进行优化,对于插入排序,之前已经了解到数列越有序越快,那么就可以当调整的长度小于某个数的时候,可以直接利用直接插入排序

🚃1.4 非递归实现

对于非递归的实现,我们此时还是一样根据原理需要找到基准值,然后再利用数据结构中栈去解决(核心的思想也是利用找基准去解决):

代码如下:

  //非递归实现
    public static void nonQuackSort(int[] array){
        int start = 0;
        int end = array.length-1;
        Stack<Integer> stack = new Stack<>();
        //找基准
        int privot = getprivot(array,start,end);
        //确保右边至少有两个可排序的数,否则就是只有一个数,就是有序的
        if(privot-1>start){
            stack.push(start);
            stack.push(privot-1);
        }
        //确保左边至少有两个可排序的数,否则就是只有一个数,就是有序的
        if(privot+1<end){
            stack.push(privot+1);
            stack.push(end);
        }
        while (!stack.isEmpty()){
            end=stack.pop();
            start=stack.pop();
            privot = getprivot(array,start,end);
            if(privot-1>start){
                stack.push(start);
                stack.push(privot-1);
            }
            if(privot+1<end){
                stack.push(privot+1);
                stack.push(end);
            }
        }
    }

🚋二 归并排序

🚌2.1 归并的核心思想

给定两个有序数组,那么如何将他们合并成为一个有序的数组呢?其实在合并的过程中就体现出归并排序的初步思想原理,就是依据这样的一个思想。

代码如下:

    public static int[] conbine(int[] array1,int[] array2){
        //创建一个新的数组来存储合并之后的数据
        int[] array = new int[array1.length+array2.length];
        //记录合并数组的下标
        int i = 0;
        //第一个数组的第一个下标
        int s1 = 0;
        //第一个数组的最后一个下标
        int e1 = array1.length-1;
        //第二个数组的第一个下标
        int s2 = 0;
        //第二个数组的最后一个下标
        int e2 = array2.length-1;
        //将两个数组中的数据按照从小到大放入新的数组中
        while (s1<=e1&&s2<=e2){
            if(array1[s1]<array2[s2]){
                array[i++]=array1[s1++];
            }else{
                array[i++]=array2[s2++];
            }
        }
        //可能存在第一个数组没放完或者第二个数组的数据没放完
        while (s1<=e1){
            array[i++]=array1[s1++];
        }
        while (s2<=e2){
            array[i++]=array2[s2++];
        }
        return array;
    }

🚎2.2 归并排序的递归实现

    public static void mergeSort(int[] array){
        merge(array,0,array.length-1);
    }

    public static void merge(int[] array,int low,int high){
        int mid = low+((high-low)>>>1);
        //递归的终止条件
        if(low>=high){
            return;
        }
        //左边递归进行分解
        merge(array,low,mid);
        //右边递归进行分解
        merge(array,mid+1,high);
        //开始归并
        Conbine(array,low,mid,high);
    }
  //归并的核心思想
    public static void Conbine(int[] array,int low,int mid,int high){
        int[] tmp = new int[high-low+1];
        int i = 0;
        int s1 = low;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = high;
        while (s1<=e1&&s2<=e2){
            while (s1<=e1&&s2<=e2){
                if(array[s1]<array[s2]){
                    tmp[i++]=array[s1++];
                }else{
                    tmp[i++]=array[s2++];
                }
            }
            //可能存在第一个数组没放完或者第二个数组的数据没放完
            while (s1<=e1){
                tmp[i++]=array[s1++];
            }
            while (s2<=e2){
                tmp[i++]=array[s2++];
            }
        }
        for (int j = 0; j < i; j++) {
            //注意数组下标,当遇到右边数组合并时,它的第一个下标已经不是零了
            array[j+low]=tmp[j];
        }
    }

🚍2.3 归并排序的非递归实现

非递归排序,所采用的思想就是先分组,先是一个一个一组,在变成两个一组,最后整个数组为一组时,此时就是一个有序的数组。

    public static void nonmergeSort(int[] array){
        //组数(一开始一个一组)
        int gap = 1;
        //只有组数大于等于数组的长度,那么此时说明数组已经有序
        while (gap<array.length){
            //每重新分组,遍历一遍数组,进行归并排序
            for (int i = 0; i < array.length-1; i+=2*gap) {
                int left = i;
                int mid = left+gap-1;
                //注意这时mid可能会越界
                if (mid>=array.length){
                    mid=array.length-1;
                }
                int right = mid+gap;
                if(right>=array.length){
                    right=array.length-1;
                }
                //开始归并
                Conbine(array,left,mid,right);
            }
            //循环结束,组数乘2
            gap=gap*2;
        }
    }
    public static void Conbine(int[] array,int low,int mid,int high){
        int[] tmp = new int[high-low+1];
        int i = 0;
        int s1 = low;
        int e1 = mid;
        int s2 = mid+1;
        int e2 = high;
        while (s1<=e1&&s2<=e2){
            while (s1<=e1&&s2<=e2){
                if(array[s1]<array[s2]){
                    tmp[i++]=array[s1++];
                }else{
                    tmp[i++]=array[s2++];
                }
            }
            //可能存在第一个数组没放完或者第二个数组的数据没放完
            while (s1<=e1){
                tmp[i++]=array[s1++];
            }
            while (s2<=e2){
                tmp[i++]=array[s2++];
            }
        }
        for (int j = 0; j < i; j++) {
            //注意数组下标,当遇到右边数组合并时,它的第一个下标已经不是零了
            array[j+low]=tmp[j];
        }
    }

🚗三 其他排序(非基于比较)

🚖3.1 计数排序

计数排序详解

🚘3.2 基数排序

基数排序详解

🚔3.3 桶排序

桶排序详解

🚉4 总结

可以通过一个表格列举出这些排序的特点,根据排序的需求,选择合适的排序方式!

目录
相关文章
|
5天前
|
人工智能 算法 测试技术
【数学】【排序】【C++算法】3027人员站位的方案数
【数学】【排序】【C++算法】3027人员站位的方案数
|
5天前
|
人工智能 算法 BI
【优选算法专栏】专题十八:BFS解决拓扑排序(一)
【优选算法专栏】专题十八:BFS解决拓扑排序(一)
21 0
|
5天前
|
算法
【优选算法专栏】专题十八:BFS解决拓扑排序--前言
【优选算法专栏】专题十八:BFS解决拓扑排序--前言
22 1
|
5天前
|
算法 搜索推荐 索引
数据结构与算法 排序(下)
数据结构与算法 排序(下)
13 1
|
5天前
|
缓存 算法 搜索推荐
数据结构与算法 排序(上)
数据结构与算法 排序(上)
11 0
|
5天前
|
算法 调度
【问题探讨】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究
【问题探讨】基于非支配排序的蜣螂优化算法NSDBO求解微电网多目标优化调度研究
|
5天前
|
搜索推荐 C语言
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
11 0
|
5天前
|
算法
讲课:拓扑排序、最短路算法
讲课:拓扑排序、最短路算法
|
5天前
|
算法 测试技术 C#
【模拟】【C++算法】2826. 将三个组排序
【模拟】【C++算法】2826. 将三个组排序
|
5天前
|
存储 搜索推荐 算法
【数据结构】八大排序之计数排序算法
【数据结构】八大排序之计数排序算法
13 4