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;
}