排序算法总结

Posted Al_tair

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法总结相关的知识,希望对你有一定的参考价值。

排序算法总结

大家好呀!我是小笙,本节是我对排序算法的一个总结

各种排序算法

稳定性:一组数列在排序的时候,相同的值的相对位置是否发生变化

选择排序

概述:将某一个数列中最大的值或者最小的值与该数列的第一个进行交换,然后缩小数列范围(不包括第一个)依次反复则可以排好序

时间复杂度:o(n^2)

空间复杂度:o(1)

public class SelectionSort 
    public static void main(String[] args) 
        int[]nums = new int[]1,8,67,3,5;
        sort(nums);
        System.out.println(Arrays.toString(nums));
    

    /**
     * 选择排序 升序排序
     * @param nums 数组
     */
    public static void sort(int[] nums)
        int len = nums.length;
        if(nums == null || len < 2)
            return;
        else
            for (int i = 0; i < len-1; i++) 
                int minIndex = i;
                for (int j = i+1; j < len; j++) 
                    minIndex = nums[j] < nums[minIndex]? j:minIndex;
                
                int temp = nums[minIndex];
                nums[minIndex] = nums[i];
                nums[i] = temp;
            
        
    

冒泡排序

概述:类似与泡泡浮出水面,比如将最大值的值向右端浮动,浮动过程中出现左边的值大于右边的值,则需要进行交换,确保最大值最后落在最右端,依次反复

时间复杂度:o(n^2)

空间复杂度:o(1)

public class BubbleSort 
    public static void main(String[] args) 
        int[]nums = new int[]1,8,67,3,5;
        sort(nums);
        System.out.println(Arrays.toString(nums));
    

    /**
     * 冒泡排序 升序排序
     * @param nums 数组
     * 可以进行优化: 如果内循环一次发现没有发生交换操作,则可以认为已经排好序并跳出循环
     */
    public static void sort(int[] nums)
        int len = nums.length;
        if(nums == null || len < 3)
            return;
        else
            for (int i = len-1; i >= 0; i--) 
                for (int j = 0; j < i; j++) 
                    if(nums[j] > nums[j+1])
                        int temp = nums[j];
                        nums[j] = nums[j+1];
                        nums[j+1] = temp;
                    
                
            
        
    

插入排序

概述:实现很像冒泡排序,注意两次循环方向,插入排序是同向的,冒泡是反向的,插入无非就是从第二数开始,插入到前面的数列中也能保持有序,在数组上的实现也就只能是层层交换,但是如果是链表可能就更好理解什么是插入概念?

时间复杂度:o(n^2)

空间复杂度:o(1)

public class InsertSort 
    public static void main(String[] args) 
        int[]nums = new int[]1,8,67,3,5;
        sort(nums);
        System.out.println(Arrays.toString(nums));
    

    /**
     * 直接插入排序 升序
     * @param nums 数组
     */
    public static void sort(int[] nums)
        int len = nums.length;
        if(nums == null || len < 2)
            return;
        else
            for (int i = 1; i < len; i++) 
                // 注意:看起来像冒泡,但是因为数组插入的时候, ,所以通过比较前移来实现也是一样的效果
                for(int j = i;j >= 0 && nums[j] < nums[j-1];j--)
                    int temp = nums[j];
                    nums[j] = nums[j-1];
                    nums[j-1] = temp;
                
            
        
    

希尔排序

希尔排序实质上是一种分组插入方法,它的基本思想是: 对于n个待排序的数列,取一个小于n的整数step(step被称为步长)将待排序元素分成若干个组子序列,所有距离为step的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小step的值,并重复执行上述的分组和排序。重复这样的操作,当step=1时,整个数列就是有序的

时间复杂度:希尔排序的时间复杂度与增量(即,步长step的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为o(N²),而Hibbard增量的希尔排序的时间复杂度为o(N3/2)

空间复杂度:o(1)

public class ShellSort 
    // 测试
    public static void main(String[] args) 
        int a[] = 80,30,60,40,20,10,50,70;
        System.out.println(Arrays.toString(a));
        shellSort(a, a.length);
        System.out.println(Arrays.toString(a));
    
    
    /**
     * 希尔排序
     * @param a 待排序的数组
     * @param n 数组的长度
     */
    public static void shellSort(int[] a, int n) 
        // gap为步长,每次减为原来的一半。
        for (int step = n / 2; step > 0; step /= 2) 
            // 共gap个组,对每一组都执行直接插入排序
            for (int i = 0 ;i < step; i++)
                groupSort(a, n, i, step);
        
    

    /**
     * 对希尔排序中的单个组进行排序
     * @param a 待排序的数组
     * @param n 数组总的长度
     * @param i 组的起始位置
     * @param step 组的步长
     */
    public static void groupSort(int[] a, int n, int i,int step) 
        for (int j = i + step; j < n; j += step) 
            // 如果a[j] < a[j-step],则寻找a[j]位置,并将后面数据的位置都后移。
            if (a[j] < a[j - step]) 
                int tmp = a[j];
                int k = j - step;
                while (k >= 0 && a[k] > tmp) 
                    a[k + step] = a[k];
                    k -= step;
                
                a[k + step] = tmp;
            
        
    

归并排序

概述:分成2部分,分别排好序,在通过比较大小归并到统一的数组中

时间复杂度: o(nlogn)

空间复杂度:o(n)

// 思路
// 1.整体就是一个简单递归,左边排好序、右边排好序、让其整体有序
// 2.让其整体有序的过程里用了外排序方法
// 3. 利用master公式来求解时间复杂度
public class MergeSort 
    public static void main(String[] args) 
        int[]nums = new int[]1,8,67,3,5,3,4,56,67;
        // 可以选择数组的一段进行排序
        sort(nums,4,nums.length-1);
        System.out.println(Arrays.toString(nums));
    

    /**
     * 归并算法(升序排序)
     * 递归算法(分治)
     */
    public static void sort(int[] nums,int L,int R)
        if(L == R)
            return;
        else
             // 中点位置
            int mid = L + ((R-L) >> 1);
            sort(nums,L,mid);
            sort(nums,mid+1,R);
            merge(nums,L,mid,R);
        
    

    /**
     * 归并数据
     */
    public static void merge(int[] nums,int L,int M,int R)
        int[] arr = new int[R-L+1];
        // 数组的下标
        int index = 0;
        // L ~ M 的数组下标
        int p0 = L;
        // M+1 ~ R 的数组下标
        int p1 = M + 1;

        while(p0 <= M && p1 <= R)
            arr[index++] = nums[p0] > nums[p1]?nums[p1++]:nums[p0++];
        
        while(p0 <= M)
            arr[index++] = nums[p0++];
        
        while(p1 <= R)
            arr[index++] = nums[p1++];
        

        for (int i = 0; i < R-L+1; i++) 
            nums[L+i] = arr[i];
        
    


求最小数和

题目理解:就是遍历数组,依次累积左侧小于当前位置的数字

public class SmallSum 
    /**
     * 对等数法来测试归并方法的正确性
     */
    public static void main(String[] args) 
        int testNum = 5000000;
        while(testNum-- >= 0)
            int[] nums = random(10,10);
            if(SimpleSum(nums,0,nums.length-1) != mergeSort(nums,0,nums.length-1))
                System.out.println("sorry,test error!");
                return;
            
            System.out.println("测试" + (5000000 - testNum) + "组数");
        
        System.out.println("right,you are great!");
    

    /**
     * 暴力解法
     */
    public static int SimpleSum(int[] nums,int L,int R)
        int sum = 0;
        for (int i = L; i < R; i++) 
            for (int j = i+1; j <= R; j++) 
                if(nums[j] > nums[i])
                    sum += nums[i];
                
            
        
        return sum;
    

    /**
     * 归并排序的过程计算最小和
     */
    public static int mergeSort(int[] nums,int L,int R)
        if(L == R)
            return 0;
        else
            int mid = L + ((R-L) >> 1);
            return mergeSort(nums,L,mid) + mergeSort(nums,mid+1,R) + merge(nums,L,mid,R);
        
    

    /**
     * 归并数据
     */
    public static int merge(int[] nums,int L,int M,int R)
        int[] arr = new int[R-L+1];
        int index = 0;
        int p0 = L;
        int p1 = M+1;

        // 归并数据时候求最小和
        int sum = 0;
        while(p0 <= M && p1 <= R)
             if(nums[p1] <= nums[p0])
                 arr[index++] = nums[p1++];
             else
                 sum += nums[p0]*(R-p1+1);
                 arr[index++] = nums[p0++];
             
        
        while(p0 <= M)
            arr[index++] = nums[p0++];
        
        while(p1 <= R)
            arr[index++] = nums[p1++];
        

        for (int i = 0; i < arr.length; i++) 
            nums[i+L] = arr[i];
        
        return sum;
    

    /**
     * 随机生成 size 个 1 ~ value 值的数组
     * @param size 数组长度
     * @param value 数组值
     */
    public static int[] random(int size,int value)
        int[] nums = new int[size];
        for (int i = 0; i < size-1; i++) 
            nums[i] = (int)(Math.random()*value + 1);
        
        return nums;
    


数组的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数

举例:

输入: [7,5,6,4]
输出: 5
解释:逆序对 [7,5] [7,6] [7,4] [5,4] [6,4] 五对

通过归并的形式解决

class Solution 
    public int reversePairs(int[] nums) 
        if(nums.length < 2)
            return 经典十大排序算法(含升序降序,基数排序含负数排序)Java版完整代码建议收藏系列

算法导论总结

排序算法总结

排序算法思路总结

js排序算法总结——冒泡,快速,选择,插入,希尔,归并

数据结构与算法堆排序总结与实现