必须知道的7大排序---数据结构

Posted 一位懒得写博客的小学生

tags:

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

七大排序

直接插入排序

每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入
插入排序,初始数据越接近有序,时间效率越高

//直接插入排序
//arr[] = 6,9,3,12,8,1;
    public static void insertSort(int[] arr) 
        for (int i = 0; i < arr.length; i++) 
            int tmp = arr[i];
            int j;
            for(j = i - 1; j >= 0; j--) 
                if(arr[j] > tmp) 
                    arr[j + 1] = arr[j];
                 else 
                    break;
                
            
            arr[j + 1] = tmp;
        
    

//执行结果
[1, 3, 6, 8, 9, 12]

性能分析

时间复杂度
最好:O(n) 数据有序
平均:O(n^2)
最坏:O(n^2) 数据逆序
空间复杂度
O(1)
稳定性
稳定

希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。

  1. 希尔排序是对直接插入排序的优化;
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

//初始arr 9,1,2,5,7,4,8,6,3,5
    public static void hellSort(int[] arr) 
        int[] gap = 5,3,1;
        for (int i = 0; i < gap.length; i++) 
            insertSortGap(arr,gap[i]);
        
    
    public static void insertSortGap(int[] arr,int gap) 
        for (int i = 1; i < arr.length; i++) 
            int tmp = arr[i];
            int j;
            for (j = i - gap; j >= 0 ; j -= gap) 
                if(arr[j] > tmp) 
                    arr[j + gap] = arr[j];
                 else 
                    break;
                
            
            arr[j + gap] = tmp;
        
    

//执行结果
[1, 2, 3, 4, 5, 5, 6, 7, 8, 9]

性能分析

时间复杂度
最好:O(n)
最坏:O(n^2)
空间复杂度
O(1)
稳定性
不稳定

选择排序

每一次从无序区间选出最大(或最小)的一个元素,存放在无序区间的最后(或最前),直到全部待排序的数据元素排完。

//选择排序
//初始数据 6,9,3,2,8,1,5
    public static void selectSort(int[] arr)
        for (int i = 0; i < arr.length; i++) 
            for (int j = i + 1; j < arr.length; j++) 
                if (arr[i] > arr[j]) 
                    int tmp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = tmp;
                
            
        
    

//执行结果
[1, 2, 3, 5, 6, 8, 9]

性能分析

时间复杂度
O()n^2 数据不敏感
空间复杂度
O(1) 数据不敏感
稳定性
不稳定

冒泡排序

    public static void bubbleSort(int[] arr) 
        for (int i = 0; i < arr.length - 1; i++) 
            boolean f = true;
            for (int j = 0; j < arr.length - 1 - i; j++) 
                if(arr[j] > arr[j + 1]) 
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;
                    f  =false;
                
            
            //如果 f = true 的话说明数组本身就是有序的,直接跳出即可
            if(f) break;
        
    

性能分析

时间复杂度
最好:O(n)
最坏:O(n^2)
空间复杂度
O(1)
稳定性
不稳定

堆排序

排升序要建大堆;排降序要建小堆

//堆排序  (大根堆)
//初始数组 27,15,19,18,28,34,65,49,25,37
    public static void heap(int[] arr) 
        for(int i = (arr.length - 1 - 1) / 2; i >= 0; i--) 
            heapSort(arr,i,arr.length);
        
    
    public static void heapSort(int[] arr,int parent,int len) 
        //孩子节点 = 父母节点 * 2 + 1
        int child = parent * 2 + 1;
        while(child < len) 
            //child + 1  判断是否有右节点
            if(child + 1 < len && arr[child] < arr[child + 1]) 
                child++;
            
            if(arr[child] > arr[parent]) 
                int tmp = arr[child];
                arr[child] = arr[parent];
                arr[parent] = tmp;
                parent = child;
                child = parent * 2 +1;
             else 
                //因为是从最后一颗子树建堆的,所以上边建好下边一定是大根堆,直接跳出。
                break;
            
        
    

//执行结果
[65, 49, 34, 25, 37, 27, 19, 18, 15, 28]

性能分析

时间复杂度
O(n * log(n))
空间复杂度
O(1)
稳定性
不稳定

快速排序

  1. 从待排序区间选择一个数,作为基准值(pivot);
  2. Partition: 遍历整个待排序区间,将比基准值小的(可以包含相等的)放到基准值的左边,将比基准值大的(可以包含相等的)放到基准值的右边;
  3. 采用分治思想,对左右两个小区间按照同样的方式处理,直到小区间的长度 == 1,代表已经有序,或者小区间的长度 == 0,代表没有数据。
//快速排序
//初始数组 6,1,2,7,9,3,4,5,10,8
    public static void quickSort(int[] arr,int left,int right) 
        if(left < right) 
            //拿到基准值
            int piv = getPivot(arr,left,right);
            //递归左边
            quickSort(arr,left,piv - 1);
            //递归右边
            quickSort(arr,piv + 1,right);
        
    
    public static int getPivot(int[] arr,int left,int right) 
        int tmp = arr[left];
        while(left < right) 
            //找右边比tmp小的
            while(left < right && arr[right] > tmp) 
                right--;
            
            arr[left] = arr[right];

            //找左边比tmp大的
            while(left < right && arr[left] < tmp) 
                left++;
            
            arr[right] = arr[left];
        
        //当left = right
        arr[left] = tmp;
        //返回基准值
        return left;
    

//执行结果
[1, 2, 3, 4, 5, 6, 9, 7, 8, 10]

性能分析

时间复杂度
最好:O(n * log(n))
最坏:O(n^2)
空间复杂度
最好:O(log(n))
最坏:O(n)
稳定性
不稳定

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

//归并排序
//初始数据 10,6,7,1,3,9,4,2
    public static void mergeSort(int[] arr,int left, int right) 
        if(left >= right) return;
        int mid = (right + left) / 2;
        mergeSort(arr,left,mid);
        mergeSort(arr,mid + 1,right);

        //进行合并
        merge(arr,left,mid,right);
    

    public static void merge(int[] arr,int start,int mid,int end) 
        int s1 = start;
        int s2 = mid + 1;
        //定义一个新数组合并原数组
        int[] ret = new int[end - start + 1];
        int k = 0;
        while(s1 <= mid && s2 <= end) 
            if(arr[s1] <= arr[s2]) 
                ret[k++] = arr[s1++];
             else 
                ret[k++] = arr[s2++];
            
        
        //有可能第一段还有数据
        while(s1 <= mid) 
            ret[k++] = arr[s1++];
        
        //有可能第二段还有数据
        while(s2 <= end) 
            ret[k++] = arr[s2++];
        

        //将ret中的数据接在a原数组中
        for (int i = 0; i < ret.length; i++) 
            arr[i + start] = ret[i];
        
    
//执行结果
[1, 2, 3, 4, 6, 7, 9, 10]

性能分析

时间复杂度
O(n * log(n))
空间复杂度
O(n)
稳定性
稳定

总结

排序方法最好平均最坏空间复杂度稳定性
冒泡排序O(n)O(n^2)O(n^2)O(1)稳定
插入排序O(n)O(n^2)O(n^2)O(1)稳定
选择排序O(n^2O(n^2)O(n^2)O(1)不稳定
希尔排序O(n)O(n^1.3)O(n^2)O(1)不稳定
堆排序O(n * log(n))O(n * log(n))O(n * log(n))O(1)不稳定
快速排序O(n * log(n))O(n * log(n))O(n^2)O(log(n)) ~ O(n)不稳定
归并排序O(n * log(n))O(n * log(n))O(n * log(n))O(n)稳定

以上是关于必须知道的7大排序---数据结构的主要内容,如果未能解决你的问题,请参考以下文章

手撸golang 基本数据结构与算法 快速排序

快速排序算法总结

算法class11 排序算法-快速排序

排序方法——快速排序

冒泡快速归并排序

小朋友学数据结构:快速排序