常见的算法排序(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++
【洛谷 P1223】排队接水(贪心算法+结构体排序)
该问题要求安排$n$个人的排队顺序以最小化平均等待时间。每个人接水需时$T_i$,解决方案是让接水时间短的人优先。给定$n\leq1000$和$t_i\leq10^6$,代码示例使用C++实现,通过排序使时间从小到大排列,然后计算平均等待时间。样例输入为10个人的时间数组,输出为优化后的排队顺序及平均等待时间(291.90)。
53 0
|
3月前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
8天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
49 8
|
8天前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
36 7
|
1月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
49 9
|
1月前
|
算法 搜索推荐 Java
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
基数排序是一种稳定的排序算法,通过将数字按位数切割并分配到不同的桶中,以空间换时间的方式实现快速排序,但占用内存较大,不适合含有负数的数组。
23 0
数据结构与算法学习十三:基数排序,以空间换时间的稳定式排序,速度很快。
|
1月前
|
算法
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
❤️算法笔记❤️-(每日一刷-83、删除排序链表中的重复项)
30 0
|
1月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
68 0
|
3月前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
39 1
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
3月前
|
算法 搜索推荐 Java
算法实战:手写归并排序,让复杂排序变简单!
归并排序是一种基于“分治法”的经典算法,通过递归分割和合并数组,实现O(n log n)的高效排序。本文将通过Java手写代码,详细讲解归并排序的原理及实现,帮助你快速掌握这一实用算法。
41 0