快速排序-qsort
有几点记录一下:
1.快速排序的时间复杂度是nlogn,推到《数据结构》上有,看不懂。在记录为有序时,快速排序退化成冒泡排序。
2.注意是low跟high记录交换,而并非跟枢轴记录交换。前者才能保证low,high两部分的基本有序。只不过要注意,low,high记录交换后,low记录本身存在偶然性,即其跟枢轴记录的相对大小不确定。需要比较,然后做出交换动作,才能保证前后两个分支的基本有序,如下面绿色注释部分所指出的。
================2013/5/2更新===========================
Programming Pearls第11章,着重介绍了快速排序,其讲解的深度和算法的优美度都远大于严蔚敏的《数据结构》第十章所介绍的。挑一种比较基本的快速排序实现如下,并做一些笔记
// 解决了原先swap相同变量的问题
#define swap(a, b) \
if (a!=b)\
{\
a = (a)+(b);\
b = (a)-(b);\
a = (a)-(b);\
}
if (a!=b)\
{\
a = (a)+(b);\
b = (a)-(b);\
a = (a)-(b);\
}
void qsort(int* L, int size)
{
{
// 确保递归循环能结束,而非死循环
if (size <= 1)
return;
int i = 0, j = size;
while (1)
{
do
{
i ++;
} while (i<size && L[i]<t);
if (size <= 1)
return;
// i,j可以理解为从两侧开始扫描,
// while循环的目的是为了将数组转变为如下图
// i变量为了找比t大的数,j变量为了找比t小的数
int t = L[0];int i = 0, j = size;
while (1)
{
do
{
i ++;
} while (i<size && L[i]<t);
// 此时i有两种可能:
// 1)i==u, 2)x[i]>=t
do
{
j --;
} while (L[j]>t);
do
{
j --;
} while (L[j]>t);
// 此时j只有一种可能:x[j]<=t
// 当i,j交叉时,说明整个数组扫描完毕
if (i>j)
break;
swap (L[i], L[j]);
}
swap(L[0], L[j]);
qsort(L, j);
qsort(&L[j+1], size-1-j);
}
if (i>j)
break;
swap (L[i], L[j]);
}
swap(L[0], L[j]);
qsort(L, j);
qsort(&L[j+1], size-1-j);
}
整个算法的关键是在那个while(1)循环,如何保证此循环可以正确的结束。
要保证正确,要保证以下三点:
1. 循环结束后,j点左侧的都要小于t,j点右侧都要大于t
2. 循环不变式是i <= j
3. 保证在交换时,i、j没有交叉
============================================================
#include <stdio.h>#include <time.h>
// 注意:不加{},会影响到if分支
#define swap(a, b) \
{\
a = (a)+(b);\
b = (a)-(b);\
a = (a)-(b);\
}
#define dim(a) (sizeof(a)/sizeof(a[0]))
void qsort(int* L, int size);
main()
{
int i;
int a[10] = {0};
srand(time(NULL));
for (i=0; i<dim(a); i++)
{
a[i] = rand() % 100;
}
qsort(a, dim(a));
printf("a: ");
for (i=0; i<dim(a); i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void qsort(int* L, int size)
{
switch (size)
{
case 0:
printf ("empty array is input.\n");
return;
case 1:
printf ("input array has only 1 member.\n");
return;
case 2:
if (L[0] > L[1])
{
swap(L[0], L[1]);
}
return;
default:
break;
}
int low = 1, high = size - 1;
while(low < high)
{
while (low<high && L[low] <= L[0])
{
low ++;
}
if (low != high)
swap(L[low], L[high]);
while (low<high && L[high] >= L[0])
{
high --;
}
if (low != high)
swap(L[low], L[high]);
}
int i;
int a[10] = {0};
srand(time(NULL));
for (i=0; i<dim(a); i++)
{
a[i] = rand() % 100;
}
qsort(a, dim(a));
printf("a: ");
for (i=0; i<dim(a); i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void qsort(int* L, int size)
{
switch (size)
{
case 0:
printf ("empty array is input.\n");
return;
case 1:
printf ("input array has only 1 member.\n");
return;
case 2:
if (L[0] > L[1])
{
swap(L[0], L[1]);
}
return;
default:
break;
}
int low = 1, high = size - 1;
while(low < high)
{
while (low<high && L[low] <= L[0])
{
low ++;
}
if (low != high)
swap(L[low], L[high]);
while (low<high && L[high] >= L[0])
{
high --;
}
if (low != high)
swap(L[low], L[high]);
}
//////////////////////
// 注意:这里low的位置存在随机性,《数据结构》中并没有注意到这点
if (L[0] > L[low])
swap(L[0], L[low])
else if (L[0] < L[low])
{
low --;
if (low != 0)
swap(L[0], L[low])
}
if (L[0] > L[low])
swap(L[0], L[low])
else if (L[0] < L[low])
{
low --;
if (low != 0)
swap(L[0], L[low])
}
//////////////////////
qsort(L, low);
if (low < size-1)
qsort(&L[low+1], size-low-1);
}
qsort(L, low);
if (low < size-1)
qsort(&L[low+1], size-low-1);
}