八大排序算法测试运行时间与时间复杂度分析

1编程实现曾经学过的所有排序算法,并对程序进行测试,列举多个测试用例,检查程序是否输出正确结果。

2、对比在待排序数据量不断增大的情况下,各个排序算法的运行时间变化情况,思考哪些算法的运行时间增长速度快,哪些算法的运行时间增长速度慢,哪个算法效率高?

3、记录测试数据量分别是10、100、1000、10000、10,0000、100,0000、1000,0000的运行时间。思考效率高的算法就一定在任何数据量下的效率都高吗?

4、分析每个算法的运行时间,用θ符号表示出算法的时间复杂度。

实验需求:
排序算法代码,存放至少100,0000个数据的随机数组,测试程序运行时间的clock()函数。

实验环境: 软件codeblocks 17.12
一、srand() and rand()函数
用srand(time(0))来设置种子 rand()函数产生随机数
srand是种下随机种子数,你每回种下的种子不一样,用rand得到的随机数就不一样。为了每回种下一个不一样的种子,所以就选用Time(0),Time(0)是得到当前时时间值
srand() 和rand() 共同使用能产生伪随机序列,如果想要产生相同的随机序列,把srand参数改成一个固定的数即可。
在这里插入图片描述

   int arr[N];
    //随机播种
    srand(1);
    for(int i=0; i<N; i++)
    {
        arr[i]=rand()%MAX;//我们在比较各种排序的算法,因此种子必须一样(控制变量)
        printf("%d ",arr[i]);
    }

二、测试clock函数

  clock_t start_time=clock();
    {
        bubbleSort(arr,N);
    }
    clock_t end_time=clock();

    printf("Running time is: %fms\n",double(end_time-start_time));

在这里插入图片描述
时间函数测试完成
三,测试判断排序结果的函数

 printf("\n排序的结果为:%s",isSorted(arr,N)==true?"true":"false");

使用判断函数的好处是数据量过大时,无法人为判断程序是否正确排序,排序准确是测试排序运行时间的前提。
四、回归题目
在这里插入图片描述
N的值控制数据量的大小,MAX控制数据的范围

五、测试排序算法, 记录测试数据量分别是100、1000、10000、10,0000、100,0000、1000,0000的运行时间。思考效率高的算法就一定在任何数据量下的效率都高吗?
对程序进行测试,列举多个测试用例,检查程序是否输出正确结果.
四、试排序算法, 记录测试数据量分别是100、1000、10000、10,0000、100,0000、1000,0000的运行时间。思考效率高的算法就一定在任何数据量下的效率都高吗?
冒泡排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述总结:用冒泡排序排100000的数据会很久 时间呈O(n2)递增 空间复杂度为O(1),冒泡是一种稳定的排序算法,冒泡可以在第二个for循环里面做一个优化,不过还是很慢。
选择排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
总结:可见选择排序是比冒泡排序要快一点 但时间复杂度仍然是O(n2) ,空间复杂度为O(1) 选择排序是不稳定的排序算法。而且数据的次序不会影响函数的时间复杂度。
插入排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
总结:插入排序比选择和冒泡排序都要快
时间复杂度还是在O(n^2)
空间复杂度为O(1)
快速排序
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述总结:排序10,0000个数据的时候时间级别大大减少,但排序100,0000的数据的时候,直接停止工作。
最好情况:时间复杂度:O(nlog2n)
最坏情况:时间复杂度:O(n^2)
快速排序算法的时间复杂度平均为O(nlog2n)
快速排序是一个不稳定的算法,但是在数据相对较小的时候,他是折合时间复杂度和空间复杂度最优的算法。
归并排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
时间复杂度为:O(nlog2n)
可知归并排序比快排,堆排序都快,并且稳定。但是他需要开辟一个很大的辅助空间。
堆排序
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
时间复杂度为:O(nlog2n)
一百万个数据排序起来,堆排序比快速排序要快,可见数据量要大的时候堆排序比快排优。

接下来终于到线性级别的排序方式了~
基数排序(桶排序)
基数排序是对数据有要求的,必须是整数,对于一些资金含(小数的排序就用不了),基数排序的原理是,先取键值,比如排序单纯排自然数的时候,直接取键值为0~9,然后对数据进行从个位再到十位一直往下进行排序。每排一次放在桶子里边(相当于一个队列),最后把桶子里面的数据串联起来即可。
10000个数据排序时间为几乎为0!!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
桶排序 :时间复杂度为O(n) 空间复杂度为O(n)
排一千万数据需要时间是1000ms以内。但是桶排序的缺点就是需要开辟一个很大的辅助空间,不过这个已经是相比于其他算法,既折中排序速度有很快的排序算法了。
计数排序
计数排序最大的特点就是数组的元素与下标一致,省略了排序的时间。
算法的步骤如下:
1.找出待排序的数组中最大和最小的元素
2.统计数组中每个值为i的元素出现的次数,存入数组的第i项
3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)4.反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结:时间复杂度O(n) 空间复杂度O(n)
可见,计数排序的算法排序整数是最快的!虽然计数排序看上去很强大,但是它存在两大局限性:
1.当数列最大最小值差距过大时,并不适用于计数排序
比如给定20个随机整数,范围在0到1亿之间,此时如果使用计数排序的话,就需要创建长度为1亿的数组,不但严重浪费了空间,而且时间复杂度也随之升高。
2.当数列元素不是整数时,并不适用于计数排序
如果数列中的元素都是小数,比如3.1415,或是0.00000001这样子,则无法创建对应的统计数组,这样显然无法进行计数排序。
正是由于这两大局限性,才使得计数排序不像快速排序、归并排序那样被人们广泛适用。
这个图片是百度,如有侵权立即删除

实验总结:综上所述,我们可以体会各种排序算法的应用场景,不是为了学习而学,要真正弄懂,才能够体会编程思想,进而享受编程的乐趣,最后,附上全部代码供大家参考:

#include <iostream>
#include <time.h>
#include <cstdio>
#include <cstdlib>
#define N 10000 //数据量的大小
#define MAX 100  //数据的范围1-100
using namespace std;

//-----------冒泡排序
void bubbleSort(int arr[],int n)
{
    int temp;
    for(int i=0; i<=n-1; i++)
    {
        for(int j=i+1; j<=n-1; j++)
        {
            if(arr[i]>arr[j])
            {
                temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
            }
        }
    }
}
//------------选择排序:
void chioseSort(int arr[],int n)
{

    int temp,index;
    for(int i=0; i < n-1; ++i)
    {
        index = i;
        for(int j=i+1; j<n; ++j)
        {
            if(arr[j]<arr[index])
                index = j;
        }
        if(index!=i)
        {
            temp = arr[i];
            arr[i] = arr[index];
            arr[index] = temp;
        }
    }
}

//------------直接插入排序:
void insertSort(int arr[], int len)
{
    int i, j, key;
    for(i = 1; i < len; ++i){
        key = arr[i];
        for(j = i-1; j >=0; --j){
            if(arr[j] > key)
                arr[j+1] = arr[j];
            else
                break;
        }
        arr[j+1] = key;
    }
}

//------------快速排序:
int partition(int arr[], int low, int high)
{
    int key=arr[low];
    while(low<high)
    {
        while(low<high&&arr[high]>=key)
            high--;
        arr[low]=arr[high];
        while(low<high&&arr[low]<=key)
            low++;
        arr[high]=arr[low];
    }
    arr[low]=key;
     //返回枢轴所在的位置 且 low and high 值是一样的
    return low;
}

void Qsort(int arr[],int low,int high)
{
    int key;
    if(low<high)
    {
        key=partition(arr,low,high);
        Qsort(arr,low,key-1);
        Qsort(arr,key+1,high);
    }
}


//------------归并排序
//辅助数组
int temp[N];
void combineArr(int arrL[],int ln,int arrR[],int rn)
{
    int i=0,j=0;
    int k=0;
    while(i<ln&&j<rn)
    {
        if(arrL[i]<=arrR[j])
        {
            temp[k++]=arrL[i++];
        }
        else
        {
            temp[k++]=arrR[j++];
        }
    }
    while(i<ln)
    {
         temp[k++]=arrL[i++];
    }
    while(j<rn)
    {
        temp[k++]=arrR[j++];
    }
    for(int i=0; i<k; i++)
    {
        arrL[i]=temp[i];
    }
}

void conflationSort(int arr[],int l,int r)
{
    if(r>l)
    {
        int mid= (l+r)/2;
        conflationSort(arr,l,mid);
        conflationSort(arr,mid+1,r);
        combineArr(&arr[l],mid-l+1,&arr[mid+1],r-mid);
    }
}

//------------堆排序
void swap(int *a,int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

//调整堆
void adjustHeap(int arr[],int index,int lenght)
{
    int l = index*2+1;
    int n = lenght;
    int temp = arr[index];
    while(l<n){

        if((l+1)<n&&arr[l+1]>arr[l])
            l++;
        if(arr[l] <= temp)
            break;
        arr[index] = arr[l];
        index = l;
        l = index*2+1;
    }

    arr[index] = temp;
}

//新建堆
void buildHeap(int arr[],int n)
{

    for(int i = n/2 -1;i>=0;--i)
    {
        adjustHeap(arr,i,n);
    }
}

void heapSort(int arr[],int n)
{

    buildHeap(arr,n);

    for(int i = n-1;i>0;--i)
    {
        swap(&arr[0],&arr[i]);
        adjustHeap(arr,0,i);
    }
}


//------------基数排序
//辅助数组
int temps[10][N];
//获取最大位数的位置 如8->1 , 17->2,7832->4
int getMexExp(int arr[],int n){

    int maxN = arr[0];
    for(int i=1;i<n;++i){   //把所有的数据都遍历一遍 然后找最大值 确定数据的位数 时间为N
        maxN = arr[i]>maxN?arr[i]:maxN;
    }
    int exps = 1;
    maxN = maxN/10;
    while(maxN!=0){
        maxN = maxN/10;
        exps++;
    }
    return exps;   //返回一个最大值的位数
}
//基数排序
void radixSort(int arr[],int n)
{
    //存每个桶中数的个数
    int countIndex[10] = {0};      //相当于10桶子
    int exps = getMexExp(arr,n);   //把位数传给exps
    int exp = 1;
    for(int e=0;e<exps;++e){
        //入桶
        for(int i=0;i<n;++i){   //把数据遍历一遍 获取从个位 十位 一直往下
            int index = (arr[i]/exp)%10;
            temps[index][countIndex[index]++] = arr[i];  //存放到队列里的过程
        }

        //取值,改变数组
        int k=0;
        for(int i=0;i<10;++i){   //排序数字0~9
            //如果桶中数的个数大于0
            if(countIndex[i]>0){
                int n  = countIndex[i];
                //将数取出,改变数组
                for(int j =0;j<n;++j){
                    arr[k++] = temps[i][j];  //按照各个位数排好 给原来的数组
                }
            }

        }
        //将桶中的数的个数重置为0
        for(int i=0;i<10;++i)
            countIndex[i] = 0;
        //位数改变
        exp *=10;
    }
}

//------------------计数排序
//创建辅助数组
//int temp[N];
void CountSort(int arr[], int n)
{
    int i;
    int minValue = arr[0];
    int maxValue = arr[0];
    int range = 0;
    int count = 0;
    for (i = 0; i < n; i++)//计算数据的分散空间
    {
        if (arr[i] < minValue){
            minValue = arr[i];   //找最大值和最小值
        }
        if (arr[i] > maxValue){
            maxValue = arr[i];
        }
    }
    range = maxValue - minValue + 1;   //存放的空间大小为最大值与最小值之差

    for (i = 0; i < n; i++)//统计每个元素出现的次数
    {
        temp[arr[i] - minValue]++;
    }

    for(i=0;i<range;i++)//通过统计temp[];回收元素
    {
        while (temp[i]--)
        {
            arr[count++] = i + minValue;
        }
    }
}

//以上排序结果均测试完毕,结果为true。

bool isSorted(int arr[],int n)
{
    for(int i=0; i<n-1; i++)
    {

        //从小到大排序
        if(arr[i]>arr[i+1])
        {

            return false;
        }
    }
    return true;
}
int main()
{
    //int arr[10]={3,2,5,2,3,4,6,7,2,10};
    int arr[N];
    //随机播种
    srand(1);
    for(int i=0; i<N; i++)
    {
        arr[i]=rand()%MAX;
       // printf("%d ",arr[i]);
    }
    printf("\n");



    clock_t start_time=clock();
    {
        // bubbleSort(arr,N);
        // chioseSort(arr,N);
        //insertSort(arr,N);
        //heapSort(arr,N);
        CountSort(arr,N);
        // radixSort(arr,N);
        // conflationSort(arr,0,N-1);
        //  Qsort(arr,0,N-1);
    }
    clock_t end_time=clock();

    printf("Running time is: %fms\n",double(end_time-start_time));
    printf("\n排序的结果为:%s",isSorted(arr,N)==true?"true":"false");

    return 0;
}

  • 17
    点赞
  • 102
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值