算法总结——三大排序(快排,计数排序,归并)

快排:

适用条件:方便...只要数字不是很多

复杂度:O(nlogn)  每一层n复杂度,共logn层

原理:利用一个随机数与最后面一个数交换,那么这个随机数就到了最后一位,然后循环,如果前面的数大于最后一个数,那么把这个数放到前面去,经过一次排序之后,前面的数都是大于最后一个的,然后对1到k和k+1到n进行排序,一层一层地下去

模板:

#include<cstdio>
#include<algorithm>
#include<time.h>
using namespace std;
void Sort(int *a,int l,int r)
{
int k = 0;
int len = l - r;
if(len <= 1) return ;
srand(time(NULL));
int pos = rand()%len;
swap(a[r-1],a[pos+l]);
for(int i = l; i < r; i++){
      if(a[i] >a[r-1]){
           swap(a[i],a[l+k]);
          k++;
      }
}
Sort(a,l,l+k-1);
Sort(a,l+k,r);
}

计数排序

复杂度:O(n+k)

适用条件:正数

原理:计数排序的基本思想是对于给定的输入序列中的每一个元素x,确定该序列中值小于x的元素的个数。一旦有了这个信息,就可以将x直接存放到最终的输出序列的正确位置上。例如,如果输入序列中只有17个元素的值小于x的值,则x可以直接存放在输出序列的第18个位置上。当然,如果有多个元素具有相同的值时,我们不能将这些元素放在输出序列的同一个位置上,因此,上述方案还要作适当的修改(来自百度百科

通俗来说,用a来记录所有的要排序的值,w来记录以该值为下标的值的个数,通过计数,w就变成小于这个数的下标的数有多少个,w[a[i]]也就是小于当前a[i]的数有多少个,也就是确定了位置,用一个数组p来记录这个位置下的这个值,然后小于这个数的其他数的个数就少了一个,那么位置全部确定了直接输出就行

计数排序的一个特点就是要开这个数值一样多的结点,比如7000,那就要开7000个,显然如果数字少并且大的话很不合算,但是多的话计数排序比快排快了六倍。

模板:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 222222;
int p[maxn],w[maxn],a[maxn];
void sort(int *a,int n,int mx)
{
    for(int i = 1; i <= mx; i++)
        w[i] = 0;
    for(int i = 1; i <= n; i++)
        w[a[i]]++;
    for(int i = 1; i <= mx; i++)
        w[i] += w[i-1];
    for(int i = n; i >= 1; i--){
        p[w[a[i]]] = a[i];
        w[a[i]]--;
    }
}
int main()
{
    int n,mx = 0;
    while(~scanf("%d",&n)){
        for(int i = 1; i <= n; i++){
            scanf("%d",&a[i]);
          mx = max(mx,a[i]);
        }
        sort(a,n,mx);
        for(int i = 1; i < n; i ++)
            printf("%d ",p[i]);
        printf("%d\n",p[n]);
    }
    return 0;
}

ps:orz,原来叫计数排序,不叫桶排,醉了~~~~~~

归并排序(Merge_Sort):

适用范围:可以用来求逆序数,在第二部分块比较上就有排序的功能,在这里记录就行,详情看代码注释处,如果数字多的话就使用,毕竟稳定,但所占内存也比较多

复杂度:O(nlogn)  合并O(n) 分成每一小块O(logn)

原理:用了分治思想,要使得所有串都排序好,那么把整块不断的分成小块,直到最后几个数,然后从下往上对于整个序列进行比较排序,用了递归(分治:把大问题分成每一个小问题来解决),也就是这个算法分成两个部分:1.对整个串进行分块 2.对分好块的进行比较排序进行合并

模板:

#include<cstdio>
#include<cstring>
using namespace std;
const int MAX = 222222;
int a[MAX],temp[MAX];
int ans = 0;
void mergearry(int *a,int first,int mid,int last,int *temp)
{
    int i = first, j = mid + 1;
    int k = first ;
    while( i <= mid && j <= last){
        if(a[i] <= a[j])
        temp[k++] = a[i++];
        else {
       // ans += j - k; 逆序数求法,因为a都都是从小到大排好的,如果a[i]>a[j]说明a[i]后面的数都大于a[j]前面的数,那么逆序数就要增加j-k个
        temp[k++] = a[j++];

        }
    }
    while( i <= mid )
        temp[k++] = a[i++];
    while( j <= last)
        temp[k++] = a[j++];
    for(int i = first ; i <= last;i++)
        a[i] = temp[i];
}
void mergesort(int *a,int first,int last,int *temp)
{
    if(first < last){
            int mid = (first + last) >> 1;
            mergesort(a,first,mid,temp);
            mergesort(a,mid+1,last,temp);
            mergearry(a,first,mid,last,temp);
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i = 1; i <= n ;i++)
    scanf("%d",&a[i]);
    mergesort(a,1,n,temp);
    for(int i = 1; i < n; i++)
        printf("%d ", a[i]);
       printf("%d\n",a[n]);
       printf("%d\n",ans);
    return 0;
}

总结:三大排序用的最多的还是快排和归并,毕竟归并可以用来求逆序数,快排方便,计数一般不用吧~~~

时间: 2024-11-08 22:34:06

算法总结——三大排序(快排,计数排序,归并)的相关文章

算法导论学习之快排+各种排序算法时间复杂度总结

快排是一种最常用的排序算法,因为其平均的时间复杂度是nlgn,并且其中的常数因子比较小. 一.快速排序 快排和合并排序一样都是基于分治的排序算法;快排的分治如下: 分解:对区间A[p,r]进行分解,返回q,使得A[p–q-1]都不大于A[q] A[q+1,r]都大于A[q]; 求解:对上面得到的区间继续递归进行快排 合并:因为快排是原地排序,所以不需要特别的合并 从上可以看出最重要的就是分解函数,其按关键值将数组划分成3部分,其具体实现的过程见代码注释. 我们一般取数组的最后一个元素作为划分比较

区间模糊排序---快排思路的应用

1 #include<iostream> 2 #include<ctime> 3 using namespace std; 4 #define max(a,b) (a>b)?a:b 5 #define min(a,b) (a>b)?b:a 6 class Interval 7 { 8 public: 9 double leftbound; 10 double rightbound; 11 Interval(int a, int b) :leftbound(a), rig

基本排序系列之计数排序

简述计数排序 看了好多别人写的计数排序,看了好久都没看懂,弄了好久最后发现这么简单居然花了几个小时,所以在这里写上,希望和我一样的初学者不会再绕弯路. 一.简述计数排序的思想: 设被排序的数组为A,排序后存储到B,C为临时数组.所谓计数,首先是通过一个数组C[i]计算大小等于i的元素个数,此过程只需要一次循环遍历就可以:在此基础上,计算小于或者等于i的元素个数,也是一重循环就完成.下一步是关键:逆序循环,从length[A]到1,将A[i]放到B中第C[A[i]]个位置上.原理是:C[A[i]]

普林斯顿公开课 算法3-3:三路快排

很多时候排序是为了对数据进行归类,比如对城市进行排序,对员工的职业进行排序.这种排序的特点就是重复的值特别多. 如果使用普通的快排对这些数据进行排序,会造成N^2复杂度,但是归并排序和三路快排就没有这样的问题. 三路快排 三路快排的基本思想就是,在对数据进行分区的时候分成左中右三个部分,中间都是相同的值,左侧小于中间,右侧大于中间. 性能 三路快排的复杂度比普通快排小,主要取决于数据中重复数据的数量.重复数据越多,三路快排的复杂度就越接近于N. 代码 public class Quick3 {

Java实现基于桶式排序思想和计数排序思想实现的基数排序

计数排序 前提:待排序表中的所有待排序关键字必须互不相同: 思想:计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少个记录的关键码比该记录的关键码小,假设针对某一个记录,统计出的计数值为c,则该记录在新的有序表中的存放位置即为c. 性能:空间复杂度:o(n):时间复杂度:o(n^2): 1 public int[] countSort(int[] array){ 2 int[] tempArray = new int[array.length]; //引入辅助数组 3 for(i

算法导论之六:线性时间排序之 决策树&amp;计数排序

本系列前五篇都是讲述的比较排序算法,从本文开始,将进入线性时间排序.什么是比较排序,简单的说,就是排序的过程依赖于数组中数据大小的比较,从而来确定数据在排好序输出时的位置. 比较排序法比较直观,但是也有它的不足,我们容易证明任何比较排序法,在最坏的情况下的时间复杂度的下限都是 nlgn.要证明这个问题,我们首先要搞清楚一个模型:决策树模型. 一.决策树模型 什么是决策树?决策树从形态上来讲,是一颗完全二叉树,它除叶子节点之外,其他层的节点都是满的.它的每一个叶子节点表示对输入数据组合的一种排序可

数据结构-排序-快排

快速排序 首先快速排序步骤: 首先选择轴值 把待排序内容分为两部分,左边为小于或者等于轴值,右边为大于轴值 然后对左右重复上面步骤直到整个序列有序 直接上代码这里先写一次划分的代码 这里的一次划分是那第一个数字为轴值,我们也可以用最后一个或者中间的. #include<iostream> #include<vector> using namespace std; //不含暂存单元的数组v1 int temp1[]={59,20,17,36,98,14,23,83,13,28}; v

算法导论第八章__实现计数排序

计数排序:不须要比較就能得出排序的顺序__比如.本章的计数排序.基数排序.桶排序 比較排序:须要进行比較才干得出排序的顺序__比如,本章的堆排序.高速排序(本质是插入排序).插入排序 代码清单:计数排序__完美演绎下标的作用 public class Count_Sort { //接收须要排序的数组 private int[] A; //排序后的数组 private int[] B; //用于计数的数组 private int[] C; // 初始化 public Count_Sort(int[

大话桶排序 基数排序和计数排序

一:计数排序 (1)当输入的元素是 n 个 0 到 k 之间的整数时,它的运行时间是 Θ(n + k).计数排序不是比较排序,排序的速度快于任何比较排序算法.由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存.例如:计数排序是用来排序0到100之间的数字的最好的算法,但是它不适合按字母顺序排序人名.但是,计数排序可以用在基数排序中的算法来排序数据范围很大的数组. (2)算法的步骤如下: 1.

算法学习——单链表快排

/**  * 以p为轴对start-end间的节点进行快排(包括start && 不包括end):  * 思路:  * 1.将头节点作为轴节点start,从start.next开始遍历,如果节点小于轴start的值,将该节点插入到轴节点后面:  * 2.将轴节点插入合适位置,即找到最后一个小于轴的节点,将该节点与轴节点值互换,此时就链表分为两部分,小于轴节点和大于轴节点:  * 3.递归的遍历2中两部分节点.  *   * @param p  * @param start  * @para