1.快排递归版
如上图所示
数组第一个数值为key,设立两个指针L和R从数组两边向中间移动,右边指针先移动,如果右边指针指向比key小的数值那么key继续向中间移动,直到指向的数值比key要大停止。左边指针在右边指针停止后移动,如果指向了比key数值小的那么继续向中间移动,直到指向比key要大或者与R指针指向的位置相同停下。
再左边指针停下后如果L指针和R指针没有重合那么交换L和R指向位置的数据,如果L指针和R指针重合那么交换key和R或L指针指向的数据。这样在key左边的数据就比key小在key右边的数据就比key要大。我们再来看图理解
通过不断的递归最终达到排序的目的,使每个数都放在自己大小对应的位置。
重点:在递归只剩一个数或没有数的时候return
代码实现如下
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
if (right - left < 10)
{
InsertSort(a, right-left);
return;
}
int mid = Getmid(a, left, right);
swap(&a[left], &a[mid]);
int key1 = left;
int begin = left + 1, end = right;
while (begin < end)
{
while (a[end] > a[key1] && begin != end)
{
end--;
}
while (a[begin] < a[key1]&& begin!=end)
{
begin++;
}
swap(&a[begin], &a[end]);
if (begin == end)
{
swap(&a[key1], &a[end]);
}
}
QuickSort(a, end + 1, right);
QuickSort(a, left, end - 1);
}
2.快排非递归
快排非递归和递归相似,主要是要考虑如何存放数据(函数处理时左右的位置数据)
我们可以设置一个栈来存储数据left 和 right
每次排完序将两边的左右位置数据放入栈中,下一次排序在将栈中的数据拿出来用,用完再将两边的数据放入栈中,当两边其中有一边的数据个数只有一个或者是一个数据都没有,那么就不需要将左右两边的位置数据放入栈中。当栈中没有数据时停止循环,排序结束。
代码实现如下
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int PartSort1(int* a, int left, int right)
{
int MID = Getmid(a, left, right);
swap(&a[left], &a[MID]);
int begin = left;
int keyi = left;
int end = right;
while (begin<end)
{
while (a[keyi] <= a[end] && begin < end)
{
end--;
}
while (a[keyi] >= a[begin] && begin < end)
{
begin++;
}
swap(&a[begin], &a[end]);
}
swap(&a[keyi], &a[begin]);
return begin;
}
void QuickSortNonR(int* a, int left, int right)
{
ST SQ;
STInit(&SQ);
int begin = left;
int end = right;
STPush(&SQ, begin);
STPush(&SQ, end);
while (!STEmpty(&SQ))
{
end = STTop(&SQ);
STPop(&SQ);
begin = STTop(&SQ);
STPop(&SQ);
int keyi = PartSort1(a, begin, end);
if (keyi - 1> begin)
{
STPush(&SQ, begin);
STPush(&SQ, keyi - 1);
}
if (keyi + 1 < end)
{
STPush(&SQ, keyi + 1);
STPush(&SQ, end);
}
}
}
3.快排前后指针法
快排前后指针依然是设立数组第一个数为key,然后设立两个指针front和back,front指向key的下一个位置,back指向key,排序时back向前走一步,然后front再向前走一步,如果front指向的值比key要大那么front继续向前走一步,如果front指向的值要比key要小那么back向前走一步,并且back指向的值与front进行交换,直到front指向的位置超出数组停止循环,key指向的数值与back进行交换,完成一次排序。
具体流程请看VCR
代码实现如下
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int PartSort3(int* a, int left, int right)
{
int head = left+1, tail = left;
while (head <= right&& head>tail)
{
if (a[head] >= a[left])
{
head++;
}
else
{
tail++;
swap(&a[tail], &a[head]);
}
}
swap(&a[tail], &a[left]);
return tail;
}
4.快排挖坑法
设立一个整形变量key存储数组第一个数,将数组第一个数置为0(不置也没关系)
再设立两个指针一个L指向数组第二个节点,一个R指向数组最后一个节点,从R开始,向中间遍历直到遇到比key小的数停下,然后L指针开始从数组左边向中间遍历直到遇到比key大的数据停下,当L停下后将R指向的数据放入空的位置中将L的数据放入R中,然后继续这样的循环直到L遇上了R,那么他们指向的数据放入空的位置中再将key的数据放入L中便完成了一次排序
代码实现如下
void swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int PartSort2(int* a, int left, int right)
{
int MID = Getmid(a, left, right);
swap(&a[left], &a[MID]);
int begin = left;
int keyi = left;
int num = a[left];
int end = right;
while (begin < end)
{
while (num <= a[end] && begin < end)
{
end--;
}
swap(&a[keyi], &a[end]);
keyi = end;
while (num >= a[begin] && begin < end)
{
begin++;
}
swap(&a[begin], &a[keyi]);
keyi = begin;
}
a[keyi] = num;
return begin;
}