<<几种常见内部排序算法分析与实现(C语言描述)>>
Tags: alg,c,blog,book,linux
1. 插入排序
1.1 算法思想
插入排序算法的主要思想是:
1) 把要排序的序列分为两部分: 已排序部分(A)和未排序部分(B); 由于已排序部分和未
排序部分有显示的位置分隔, 我们也可以将已排序部分称之为序列的前部分, 将未排
序 部分称之为序列的后部分. 显然在算法开始前, 已排序部分为空, 未排序部分为
整个待排序序列.
2) 从B中取第一个元素(b), 然后从后往前依次从A中取出元素(a)与b比较, 若b<a, 则把
a往后移动一个位置; 否则, 为b找到了其正确位置(a的位置的下一个位置), 把b放入
该位置(记住: A是已经排序好的).
3) 对A增加一个元素: b, 对B减少一个元素: b.
4) 重复 2 – 3 步骤, 直至B为空.
1.2 实现
// #c---
/*==========================================================================*
* @Description:
* 插入排序
*
* @Param base
* @Param nmemb
* @Param size
* @Param compar
*==========================================================================*/
void Sort_insertSort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
#define SWAP(a, b, t) ( (t)=(a), (a)=(b), (b)=(t) )
assert(base != NULL && nmemb >= 1 && size >= 1 && compar != NULL);
char *i, *j, t, *b, *e;
char *bot = (char*)base;
char *top = bot + nmemb * size;
for ( i = bot + size; i < top; i += size )
{
for ( j = i; (j-=size) >= bot && compar(i, j) < 0; )
{ }
if ( i != (j+=size) )
{
for ( b = j, e = i-1; b < e; b++, e-- )
SWAP(*b, *e, t);
for ( b = i, e = i+size-1; b < e; b++, e-- )
SWAP(*b, *e, t);
for ( b = j, e = i+size-1; b < e; b++, e-- )
SWAP(*b, *e, t);
}
}
#undef SWAP
}
// #c---end
1.3 算法复杂度分析
从插入排序的算法思想中, 我们很容易得知其空间复杂度为 O(1), 时间复杂度为 O(N^2).
2. 选择排序
2.1 算法思想
选择排序算法的主要思想是:
1) 把要排序的序列分为两部分: 已排序部分(A)和未排序部分(B); 由于已排序部分和未
排序部分有显示的位置分隔, 我们也可以将已排序部分称之为序列的前部分, 将未排
序部分称之为序列的后部分. 显然在算法开始前, 已排序部分为空, 未排序部分为整
个待排序序列.
2) 遍历B中的每一个元素, 找到B中的最小元素(b), 把b与A之后的那个元素交换.
3) 对A增加一个元素: b, 对B减少一个元素: b.
4) 重复 2 – 3 步骤, 直至B为空.
2.2 实现
// #c---
/*==========================================================================*
* @Description:
* 选择排序
*
* @Param base
* @Param nmemb
* @Param size
* @Param compar
*
*==========================================================================*/
void Sort_selectSort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
#define SWAP(a, b, t) ( (t)=(a), (a)=(b), (b)=(t) )
assert(base != NULL && nmemb >= 1 && size >= 1 && compar != NULL);
int s;
char t, *i, *j, *min;
char *left = base;
char *right = left + (nmemb - 1) * size;
for ( i = left; i <= right - size; i += size )
{
min = i;
for ( j = i + size; j <= right; j += size )
{
if ( compar(j, min) < 0 )
min = j;
}
if ( i != min )
for ( s = 0; s < size; s++ )
SWAP(*(i+s), *(min+s), t);
}
#undef SWAP
}
// #c---end
2.3 算法复杂度分析
选择排序的空间复杂度为 O(1), 时间复杂度为 O(N^2).
3. 冒泡排序
3.1 算法思想
冒泡排序算法的主要思想是:
1) 把要排序的序列分为两部分: 已排序部分(A)和未排序部分(B); 由于已排序部分和未排
序部分有显示的位置分隔, 我们也可以将已排序部分称之为序列的前部分, 将未排序
部分称之为序列的后部分. 显然在算法开始前, 已排序部分为空, 未排序部分为整个
待排序序列.
2) 对B进行从后往前遍历, 取所有相邻的两个元素对(b1和b2, b1较靠后, b2较靠前)作比
较; 若b1<b2, 则交换b1和b2. 当遍历完B中所有的元素后, B中的第一个元素(b)即放
置到了正确的位置上.
3) 对A增加一个元素: b, 对B减少一个元素: b.
4) 重复 2 – 3 步骤, 直至B为空.
3.2 实现
// #c---
/*==========================================================================*
* @Description:
* 冒泡排序
*
* @Param base
* @Param nmemb
* @Param size
* @Param compar
*
*==========================================================================*/
void Sort_bubbleSort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
#define SWAP(a, b, t) ( (t)=(a), (a)=(b), (b)=(t) )
assert(base != NULL && nmemb >= 1 && size >= 1 && compar != NULL);
int s, isSwap;
char t, *i, *j;
char *left = base;
char *right = base + (nmemb - 1) * size;
for ( i = left; i < right; i += size )
{
isSwap = 0;
for ( j = right; j > i; j -= size )
{
if ( compar(j, j-size) < 0 )
{
isSwap = 1;
for ( s = 0; s < size; s++ )
SWAP(*(j+s), *(j-size+s), t);
}
}
if ( isSwap == 0 )
break;
}
#undef SWAP
}
// #c---end
3.3 算法复杂度分析
冒泡排序的空间复杂度为 O
(1), 时间复杂度为 O
(N^2).
4. 合并排序
4.1 算法思想
1) 将序列分为两个子序列.
2) 对两个子序列递归地进行合并排序.
3) 把此两个子序列
(已排序)合并为一个有序序列.
4.2 实现
// #c---
/*==========================================================================*
* @Description:
* 合并排序之合并例程
*
* @Param left
* @Param center
* @Param right
* @Param size
* @Param compar
* @Param tmparray
*
*==========================================================================*/
static void SortST_memge(char *left, char *center, char *right, int size,
int(*compar)(const void *, const void *), char *tmparray)
{
#define COPY_SIZE(d, s) \
do { \
for ( i = 0; i < size; i++ ) \
*((d) + i) = *((s) + i); \
} while ( 0 )
int i;
char *Lright = center;
char *Rright = right;
char *Lpcur = left;
char *Rpcur = center + size;
char *Tpcur = tmparray;
for ( ; Lpcur <= Lright && Rpcur <= Rright; Tpcur += size )
{
if ( compar(Lpcur, Rpcur) < 0 )
{
COPY_SIZE(Tpcur, Lpcur);
Lpcur += size;
}
else
{
COPY_SIZE(Tpcur, Rpcur);
Rpcur += size;
}
}
for ( ; Lpcur <= Lright; Lpcur += size, Tpcur += size )
COPY_SIZE(Tpcur, Lpcur);
for ( ; Rpcur <= Rright; Rpcur += size, Tpcur += size )
COPY_SIZE(Tpcur, Rpcur);
for ( Lpcur = left; Lpcur <= right; Lpcur += size, tmparray += size )
COPY_SIZE(Lpcur, tmparray);
#undef COPY_SIZE
}
/*==========================================================================*
* @Description:
* 合并排序
*
* @Param left
* @Param right
* @Param size
* @Param compar
* @Param tmparray
*
*==========================================================================*/
static void Sort_mergeSort_priv(char *left, char *right, int size,
int(*compar)(const void *, const void *), char *tmparray)
{
if ( left < right )
{
char *center = left + ((right - left) / size / 2) * size;
Sort_mergeSort_priv(left, center, size, compar, tmparray);
Sort_mergeSort_priv(center + size, right, size, compar, tmparray);
SortST_memge(left, center, right, size, compar, tmparray);
}
}
/*==========================================================================*
* @Description:
* 合并排序驱动例程
*
* @Param base
* @Param nmemb
* @Param size
* @Param compar
*
*==========================================================================*/
void Sort_mergeSort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
assert(base != NULL && nmemb >= 1 && size >= 1 && compar != NULL);
char *left = base;
char *right = base + (nmemb - 1) * size;
char *tmparray;
tmparray = malloc(nmemb * size);
if ( tmparray == NULL )
return;
Sort_mergeSort_priv(left, right, size, compar, tmparray);
free(tmparray);
}
// #c---end
4.3 算法复杂度分析
归并排序算法是运用分治思想的典范, 其空间复杂度为 O(N), 时间复杂度为 O(NlogN).
5. 快速排序
5.1 算法思想
1) 从输入序列中任意选取一个元素(k)作枢纽元;
2) 遍历整个序列, 对于小于等于k的元素放在左边(L), 对于大于k的元素放在右边(R);
3) 对子序列L和R递归地进行快速排序; 直到序列中只有一个若零个元素, 退出递归.
5.2 实现
// #c---
/*==========================================================================*
* @Description:
* 取三者间的中间值
*
* @Param left
* @Param right
* @Param size
* @Param compar
*
* @Returns:
*==========================================================================*/
static char* Sort_median3(char *left, char *right, int size,
int(*compar)(const void *, const void *))
{
#define SWAP(a, b, t) ( (t)=(a), (a)=(b), (b)=(t) )
int s;
char t;
// char *center = left + (right - left) / 2; // 错误!!
// 每一步计算都必须取整! 才不至于最后的结果位于字节内!
char *center = left + (((right - left) / size) / 2) * size;
if ( compar(left, center) > 0 )
for ( s = 0; s < size; s++ )
SWAP(*(left+s), *(center+s), t);
if ( compar(left, right) > 0 )
for ( s = 0; s < size; s++ )
SWAP(*(left+s), *(right+s), t);
if ( compar(center, right) > 0 )
for ( s = 0; s < size; s++ )
SWAP(*(center+s), *(right+s), t);
for ( s = 0; s < size; s++ )
SWAP(*(center+s), *(right-size+s), t);
return right - size;
#undef SWAP
}
/*==========================================================================*
* @Description:
* 快速排序
*
* @Param left
* @Param right
* @Param size
* @Param compar
*==========================================================================*/
static void Sort_quicklySort_priv(char *left, char *right, int size,
int(*compar)(const void *, const void *))
{
#define SWAP(a, b, t) ( (t)=(a), (a)=(b), (b)=(t) )
int s;
char t, *i, *j, *pivot;
if ( left + SORT_CUTOFF * size <= right )
{
pivot = Sort_median3(left, right, size, compar);
i = left;
j = right - size;
for ( ; ; )
{
for ( i += size; compar(i, pivot) < 0; i += size ) { }
for ( j -= size; compar(j, pivot) > 0; j -= size ) { }
if ( i < j )
{
for ( s = 0; s < size; s++ )
SWAP(*(i+s), *(j+s), t);
}
else
break;
}
for ( s = 0; s < size; s++ )
SWAP(*(i+s), *(right-size+s), t);
Sort_quicklySort_priv(left, i - size, size, compar);
Sort_quicklySort_priv(i + size, right, size, compar);
}
else
Sort_insertSort(left, (right-left)/size + 1, size, compar);
#undef SWAP
}
/*==========================================================================*
* @Description:
* 快速排序驱动例程
*
* @Param base
* @Param nmemb
* @Param size
* @Param compar
*==========================================================================*/
void Sort_quicklySort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *))
{
assert(base != NULL && nmemb >= 1 && size >= 1 && compar != NULL);
if ( nmemb <= 1 )
return;
if ( nmemb >= SORT_CUTOFF )
Sort_quicklySort_priv(base, base + (nmemb-1)*size, size, compar);
else
Sort_insertSort(base, nmemb, size, compar);
}
// #c---end
5.3 算法复杂度分析
快速排序算法也是运用分治思想, 其空间复杂度为 O(1), 时间复杂度为 O(NlogN).