十大经典排序算法

Posted yangbocsu

tags:

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

十大经典排序算法




默认从小排到大。


一、冒泡排序

1.1 思想

  • 两两相互比较;
  • 大数都往后扔;

1.2 参考代码

	// 冒泡排序
    public static int[] BubbleSort(int[] nums)
        for (int i = 0; i < nums.length; i++) 
            for (int j = 0; j < nums.length-1-i; j++) 
                if(nums[j]> nums[j+1])
                    int temp = nums[j];
                    nums[j] = nums[j+1];
                    nums[j+1] = temp;
                
            
        
        return nums;
    

1.3 复杂度

时间复杂度: O(n2)
空间复杂度:O(1)

由于冒泡排序只会交换相邻的元素,它不会出现两个相等的元素,后面的元素被交换到前面去的情况,所以冒泡排序是稳定的


二、选择排序

2.1 思想

  • 每一轮找出最小元素的下标;
  • 再与当前索引位置元素进行交换。

2.2 参考代码

	// 选择排序
    public static int[] SelectSort(int[] nums)
        for (int i = 0; i < nums.length; i++) 
            int minIndex = i;
            for (int j = i; j < nums.length; j++) 
                if(nums[j] < nums[minIndex])
                    minIndex = j;
                
            
            int temp = nums[i];
            nums[i] = nums[minIndex];
            nums[minIndex] = temp;
        
        return nums;
    

2.3 复杂度

时间复杂度: O(n2)
空间复杂度:O(1)

由于选择排序只会选择最小的元素进行交换,如果我们可以保证我们每次选择到的最小元素是第一次出现的(就算后面出现大小相等的元素我们也不会选择后面的),那么就可以保证它的稳定性,所以选择排序是可以做到稳定的


三、插入排序

3.1 思想

  • 依次选择一个元素,插入到前面已经排好序的数组中去;

3.2 参考代码

    //插入排序
    public static int[] InsertSort(int[] nums)
        // 默认第一个元素是有序的,从第二个元素开始遍历
        for (int i = 1; i < nums.length; i++) 
            int temp = nums[i];
            int j = i-1;
            // 如果当前元素比前一个元素小,则将前一个元素后移一位
            while (j >= 0 && nums[j] > temp)
                nums[j+1] = nums[j];
                j--;
            
            nums[j+1] = temp;
        
    

3.3 复杂度

时间复杂度: O(n2)
空间复杂度:O(1)

由于插入排序只会选择元素插入到适合的位置,只要我们按照原来的顺序遍历,即使相等的两个元素最后排完顺序之后,也会保持原有的相对顺序,所以插入排序是稳定的


四、希尔排序

4 .1 思想

  • 希尔排序是在数组中采用跳跃式分组,按照某个增量 gap 进行分组,分为若干组,每一组分别进行插入排序
  • 再逐步将增量 gap 缩小,再每一组进行插入排序,循环这个过程,直到增量为 1。

数组 [98,90,34,56,21,11,43,61]


4.2 参考代码

    // 希尔排序
    public static int[] ShellSort(int[] nums)
        for (int gap = nums.length; gap >0 ; gap /= 2) 
            for (int i = gap; i < nums.length ; i++) 
                int temp = nums[i];
                int j = i-gap;
                while (j >= 0 && nums[j] > temp)
                    nums[j+gap] = nums[j];
                    j -= gap;
                
                nums[j+gap] = temp;
            
        
        return nums;
    

4.3 复杂度

平均时间复杂度:O(n3/2)
空间复杂度:O(1)

由于希尔排序,在分组的时候,会将后面的元素间隔性的调动到前面,所以会打乱原本两个相等的数之间的相对顺序,所以希尔排序是不稳定的排序算法


五、快速排序

5.1 思想

  • 选择数组的一个数作为基准数,一趟排序,将数组分割成为两部分,一部分均小于/等于基准数,另外一部分大于/等于基准数;
  • 然后分别对基准数的左右两部分继续排序,直到数组有序;
  • 这体现了分而治之的思想,其中还应用到挖坑填数的策略。



5.2 参考代码

    // 快速排序
    public static int[] QuickSort(int[] nums)
        quickSort(nums, 0, nums.length-1);
        return nums;
    
    public static void quickSort(int[] nums, int left, int right)
        if(left >= right)
            return;
        
        // 取基准数
        int standardNum = nums[left];
        int i = left;
        int j = right;
        //
        while (i < j)
            // 如果 当前数 比 基准数 大,则继续向前找
            while (i < j && nums[j] >= standardNum)
                j--;
            
            nums[i] = nums[j];// 将比基准数小的数放到前面
            while (i < j && nums[i] <= standardNum)
                i++;
            
            nums[j] = nums[i];
        // 当i=j时,循环结束,i和j相等,此时i和j位置的数就是基准数
        
        nums[i] = standardNum;
        
        quickSort(nums, left, i-1);//对基准数左边的数组进行排序
        quickSort(nums, i+1, right);//对基准数右边的数组进行排序
    

5.3 复杂度

由于快速排序会将一个数大间隔的移动到一边,大的数放在右边,小的数放在左边,所以会破坏两个相等的元素的相对顺序,所以它是不稳定的排序算法



六、归并排序

6.1 思想

  • 先将数组分割,再分割 … 分割到一个元素,然后再两两归并排序,做到局部有序
  • 不断地归并,直到数组又被全部合起来。

6.2 参考代码

    // MergeSort 归并排序
    public static int[] mergeSort(int[] arr, int l, int r) 
        if (l < r) 
            int mid = (l + r) / 2;
            // 左边归并排序
            mergeSort(arr, l, mid);
            // 右边归并排序
            mergeSort(arr, mid + 1, r);
            // 合并
            merge(arr, l, mid, r);
        
        return arr;
    

    public static void merge(int[] arr, int l, int mid, int r) 
        // 申请临时数组
        int[] temp = new int[r - l + 1];
        int i = l;
        int j = mid + 1;
        int k = 0;
        //比较左右两部分的元素,哪个小,就把那个元素填入temp中
        while (i <= mid && j <= r) 
            // 左边的元素小
            if (arr[i] < arr[j]) 
                temp[k++] = arr[i++];
            
            // 右边的元素小
            else 
                temp[k++] = arr[j++];
            
        
        // 如果左边还有元素剩下,则全部合并过去
        while (i <= mid) 
            temp[k++] = arr[i++];
        
        // 如果右边还有元素剩下,则全部合并过去
        while (j <= r) 
            temp[k++] = arr[j++];
        

        // 将temp中的元素全部拷贝到原数组中
        for (int m = 0; m < temp.length; m++) 
            arr[l + m] = temp[m];
        
    

6.3 复杂度

时间复杂度: O(nlog2n)
空间复杂度:O(n)

由于归并排序只会在相邻的子数组做合并操作,而且是严格按照从左到右的顺序,不会出现跳跃交换的情况,所以归并算法是稳定的排序算法



七、桶排序

.1 思想

.2 参考代码

.3 复杂度



八、堆排序

.1 思想

.2 参考代码

.3 复杂度



九、计数排序

.1 思想

.2 参考代码

.3 复杂度



十、基数排序

.1 思想

.2 参考代码

.3 复杂度



以上是关于十大经典排序算法的主要内容,如果未能解决你的问题,请参考以下文章

十大经典排序算法总结(桶排序)

十大经典排序算法总结(希尔排序)

十大经典排序算法总结(快速排序)

十大经典排序算法总结(冒泡排序)

十大经典排序算法总结(堆排序)

十大经典排序算法详解