排序总结

Posted mychen06

tags:

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

稳定性排序:稳定性排序是指相等的元素相对位置不会发生改变。

 

以下介绍一系列排序算法:以非降序排列为序;

选择排序:遍历i,求[i,n)中的最小值,与A[i]交换;

时间复杂度O(N^2)

void selection_sort(vector<int>& num)
{
    int len = num.size() ;
    for(int i = 0 ; i < len ; i++)
    {
        int mini = i ;
        for(int j = i + 1 ; j < len ; j++)
        {
            if(A[j] < A[mini]) mini = j ;
        }
        swap(A[mini] , A[i]);
    }
}

  

冒泡排序:遍历 j in[0 , n-i) , i in [1 , n - 1], 如果A[j] > A[j +1] , 就交换。这样子每一次遍历都将最大的值放到A[n-i], 最好的情况是完全有序,不需要交换。 时间复杂度为O(N^2) ;

void bubble_sort(vector<int> &num)
{
    for(int i = 1 ; i < n ; i++)
        for(int j = 0 ; j < n - i ; j++)
        {
            if(nums[j] > nums[j+1]) swap(nums[j] , nums[j+1]) ;
        }
}

  

插入排序:数列分为已排序和未排序两部分,每一次从未排序的元素中选择一个插入到已排序部分中;当序列完全有序时,时间复杂度为O(N) ; 最坏时间复杂度为O(N^2), 平均时间复杂度为O(N^2) ;

void insert_sort(vector<int> &num))
{
     int n = num.size() ;
     for(int i = 1;  i < n ; i++)
    {
        int key = num[i] , j = i - 1; 
        while(j >= 0 && num[j] > key)
        {
            num[j + 1] = num[j] ;
            j-- ;
        }
        num[j + 1] = key ;
     }
}

  

计数排序:统计每个数出现的次数,从小到大计算每个数出现的前缀和,利用出现次数的前缀和,从右往左的计算每个数的排名; 时间复杂度为O(N + W) ;

void counting_sort(vector<int> &num)
{
    int maxn = INT_MIN, minn = INT_MAX ;
    for(auto n : num)
    {
        maxn = max(maxn , n) ;
        minn = min(minn , n) ;
    }

    vector<int> cnt(maxn - minn + 1 , 0)  , res(num.size() , 0);
    for(auto n : num) cnt[n-minn]++ ;
    for(int i = 0 ; i <= maxn - minn ; i++) cnt[i] += cnt[i-1] ;
    for(int i = n - 1 ; i >= 0 ; i--) res[--cnt[num[i]]] = num[i] ;
}

  

快速排序:选一个基准值,找到这个基准值在数列中的正确位置,然后再递归排序两部分数组;时间复杂度为O(NlogN) - O(N^2) , 实际运行效果要比时间复杂度为O(NlogN)的排序算法运行效果要好

int partion(vector<int> &num , int low , int high)
{
    int pivot = num[low] ;
    while(low < high)
    {
        while(high > low && num[high] >= pivot ) high-- ;
        num[low] = num[high] ;
        
        while(low < high && nums[low] <= pivot) low++ ;
        num[high] = num[low] ;
    }

     num[low] = pivot ;
     return low ;
}

void quickSort(vector<int> &num , int low, int high)
{
    if(low < high)
    {
        int pivot = partion(num , low , high) ;
        quickSort(num , low , pivot - 1) ;
        quickSort(num , pivot + 1 , high) ;
    }
}

 

归并排序:1.将数列划分成两部分;2.递归地分别对两个子序列进行排序。3.合并两个子序列

归并排序的核心是如何合并两个子序列。时间复杂度O(NlogN),空间复杂度O(N).

void mergeSort(vector<int>& num , int l , int r)
{
    int mid = l + (r - l )  / 2 ;
    mergeSort(num , l , mid) ;
    mergeSort(num , mid , r) ;
    
    int i = l , p = l , q = mid ;
    while(i < r)
    {
        if(p >= mid || (q < r && num[q] < num[p])) t[i++] = num[q++] ;
        else t[i++] = num[p++] ;
    }

    for(int j = l ; j < r ; j++) num[j] = t[j] ;
}

  

归并排序还有一种迭代版的做法:每一次将数列以2^i大小划分成组,两两合并,i<<1;

void mergeSort(vector<int> &num , int l , int r)
{
    int cur = 0 , len = num.size() ;
    for(int i = 1 ; i < len  ; i<<= 1)
    {
        cur = 0 ;
        while(cur < len)
        {
             int l = cur , r = l + i ;
             cur += 2 * i ;
             merge(num , l , r , min(r+i , len)) ;
        }
    }
}

void merge(vector<int> &num , int l1 , int l2 , int r2 )
{
     int s = l1 , p = l1 , q = l2;
     while(s < r2)
    {
        if(p >= l2 || (q < r2 && num[q] < num[p])) t[s++] = num[q++] ;
        else t[s++] = num[p++] ;
    }
}

  

归并排序可以求逆序对,也就是求(i < j && a[i] > a[j])的对数;

逆序对也可以用线段树,二分搜索树,树状数组来求,平均时间复杂度为O(NlogN);

 

桶排序:跟计数排序类似,跟值域有关,适用于值域较大,但分布比较均匀的情况,期望时间复杂度为O(N) , 空间复杂度为O(N) ;

  桶排序就是将值域分成n组(桶),根据a[i]/n决定在哪一个桶中 , 对桶中的元素进行插入排序。

 

排序相关的STL:

sort(begin , end , cmp)

stable_sort(begin , end , cmp) ;

部分排序:将数列的前k小哥元素置于数列的前

k个位置,后面元素不保证顺序性 partial_sort(beging , begin + k , end , cmp) ;

以上是关于排序总结的主要内容,如果未能解决你的问题,请参考以下文章

初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段

第九次作业

BootStrap有用代码片段(持续总结)

BootStrap实用代码片段(持续总结)

201621123054《Java程序设计》第九周学习总结

回归 | js实用代码片段的封装与总结(持续更新中...)