内部排序算法比较(超详解)

2023-11-12

一、题目描述
通过随机数据比较各排序算法的关键字比较次数和关键字移动次数,以 及执行时间,取得直观感受。
二、设计要求

一、需求分析
实现各排序算法,分别进行以下各组比较,并进行总结。
一、各算法在不同规模下的比较。
1)比较范围:直接插入排序、冒泡法排序、简单选择排序、快速排序1(自己实现)、快速排序2(调用STL)、归并排序。
2)比较指标:a)关键字操作次数(比较次数和移动次数之和),b)排序时间。每个指标采用多次重复取平均数记录,重复次数不小于100。注:1次关键字对换按3次移动计算。
3)数据规模:分别为50,100,500,1000,5000,10000;
4)数据类型:随机数据
二、算法在不同数据类型下的比较
1)比较范围:直接插入排序、冒泡法排序、简单选择排序、快速排序1(自己实现)、快速排序2(调用STL)、归并排序。
2)比较指标:a)关键字操作次数(比较次数和移动次数之和),b)排序时间。每个指标采用多次重复取平均数记录,重复次数不小于100。注:1次关键字对换按3次移动计算。
3)数据规模:10000;
4)数据类型:随机数据、正序数据、逆序数据;

三、代码要求
1、必须要有异常处理,比如删除空链表时需要抛出异常;
2、保持良好的编程的风格:
代码段与段之间要有空行和缩近
标识符名称应该与其代表的意义一致
函数名之前应该添加注释说明该函数的功能 、关键代码应说明其功能
3、递归程序注意调用的过程,防止栈溢出
四、算法分析

#include<iostream>
#include<time.h>
#include <algorithm>
#include<stdlib.h>
#include <windows.h>
#include <string>
using namespace std;

//关键次数初始化
static long long move1=0;
static long long move2=0;
static long long move3=0;
static long long move4=0;
static long long move5=0;
static long long move6=0;


//输出结果
void print(int a[], int n){  
        for(int j= 0; j<n; j++){  
            cout<<a[j] <<"  ";  
        }  
        cout<<endl<<endl;  
    }  

/***********归并排序*******************/
 void Merge(int r[],int rf[], int i, int m, int n)   //归并操作
{  
    int j,k;  
    for(j=m+1,k=i; i<=m && j <=n ; ++k){  
        move1+=1;
        if(r[i] < r[j]) {rf[k] = r[i++]; move1+=3; move1+=1;}
        else {rf[k] = r[j++]; move1+=3; move1+=1;}
    }  

    while(i <= m)  {rf[k++] = r[i++];  move1+=3; move1+=2;}
    move1+=1;
    while(j <= n)  {rf[k++] = r[j++];  move1+=3; move1+=2;}
    move1+=1;

 }  

void MSort(int r[], int rf[], int s, int t)   //将r[]归并排序为rf[] 
{   
        move1+=1;
        //int *rf2=new int[t];
        int rf2[10000+1];
        if(s==t) {rf[s] = r[s];  move1+=3;}
        else  
        {   
            move1+=1;
            int m=(s+t)/2;              /*平分*p 表*/  
            MSort(r, rf2, s, m);        /*递归地将p[s…m]归并为有序的p2[s…m]*/  
            MSort(r, rf2, m+1, t);      /*递归地将p[m+1…t]归并为有序的p2[m+1…t]*/ 
            Merge(rf2, rf, s, m,t);   /*将p2[s…m]和p2[m+1…t]归并到p1[s…t]*/

        }  

 }  

void MergeSort(int r[], int rf[], int n)  
{   /*对顺序表*p 作归并排序*/ 

        MSort(r, rf, 0, n-1);  
 }  
/*************归并排序结束*******************/

/***********快速排序1(递归)*******************/
/*
void swap(int* a,int*b)
{
    int temp;
    temp=*a;
    *a=*b;
    *b=temp;
    move2+=3;
}
int Partition(int a[],int low,int high)
{
    int pivotkey= a[low];
    while(low<high)
    {
        while (low<high&&a[high]>=pivotkey) { --high;move2+=1;}
        swap(&a[low],&a[high]);
        while (low<high&&a[low<=pivotkey]){ ++low;move2+=1;}
        swap(&a[low],&a[high]);
    }
    move2+=1
     return low;  
}
void quickSort(int a[], int low, int high)
{
    int pivotloc;
    if (low<high)
    {
        pivotloc = Partition(a,low,high);    //将表一分为二  
        quickSort(a,low,pivotloc-1);        //递归对低子表递归排序
        quickSort(a,pivotloc+1,high);      //递归对高子表递归排序
    }
    move2+=1;
}*/

/*************快速排序1(递归)结束*******************/

/***********快速排序1(非递归)*******************/


void quicksort(int a[],int n)  
{      
            struct node   
            {  
                int low,high;  
            }st[10000];
           int i,j,low,high,temp,top=0;   
           st[top].low=0;
           st[top].high=n-1;  
           while(top>-1)  
           {   low=st[top].low;  
               high=st[top].high;  
               top--;  
               i=low;  
               j=high;  
               if(low<high) 
               {   
                   move2+=1;
                   temp=a[low];  
                   while(i!=j)  
                   {   
                       move2+=1;
                       while(i<j&&a[j]>temp){   j--;  move2+=1;}
                       if(i<j){a[i]=a[j];i++;move2+=3;}  
                       while(i<j&&a[i]<temp){  i++;   move2+=1;}
                       if(i<j){a[j]=a[i];j--;move2+=3;}  
                   }  
                   a[i]=temp;  

                   top++;    
                   st[top].low=low;     
                   st[top].high=i-1;  

                   top++;    
                   st[top].low=i+1;     
                   st[top].high=high;  
               }  
               move2+=1;
           }  
           move2+=1;
    }  
/*************快速排序1(非递归)结束*******************/

/*************冒泡排序开始*******************/
void bubbleSort(int a[], int n)
{
    int temp;
    for(int i=0;i<n-1;i++)
        for(int j=0;j<n-i-1;j++)
        {
            if(a[j]>a[j+1])
            {
                temp=a[j];
                a[j]=a[j+1];
                a[j+1]=temp;
                move3+=3;
            }
            move3+=1;
        }
}
/*************冒泡排序结束*******************/

/*************简单选择排序开始*******************/
void selectSort(int a[], int n)
{
    int key,temp;
    for(int i=1;i<n;i++)
    {
        key=i-1;
        for(int j=i;j<n;j++)
        {
            if(a[j]<a[key])
            {
                key=j;
                move4+=3;
            }   
            move4+=1;
        }
        if(key!=i-1)
        {
            temp=a[key];
            a[key]=a[i-1];
            a[i-1]=temp;
            move4+=3;
        }
        move4+=1;
        //  print(a,n,i);           //打印每趟排序的结果  
    }
}
/*************简单选择排序结束*******************/

/*************直接插入排序结束*******************/
void InsertSort(int a[], int n)  
{  
        for(int i= 1; i<n; i++){  
            if(a[i] < a[i-1]){               //若第i个元素大于i-1元素,直接插入。小于的话,移动有序表后插入  
                move5+=1;
                int j= i-2;   
                int x = a[i];        //复制为哨兵,即存储待排序元素  
                move5+=3;
                a[i] = a[i-1];           //先后移一个元素  
                move5+=1;
                while(x < a[j]&&j>=0){  //查找在有序表的插入位置  
                    a[j+1] = a[j];  
                    j--;         //元素后移 
                    move5+=1;
                }  
                move5+=1;
                a[j+1] = x;      //插入到正确位置  
            }  
            move5+=1;
           // print(a,n,i);           //打印每趟排序的结果  
        }  
}  
/*************直接插入排序结束*******************/

/*************STL快速排序开始************************/
int comp(const void*a,const void*b)
{
    move6+=3;
    return *(int*)a-*(int*)b;
}
/*************STL快速排序结束************************/


//汇总所有的排序算法    
void sort123(int z,int type)
{
        /********初始化变量*********************/
        //clock_t *start=new clock_t[100];
        //clock_t *end=new clock_t[100];
        long long *start=new long long[100];
        long long *end=new long long[100];
        double *dfMinus=new double[100];
        double *dfTim=new double[100];
        LARGE_INTEGER litmp;
        double  dfFreq;  
        QueryPerformanceFrequency(& litmp);         //获取CPU时钟频率
        dfFreq = (double)litmp.QuadPart;
        double times1=0;
        double times2=0;
        double times3=0;
        double times4=0;
        double times5=0;
        double times6=0;
        srand(time(NULL));
        //给原数组赋值
        for(int i=0;i<=99;i++)
        {
            //初始化各个数组
            int *a=new int[z];
            int *c=new int[z];
            int *d=new int[z];
            int *e=new int[z];
            int *f=new int[z];
            int *g=new int[z];
            if(type==0)
            {
                for(int j=0;j<z;j++)   //下标法
                {  
                    a[j]=rand();

                    c[j]=a[j];
                    d[j]=a[j];
                    e[j]=a[j];
                    f[j]=a[j];
                    g[j]=a[j];
                } 
            }
            else if(type==1)
            {
                for( int j=0;j<z;j++)
                {
                    a[j]=j+i;

                    c[j]=a[j];
                    d[j]=a[j];
                    e[j]=a[j];
                    f[j]=a[j];
                    g[j]=a[j];
                }
            }
            else
            {
                for(int j=0;j<z;j++)
                {
                    a[j]=z-j+i;

                    c[j]=a[j];
                    d[j]=a[j];
                    e[j]=a[j];
                    f[j]=a[j];
                    g[j]=a[j];
                }
            }

                /***归并排序开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                int *b=new int[z];   //b数组用于归并排序
                MergeSort(c,b, z);
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times1+=dfTim[i];
                delete []b; 
                delete []c;
                /*****归并排序结束********/

                /***快速排序1开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                quicksort(d,z); //此处用的是非递归快排,非递归需要堆栈不是很大
                //quickSort(d,0,z-1);   //此处是递归快排算法,算法在上面已经注释掉,因为快排递归需要堆栈太大,一般电脑需要调整堆栈,我改动的为5032768字节(随便,够大就好)
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times2+=dfTim[i];
                //if(i<=0)
                //  print(d,z);
                delete []d; 
                /*****快速排序1结束********/

                /***冒泡开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                bubbleSort(e,z);           //冒泡排序  
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times3+=dfTim[i];
                delete []e; 
                /*****冒泡结束********/

                /***选择法开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                selectSort(f,z);       //简单选择排序
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times4+=dfTim[i];
                delete []f; 
                /*****选择法结束********/

                /***插入法开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                InsertSort(g,z);         //直接插入排序
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times5+=dfTim[i];
                delete []g; 
                /*****插入法结束********/

                /***STL快排法开始*******/
                QueryPerformanceCounter(&litmp);         //获取开始计数值
                start[i] = litmp.QuadPart;
                //sort(a, a+z);         //STL一种改进型分段算法
                qsort(a,z,sizeof(int),comp);
                QueryPerformanceCounter(&litmp);        //获取结束计数值
                end[i] = litmp.QuadPart;
                dfMinus[i] = (double)(end[i]- start[i]);
                dfTim[i] = dfMinus[i]/dfFreq;                       //计算持续时间,单位为秒误差不超过1微妙算持续时间,单位为秒误差不超过1微妙
                times6+=dfTim[i];
                /*****STL快排法结束********/

                delete []a;
        }
                delete []start;
                delete []end;
                delete []dfMinus;
                delete []dfTim;
        /***********打印用时**********************/
        string s;
        if(type==0)  {  s="随机数据";cout<<s<<endl;}
        else if(type==1)  {  s="正序数据";cout<<s<<endl;}
        else   {  s="逆序数据";cout<<s<<endl;}

        cout<<"归并排序:          "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move1/100<<"次"<<endl<<"平均耗时"<<times1/100*1000<<"   毫秒"<<endl<<endl;
        cout<<"快速排序(非递归):  "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move2/100<<"次"<<endl<<"平均耗时"<<times2/100*1000<<"   毫秒"<<endl<<endl;
        cout<<"冒泡排序:          "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move3/100<<"次"<<endl<<"平均耗时"<<times3/100*1000<<"   毫秒"<<endl<<endl;
        cout<<"简单选择排序:      "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move4/100<<"次"<<endl<<"平均耗时"<<times4/100*1000<<"   毫秒"<<endl<<endl;
        cout<<"直接插入排序:      "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move5/100<<"次"<<endl<<"平均耗时"<<times5/100*1000<<"   毫秒"<<endl<<endl;
        cout<<"STL快速排序:       "<<z<<"个"<<s<<"重复实验100次;"<<" 关键字操作次数平均为"<<move6/100<<"次"<<endl<<"平均耗时"<<times6/100*1000<<"   毫秒"<<endl<<endl;


}




//主函数
int main()
{  
        sort123(50,0);
        sort123(100,0);
        sort123(500,0);
        sort123(1000,0);
        sort123(5000,0);
        sort123(10000,0);
        sort123(10000,1);
        sort123(10000,2);
        system("pause");
        return 0;
 }  

六、结果截图
1
2
3
正序
逆序
七、结果分析:
1、随机数据比较:数据规模分别为50,100,500,1000,5000,10000,我们经过验证可以得出初步结论:
在数据基本无序的状态下且数据较多:排序效率比较如下:
快速排序法>STL快速排序法>归并排序法>直接插入排序法>简单选择法>
冒泡排序法
在数据基本无序的状态下且数据较少:排序效率比较如下:
快速排序法>STL快速排序法>直接插入排序法简单选择法>冒泡排序法>
归并排序法

在数据更少的情况下,直接插入法也有奇效。

2、正序数据比较:数据规模为10000,我们经过验证可以得出初步结论:
在数据基本有序且为正序的状态下:排序效率如下:
直接插入排序>STL快速排序法>归并排序>快速排序>简单选择排序>
冒泡排序法

3、逆序数据比较:数据规模为10000,我们经过验证可以得出初步结论:
在数据基本有序且为正序的状态下:排序效率如下:
STL快速排序法>归并排序>快速排序>直接插入排序>简单选择排序>
冒泡排序法

八、总结
1、涉及递归的有归并排序以及快速排序,这两个都是我编写程序的时候感觉最艰难的。
2、归并排序使用的数组除了中间要合并用的那个rf2用的是静态数组,其他都是动态数组new创建的,堆创建数组本来是挺好的,可是这里却因为数据规模较大的时候,递归太深rf2又无法delete[],只能用数组,创建了一个rf2[10001].
3、快速排序我写了两种方法,一种是递归的,一种是非递归的,递归真的理解是最简单的,可是对堆栈真的要求太高了,递归本来是崩溃的,不过忽然找到了方法:因为快排递归需要堆栈太大,一般电脑需要调整堆栈,我改动的为5032768字节(随便,够大就好)
4、时间精度的问题也好解决,用的是QueryPerformance,这个精度非常好,学到的好东西。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

内部排序算法比较(超详解) 的相关文章

随机推荐

  • java必知必会_Java必知必会-Spring Security

    一 Spring Security介绍 1 框架介绍 Spring 是一个非常流行和成功的 Java 应用开发框架 Spring Security 基于 Spring 框架 提供了一套 Web 应用安全性的完整解决方案 一般来说 Web 应
  • 基于DFA方法的健康人与癫痫病人EEG数据分析附代码

    引言 DFA分析方法是由C K提出的一种研究时间序列波动长时相关性的方法 主要用来区别复杂系统本身产生的波动和由外界及环境刺激作用在系统上产生的波动 外部刺激产生的变化假设引起了局部效应 而系统本身内部的动力学产生的变化假设展示了长时的相关
  • 浅拷贝和深拷贝: copy模块的copy()和deepcopy()函数(*^▽^*)

    我们在平时处理列表和字典的时候 有时候希望创建一个列表或者字典的副本拿出来使用 但是同时我们也不希望列表 字典 和其列表 字典 副本还保留着某种联系的时候 比如说我们在修改列表的时候副本也跟着同步被修改了 这是我们最不想看到的情况 这种情况
  • 树莓派教程 - 1.2 树莓派GPIO库wiringPi 软件PWM

    Git例程源码仓库 https github com ZhiliangMa raspberry git 使用到的硬件 led 200 左右的电阻 杜邦线 上一节使用硬件PWM来控制led亮度 可树莓派的硬件PWM引脚只有1路 在实际应用中
  • php生成密码及密码检验

    1 生成密码 password hash test password PASSWORD DEFAULT 2 密码检验 hash 2y 10 ckeTXO nnKfWTDDYRSwGWu0xste 55Cp0RIpolBldDOXZ61ecZ
  • vscode同时编辑多处文字 批量替换编辑内容

    先按Ctrl F打开搜索框 然后搜索要编辑的内容 接着按Ctrl Shift L就可以选中对应的所有内容了 然后可以全部编辑和替换了 按了Ctrl shift L之后把搜索框关闭就可以同时编辑多处了 此处我就是搜索items
  • NLP 中 Bilstm-attentio的使用

    NLP 中 Bilstm attentio的使用 bilstm attention 理解 bilstm attention的作用 bilstm attention 编码实现 bilstm attention 理解 bilstm attent
  • java中的运算符

    java中常见的运算符 1 public static void q1 int a 5 0000 0101 int b 3 0000 0011 a b 0000 00111 二进制两个都为0的时候 结果是0 否则是1 System out
  • qt中lable中更改字体字号加粗等

    以下内容摘抄博客 https blog csdn net superbfly article details 53199731 utm medium distribute pc relevant none task blog BlogCom
  • 音频驱动篇之pop音攻略

    接触音频驱动工作也有2年的时间了 这这段时间里深刻感受了手机行业的更新换代是MB的迅速 2年的时间里 从TI到QUALCOMM 从android2 1到4 2 从单核到四核 经我参与的项目就有20款 日子是相当的难过 今天回头来说一些我在研
  • CentOS 使用nc命令进行端口扫描

    目录 CentOS 6 中nc命令的使用 CentOS 7 中nc命令的使用 使用nc命令可以探测目标主机的端口 但是在Centos 6 和 CentOS 7中这个命令的使用有所不同 甚至可以说功能已经不同 下面分别是CentOS 6 和
  • gitee密码修改后,pycharm权限不够提醒(windows10)

    问题 gitee密码修改后 pycharm更新代权限不够提醒 windows10 解决办法 gitee密码修改后 要在windows中同时进行修改 步骤如下 具体如图 控制面板 gt 所有控制面板项 gt 凭据管理器 gt Windows凭
  • vue 学习相关笔记大全

    与三阶段无关 框架是什么 封装与业务 功能 无关的代码块 简化了我们对于某些功能的代码量 但是我们需要记一套当前框架的语法 淘宝镜像 npm的服务器在国外 咱们国内下载的时候很慢 淘宝就自建了一个服务器 每个10分钟 就把npm的服务器里面
  • 这是一份面向3年以上Android开发者的中高级面试宝典,拔剑金九银十,大厂直通车

    前言 这是 拔剑金九银十 的第二篇文章 本文主要针对3年以上的Android开发者进阶面试中高级开发工程师而整理 三年以下小伙伴请移步 这是一份面向0 3年Android开发者的面试宝典 2020一线互联网大厂面试真题系统收录 希望可以对你
  • Arthur系统性详解微服务-完善中

    第一篇 微服务的意义 1 常见架构对比 第二篇 微服务的构建 1 微服务建模关注点及方法论 1 1 服务分类 1 2 服务模型 1 3 服务边界 1 4 服务数据 2 服务拆分和集成 2 1 服务拆分及方法论 2 1 1 服务拆分的维度 策
  • 配置环境说明

    工具及环境介绍 Eclipse 是一个开放源代码的 基于Java的可扩展开发平台 就其本身而言 它只是一个框架和一组服务 用于通过插件组件构建开发环境 Tomcat是一个应用服务器 他可以运行按照J2EE中的Servlet规范编写好的Jav
  • mysql数据库常用命令

    1 显示当前数据库服务器中的数据库列表 mysql gt show databases 2 创建数据库 mysql gt create database item character set utf8mb4 3 创建用户 mysql gt
  • unity3d 摄像机跟随角色时被物体遮挡解决方案

    unity3d 摄像机跟随角色时被物体遮挡解决方案 未被遮挡时 为了解决这个问题 在这里我们需要用到 Physics RaycastAll 使用方法详见圣典 首先 我们引入命名空间 System Collections Generic 然后
  • 电压电流双环控制PI参数计算01

    1 截止频率 将内环看作一个采样环节 对外环给定信号进行采样 同理驱动电路对内环给定信号进行采样 为保持环路稳定 外环截止频率 lt 内环截止频率 lt 开关频率 通常内环截止频率一般设置为开关频率的1 10 外环截止频率一般设置为开关频率
  • 内部排序算法比较(超详解)

    一 题目描述 通过随机数据比较各排序算法的关键字比较次数和关键字移动次数 以 及执行时间 取得直观感受 二 设计要求 一 需求分析 实现各排序算法 分别进行以下各组比较 并进行总结 一 各算法在不同规模下的比较 1 比较范围 直接插入排序