在程序设计实践上看到这个简单的快速排序,用模板重新写了一遍,加深一下印象。平均算法复杂度为O(nlogn)。
其中寻找支点元素pivot有多种方法,不同的方法会导致快速排序的不同性能。根据分治法平衡子问题的思想,希望支点元素可以使p[m..n]尽量平均地分为两部分,但实际上很难做到。下面给出几种寻找pivot的方法。
1.选择p[m..n]的第一个元素p[m]的值作为pivot;
2.选择p[m..n]的最后一个元素p[n]的值作为pivot;
3.选择p[m..n]中间位置的元素p[k]的值作为pivot;
4.选择p[m..n]的某一个随机位置上的值p[random(n-m)+m]的值作为pivot;
按照第4种方法随机选择pivot的快速排序法又称随机化版本的快速排序法,在实际应用中该方法的性能也是最好的。本程序使用第4种方法。要求节点类型支持比较运算符。
template<typename T>
void quicksort(T* v, int n)
{
if (n<=1)
return;
int last = 0;
int pivot = rand()%n;
swap(v, 0, pivot);
for (int i = 1; i < n; i++)
{
if (v[i]<v[0])
swap(v, ++last, i);
}
swap(v, last, 0);
quicksort(v, last);
quicksort(v+last+1, n-last-1);
}
template<typename T>
void swap(T* v, int i, int j)
{
T tmp = v[i];
v[i] = v[j];
v[j] = tmp;
}
随手写一个不太好看的测试程序
struct str
{
str(const char* a)
{
assert(a);
v = new char[strlen(a)+1];
strcpy(v, a);
}
str(const str& a)
{
assert(a.v);
v = new char[strlen(a.v)+1];
strcpy(v, a.v);
}
~str()
{
delete [] v;
}
void operator = (const str& a)
{
if (this == &a)
return;
assert(a.v);
delete [] v;
v = new char[strlen(a.v)+1];
strcpy(v, a.v);
}
bool operator == (const str& a) const
{
return (strcmp(v, a.v)==0);
}
bool operator > (const str& a) const
{
return (strcmp(v, a.v)>0);
}
bool operator < (const str& a) const
{
return (strcmp(v, a.v)<0);
}
char* v;
};
int main(int argc, char* argv[])
{
int* array = new int [10];
for(int i = 0; i < 10; i++)
array[i] = rand();
quicksort(array, 10);
for(i = 0; i < 10; i++)
{
cout<<array[i]<<endl;
}
str s[] = {"bd", "e", "ba", "a"};
quicksort(s, 4);
for(i = 0; i < 4; i++)
{
cout<<s[i].v<<endl;
}
return 0;
}
posted on 2007-12-29 14:31
小四 阅读(401)
评论(0) 编辑 收藏 引用 所属分类:
算法与数据结构