排序算法

内部排序

  • 这里先介绍一个概念,算法稳定性
  • 算法稳定性 — 假设在数列中存在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)

大家都在看

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