(1)在待排序的序列中随便找一个数作为基准数(用来参照的数),假设将第一个数作为基准数,接下来,需要将这个序列中所有比基准数大的数放在它的右边,比基准数小 的 数放在它的左边。
(2)目标是将基准数挪到序列中间的某个位置,假设这个位置是k。现在就需要寻找这个k,并且以第k位为分界点,左边的数都小于等于基准值,右边的数都大于等于基准值。
(3)如何找到位置k:我们采用从序列的两端向中间扫描的方法,假设 i 指向左端的第一个数,j 指向右端第一个数(最后一个数)。每次进行扫描时,先让 j 移动,当扫描到小于基准数的时候,i 开始移动,直至找到大于基准数,将这俩个数值进行交换,j 和 i 继续扫描,交换,直至 i 和 j 相遇,说明第一轮扫描结束,将该位置与基准数交换,这样基准数的左边全是小于它,基准数的右边全是大于它。
问题:为什么是右边 j 先进行扫描? (先思考,后面有解释)(4)这样以k 位置分出俩个序列,左边是小于基准数的序列,右边是大于基准数的序列。我们再通过(1),(2)和(3)步骤对俩个序列进行排序,以此类推,直至再也分不出子序列为止。
template<class T>
void list<T>::quicksort(int low,int high)
{
if (low < high)
{
int pos = Arrayadjust(low,high); //返回调整后的基准数的位置
quicksort(0,pos - 1);//对右区域进行排序
quicksort(pos + 1, high); //对左区域进行排序
}
}
方法一:
数值交换法:
template<class T>
int list<T>::Arrayadjust(int low, int high) //区间的排序
{
node<T> x = vec[low];
int xx = low; //保存基准位置
while (low < high)
{
while (low<high&&vec[high].data >= x.data) //从右到左寻找小于基准的数
--high;
while (low<high&& x.data >= vec[low].data)//从左到右寻找大于基准的数
++low;
if (low < high)
{
T dt = vec[high].data;
vec[high].data = vec[low].data;
vec[low].data = dt;
--high;
++low;
}
}
T tp = vec[high].data; //交换基准值
vec[high].data = x.data;
vec[xx].data = tp;
return high;
}
这种方法是对序列的值进行互相交换,左边查找大于基准的数,右边查找小于基准的数。当找到k位置时候,与基准的值进行交换。
方法二:
挖坑法:
template<class T>
int list<T>::Arrayadjust(int low,int high) //区间的排序
{
node<T> x = vec[low]; //基准位置
while (low < high)
{
while (vec[high].data > x.data) //从右到左寻找小于基准的数
--high;
if (low < high)
{
vec[low].data = vec[high].data;
++low;
}
while (low<high&&vec[low].data<x.data)//从左到右寻找大于基准的数
{
++low;
}
if (low < high)
{
vec[high].data = vec[low].data;
--high;
}
}
vec[low].data = x.data;
return low;
}
1.http://developer.51cto.com/art/201403/430986.htm
2.http://blog.csdn.net/morewindows/article/details/6684558
问题答案:如果是左边先扫描,在定位K位置时,很有可能将大于基准的值交换到左边,造成排序失败,因为左边扫描时只有在遇到大于基准值才停止。