算法精解----18、插入排序,快速排序

1、插入排序:每次找到最小元素,从无序数据集中取出一个元素,扫描已排好的数据集,把这个元素插入有序集的合适位置。
特点:简单,但不适合处理大型数据集,不需要额外空间,最坏O(n2),在增量排序中非常高效。
这里写图片描述

int issort(void *data, int size, int esize, int (*compare)(const void *key1, const void *key2))
{
    int i, j;
    void *key;
    char *a = data;

    if((key = (char *)malloc(esize)) == NULL)
        return -1;
    for(j = 1; j < size; j++)
    {
        //key暂存当前需要移动的数据 
        memcpy(key, a[i * esize], esize);
        i = j - 1;

        //如果key小,向左和下一个比较 
        while((i >= 0) && (compare(&a[i * esize], key) > 0))
        {
            memcpy(&a[(i + 1) * esize], &a[i * esize], esize);
            i--;
        }
        //把该数插入比左边较小数的右边 
        memcpy(&a[(i + 1) * esize], key, esize);
    }
    free(key);
    return 0;
}

2、快速排序:一种分治排序算法。每次以某个数为基准交换左右两边大于和小于它的数。
分:将未排序的支票分为两堆,其中一堆小于等于某个数,另一堆大于某个数。
治:重复划分,递归快速排序直到每堆只有一个。
合:对分割部分排序直至完成。
特点:适合大数据,不需要额外空间,最坏O(n2),平均O(nlgn)。如果分割值选的不好,性能会很差。一个有效方法为随机选择法。还可以改进随机选择法:随机选取3个数,取3个元素的中间值。
这里写图片描述

//i, k 初始值为 0 和 size - 1, 返回分好的边界点位置 
//partition完成分割值的选取,把一堆分成以分割值为边界的两堆。 
static int partition(void *data, int size, int esize, int i, int k, int (*compare)(const void *key1, const void *key2))
{
    char *a = data;
    void *pval, *temp;//pval存放边界值,temp交换中介 
    int r[3];

    if((pval = malloc(esize)) == NULL)
        return -1;
    if((temp = malloc(esize)) == NULL)
    {
        free(pval);
        return -1;
    }
    r[0] = (rand() % (k - i + i)) + i;
    r[1] = (rand() % (k - i + i)) + i;
    r[2] = (rand() % (k - i + i)) + i;
    issort(r, 3, sizeof(int), compare);
    memcpy(pval, &a[r[1] * size], esize);
    i--;
    k--;
    while(1)
    {
        do
        {
            k--;
        }while(compare(&a[k * esize], pval) > 0);
        do
        {
            i++;
        }while(compare(&a[i * esize], pval) < 0);

        //找完 
        if(i >= k)
        {
            break;
        }
        //大于边界值的放右边,小于边界值的放左边 
        else
        {
            memcpy(temp, &a[i * esize], esize);
            memcpy(&a[i * esize], &a[k * esize], esize);
            memcpy(&a[k * esize], temp, esize);
        }
    }
    free(pval);
    free(temp);
    return k; 

} 

//划分即排序 
int  qksort(void *data, int size, int esize, int i, int k, int (*compare)(const void *key1, const void *key2))
{
    int j;
    while(i < k)
    {
        if((j = partition(data, esize, i, k, compare)) < 0)
            return -1;
        if(qksort(data, size, esize, i, j,compare))
            return -1;
        i = j + 1;
    }
    return 0;
}

3、快速排序的例子-目录列表

int directls(const char *path, Directory **dir)
{
    DIR *dirptr;
    Directory *temp;
    struct dirent *curdir;
    int count, i;

    //先打开路径 
    if((dirptr = opendir(path)) == NULL)
        return -1;
    *dir = NULL;
    count = 0;

    //先把每个文件的名字读到字符串数组dir中 
    while((curdir = readdir(dirptr)) != NULL)
    {
        count++;
        if((temp = (Directory *)realloc(*dir, count * sizeof(Directory))) == NULL)
        {
            free(*dir);
            return -1;
        }
        else
        {
            *dir = temp;
        }
        strcpy( ((*dir)[count - 1]).name, curdir->d_name );
    } 
    closedir(dirptr);
    if(qksort(*dir, count, sizeof(Directory), 0, count - 1, compare_dir) != 0)
        return -1;
    return count;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值