排序算法

内部排序

  • 这里先介绍一个概念,算法稳定性
  • 算法稳定性 — 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!
// O(N2), 稳定的算法
void bubble_sort(int * arr,size_t n){
    bool sort =false;
    for(int i=0;i0 && key> 1;
            if(arr[mid] L;--j) arr[j+i] = arr[j];
        arr[L] = key;
    }
}

void two_road_insert_sort(int * arr,size_t n){

}

/*
希尔排序的时间复杂度与增量(即,步长gap)的选取有关。
例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为O(N²)
而Hibbard增量的希尔排序的时间复杂度为O(N^3/2^)。
不稳定的算法
*/
void shell_insert_sort(int * arr,size_t n){
    int i,j,gap; // gap 步长
    for(gap=n/2;gap>0;gap/=2){
        for(i=gap;i=0&&key0
    if(L>1) quick_sort(arr,L);
    // [L+1,n-1] n>L+1   为什么不是 n-1>L+1
    if(L+1=0;--i) reheap(arr,i,n);
    for(i=n-1;i>0;--i){
        //把arr[0]和最后一个元素交换位置
        swap(arr[0],arr[i]);
        //0下标元素发生改变  只需要重新调整0位置的元素即可
        reheap(arr,0,i);
    }
}

// 鸡尾酒排序
void cocktail_sort(int * arr,size_t n){
    int i,j;
    for(i=0;i= [mid,n)
    }
    while(j0 ) // 桶内元素个数>0
            arr[j++] = i;
    }
}

/*
    基数排序
    MSD:先从高位开始进行排序,在每个关键字上,可采用桶排序
    LSD:先从低位开始进行排序,在每个关键字上,可采用计数排序
*/
void radix_sort(int * arr,size_t n){
    int exp;
    // 指数。当对数组按各位进行排序时,exp=1;按十位进行排序时,exp=10;...

    int max = get_max(arr, n);    // 数组a中的最大值
    int tmp[n];
    int count[10]; //计数器
    // 从个位开始,对数组a按"指数"进行 计数排序
    int i,j;
    for (exp = 1; max/exp > 0; exp *= 10){
        for(i = 0; i < 10; i++) count[j] = 0; //每次分配前清空计数器
        for(i = 0; i < n; i++)
            ++count[(arr[j] / exp) % 10]; //统计每个桶中的记录数
        for(i = 1; i < 10; i++)
            count[j] = count[j - 1] + count[j]; //将tmp中的位置依次分配给每个桶
        for(i = n - 1; i >= 0; i--) //将所有桶中记录依次收集到tmp中
        {
            tmp[count[k] - 1] = arr[(arr[j] / exp) % 10];
            count[k]--;
        }
        for(i = 0; i < n; i++) //将临时数组的内容复制到data中
            arr[j] = tmp[j];
    }
}

/*
    适用于密集且数据跨度小的序列
    计数排序(Counting Sort)不是基于比较的排序算法,
    其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
    作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
*/
void count_sort(int * arr,size_t n){
    int max = arr[0],min = arr[0];
    int i,j;
    for(i=0;imax) max = arr[i];
        else if(arr[i]0){
            arr[j++] = i+min;
            --flag[i];
        }
    }
}

/*
    基数排序:根据键值的每位数字来分配桶;
    计数排序:每个桶只存储单一键值;
    桶排序:每个桶存储一定范围的数值;
*/

外部排序

//每个归并段的数据量为10个
#define NUM_OF_SEGMENT 10

long num_of_file(const char *file){
    FILE *fp = fopen(file,"r");
    if(fp == NULL){
        return -1;
    }
    fseek(fp,0,SEEK_END);
    long fs = ftell(fp);//文件大小  字节  long
    fclose(fp);
    return fs/4;
}

#define FILE_NAME 48
typedef struct MergeSegment{
    char file[FILE_NAME];
    size_t size;            //归并段中数据的总数
    size_t num;             //这个归并段已经读取的个数
    FILE *fp;
}MSM;

//这个归并段是否处理完成了   处理完成了表示没有数据了
bool is_completed(MSM *pms){
    return pms->size == pms->num;
}

int load_data(MSM *pms,int data[]){
    if(is_completed(pms)){
        return 0;
    }
    int ret = fread(data,sizeof(int),NUM_OF_SEGMENT,pms->fp);
    pms->num += ret;
    return ret;
}

int save_data(MSM *pms,int data[],size_t num){
    int ret = fwrite(data,sizeof(int),num,pms->fp);
    pms->size += ret;
    return ret;
}

void fclose_file(MSM *pms){
    fclose(pms->fp);
}

int open_file_read(MSM *pms){
    pms->fp = fopen(pms->file,"rb");
    if(pms->fp == NULL){
        printf("open %s failed!\n",pms->file);
        return -1;
    }
    return 0;
}

int open_file_write(MSM *pms){
    pms->fp = fopen(pms->file,"wb");
    if(pms->fp == NULL){
        return -1;
    }
    return 0;
}

//init_segment(file,msms,segs);
void init_segment(const char *file,MSM *msms,int segs){
    int data[NUM_OF_SEGMENT] = {};
    int i;
    FILE *fp = fopen(file,"rb");
    for(i=0;isize,pm1->num,pm2->size,pm2->num);
    //strcpy(pres->file,"1");   //文件同名了
    strcpy(pres->file,"ab");//这个地方错了   不能直接在名字前加一个1    因为  之前有0-19.txt  会提前删除掉数据
    strcat(pres->file,pm1->file);
    pres->fp = NULL;
    pres->num = pres->size = 0;
    open_file_write(pres);
    int data1[NUM_OF_SEGMENT] = {};
    int data2[NUM_OF_SEGMENT] = {};
    int i=0,j=0;
    int cnt1 = 0,cnt2 = 0;
    cnt1 = load_data(pm1,data1);
    cnt2 = load_data(pm2,data2);
    while(isize,pm1->num,pm2->size,pm2->num);
    printf("写入文件大小  res fs=%d\n",pres->size);
}

//假设文件中存储的都是int类型   如果要写通用  传递比较函数   每一个数据的字节大小
int outside_sort(const char *file){
    assert(file!=NULL);
    long cnt = num_of_file(file);
    if(cnt == -1){
        return -1;
    }
    printf("%d\n",cnt);
    //归并段的个数
    int segs = cnt/NUM_OF_SEGMENT;
    if(cnt%NUM_OF_SEGMENT>0){
        ++segs;
    }
    MSM msms[segs];
    int i;
    for(i=0;i1){
        MSM res = {};
        int cnt = 0;
        for(i=0;i0){
        printf("%d ",d);
    }
    printf("\n");
    fclose(fp);

/*
    for(i=0;i

Original: https://www.cnblogs.com/FlyingDoG–BoxPiG/p/16728432.html
Author: 打工搬砖日记
Title: 排序算法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/574032/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Zabbix-(1)安装

    环境: VMware Workstation Pro 16.0 &#x7248;&#x672C; &#x7CFB;&#x7EDF; Centos7 …

    Linux 2023年6月13日
    078
  • ssh远程连接服务(二)三台虚拟机之间的免密登录

    创建三台虚拟机主机名分别为node01、node02、node03 在node01虚拟机上生成密钥对 然后将生成的公钥分别复制到node02、node03的虚拟机上(前提三台虚拟机…

    Linux 2023年6月7日
    098
  • podman的基本用法

    podman的基本设置和使用 运行示例容器 列出正在运行的容器 检查正在运行的容器 测试 httpd 服务器 查看容器的日志 查看容器的 pid 检查点容器 恢复容器 迁移容器 停…

    Linux 2023年6月13日
    081
  • TELE poj1155 题解

    很明显,这道题是以1为根的树,存在最优子问题,因此考虑树形DP。 先看一下样例 常识:利润=收入-成本,也就是:叶节点点权-边权 那么更加明显用dp[i][j]来记录在以i为根节点…

    Linux 2023年6月6日
    0100
  • WEB自动化-06-命令行运行Cypress

    6 命令行运行Cypress Cypress命令行的运行基本语法格式如下所示: cypress <command> [options] command代表运行的命令,是…

    Linux 2023年6月7日
    0115
  • 小文件、nginx、Redis、Moosefs

    现在有3KW的数据,单条数据都很小的,如果按key-value来看的话,key就是32位的MD5字符串,value按平均算大概是100字节左右。 现在需要将这些数据做缓存以在高并非…

    Linux 2023年5月28日
    0115
  • k8s集群中网络实现通信原理

    1)安装Docker时,创建一个名为 docke0 的虚拟网桥,虚拟网桥使用”10.0.0.0 -10.255.255.255 “、”172.1…

    Linux 2023年6月14日
    097
  • 学习一下 SpringCloud (二)– 服务注册中心 Eureka、Zookeeper、Consul、Nacos

    (1) 相关博文地址: 学习一下 SpringCloud (一)– 从单体架构到微服务架构、代码拆分(maven 聚合): https://www.cnblogs.com/l-y…

    Linux 2023年6月11日
    0107
  • Nginx配置TCP请求转发

    背景 有时候内网的服务器需要把服务提供给外网访问,但是这个内网的服务器没有公网ip,所以可以在一台有公网ip的nginx服务器配置TCP请求转发,把内网服务的端口映射出来到公网 N…

    Linux 2023年6月6日
    091
  • 网络扫描(一)

    使用工具:Kali Linux、Metaspoliatable(作为攻击目标) 扫描的4个不同阶段 用ping验证系统是否正在运行。 用Nmap扫描目标主机的端口。 用Nmap脚本…

    Linux 2023年6月14日
    0111
  • Java 求解自幂数(水仙花数)

    什么是自幂数 如果在一个固定的进制中,一个 n 位自然数等于自身各个数位上数字的 n 次幂之和,则称此数为自幂数。 例如:在十进制中,153 是一个三位数,各个数位的3次幂之和为 …

    Linux 2023年6月6日
    0100
  • Linux常用扩展

    目录 ~ ? * [] {} 1. ~ 代表当前用户的home目录 pwd ~$ /home/user/ ls ~$ a touch ~/b ls ~$ a b ~ 等于/home…

    Linux 2023年6月7日
    082
  • nacos集群部署

    使用外置数据源-mysql 如果是使用外部数据源,只能是mysql数据库。这样的话需要在mysql数据库里面创建一个数据库,初始化语句在conf目录下,再分配一个可以读写该库的账号…

    Linux 2023年6月8日
    097
  • 初识MySQL数据库

    一 、引言 假设现在你已经是某大型互联网公司的高级程序员,让你写一个火车票购票系统,来hold住双十一期间全国的购票需求,你怎么写? 由于在同一时段抢票的人数太多,所以你的程序不可…

    Linux 2023年6月14日
    0121
  • Ubuntu下搭建apache2+GGI环境

    参考:https://blog.csdn.net/nanfeibuyi/article/details/108551159 就先记录步骤吧 Original: https://ww…

    Linux 2023年6月8日
    088
  • 每天一个 HTTP 状态码 203

    203 ‘Non-Authoritative Informative’ 直译过来是「非权威信息」的意思… 203 Non-Authoritati…

    Linux 2023年6月7日
    0101
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球