杂谈:指针和数组
对于数组编译器可以自动推到出内部元素的大小,可以通过sizeof或者模板,
但是指针,则不能通过模板或者sizeof推到出尺寸大小,原因在于sizeof和模板都是在编译期起作用~
所以使用模板写排序函数时候,为了兼容指针和数组,要么传首指针和size,要么像STL中的传首位指针。本文使用前者。
快速排序
快速排序是最实用的排序方法,虽然它最坏运行时间为O(n^2), 但是它的平均期望运行时间为O(nlgn),std::sort在元素个数小于32的情况下使用的就是quick_sort排序(大于32则使用堆排序)。
快速排序的核心思想是将数组划分为三部分,如果大到小顺序排序,则一次划分将数组分为小于枢轴值的区间,等于枢轴值,大于枢轴值的区间。然后分段递归划分。
代码如下:
在debug模式下,输出快速排序过程:
后记
如果要逆序从大到小排序,只需要修改划分函数中的if比较表达式,或者像STL中传入一个函数指针进去。导论中提到了一个stooge_sort排序算法,效率实在是低~
快排分区算法常见的是:双边交换的算法。
分区算法-2011-9-15
int partition(int* ptr, int beg, int end)
{
int povit = ptr[beg];
int h = beg;
for (int k=h; k<=end; k++)
{
if (ptr[k] < povit)
{
h = h+1;
swap(ptr[h], ptr[k]);
}
}
swap( ptr[h], ptr[beg] );
return h;
}
int double_partition(int* ptr, int beg, int end)
{
int h = beg;
int k = end;
int povit = ptr[beg];
while ( h < k)
{
while (h < k && ptr[k] > povit)
--k;
ptr[h] = ptr[k];
while (h < k && ptr[h] < povit)
++h;
ptr[k] = ptr[h];
}
ptr[h] = povit;
return h;
}
int select_kth_element(int* ptr, int beg, int end, int kth)
{
if (beg > end)
return -1;
// int pos = partition(ptr, beg, end);
int pos = double_partition(ptr, beg, end);
/*
if (pos == kth) // 直接位置比较
return ptr[pos];
else if (pos > kth)
return select_kth_element(ptr, beg, pos-1, kth);
return select_kth_element(ptr, pos+1, end, kth);
*/
int offset = pos - beg; // 偏移量比较
if (offset == kth)
return ptr[pos];
else if (offset > kth)
return select_kth_element(ptr, beg, pos-1, kth);
// k - (offset+1)
return select_kth_element(ptr, pos+1, end, kth-offset-1);
}