C语言实现
#include <stdio.h>
#define N 9
int A[N] = { 10, -3 , 28, 76, 37, 55, -1, 99, 11};
void printArr(int arr[], int length)
{
int i;
for (i = 0; i < N; i++)
{
printf("%d ", A[i]);
}
printf("\n");
}
void quick_sort(int a[],int numsize) //a是整形数组,numsize是元素个数
{
int i = 0, j = numsize-1;
int val = a[0];//指定参考值val大小
if(numsize>1)//确保数组长度至少为2,否则无需排序
{
while(i<j)//循环结束条件
{
for( ; i < j; j--) //从后向前搜索比val小的元素,找到后填到a[i]中并跳出循环
if(a[j]<val)
{
a[i]=a[j];
printf("参考值%d,前 <-- 后 找a[j--]<%d的元素| ", val, val);
printArr(a, numsize);
break;
}
for(;i<j;i++)//从前往后搜索比val大的元素,找到后填到a[j]中并跳出循环
if(a[i]>val)
{
a[j]=a[i];
printf("参考值%d,前 --> 后 找a[i++]>%d的元素| ", val, val);
printArr(a, numsize);
break;
}
}
a[i]=val; //将保存在val中的数放到a[i]中
printf("参考值%d,整理结果\t\t | ", val);
printArr(a, numsize);
quick_sort(a,i); //递归,对前i个数排序
quick_sort(a+i+1,numsize-1-i); //对i+1到numsize这numsize-1-i个数排序
}
}
int main()
{
quick_sort(A, N);
return 0;
}
运行结果
[root@centos6 data]# gcc test.c
[root@centos6 data]# ./a.out
原数列| 10 -3 28 76 37 55 -1 99 11
参考值10,前 <– 后 找a[j–]<10的元素| -1 -3 28 76 37 55 -1 99 11
参考值10,前 –> 后 找a[i++]>10的元素| -1 -3 28 76 37 55 28 99 11
参考值10,整理结果 | -1 -3 10 76 37 55 28 99 11
参考值-1,前 <– 后 找a[j–]<-1的元素 | -3 -3 10 76 37 55 28 99 11
参考值-1,整理结果 | -3 -1 10 76 37 55 28 99 11
参考值76,前 <– 后 找a[j–]<76的元素 | -3 -1 10 11 37 55 28 99 11
参考值76,前 –> 后 找a[i++]>76的元素| -3 -1 10 11 37 55 28 99 99
参考值76,整理结果 | -3 -1 10 11 37 55 28 76 99
参考值11,整理结果 | -3 -1 10 11 37 55 28 76 99
参考值37,前 <– 后 找a[j–]<37的元素| -3 -1 10 11 28 55 28 76 99
参考值37,前 –> 后 找a[i++]>37的元素| -3 -1 10 11 28 55 55 76 99
参考值37,整理结果 | -3 -1 10 11 28 37 55 76 99
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
A[N] | -3 | -1 | 10 | 11 | 37 | 28 | 55 | 76 | 99 |
结果分析
假设有两个指针,i指向开始,j指向结束。i从前向后运动做比较,j从后向前运动做比较,当两者交集的时候,比较结束。
1.参考值10
这是最开始的情况,将数组第一个元素A[0]作为参考值,另找一变量保存该值,i=0
10 -3 28 76 37 55 -1 99 11
1>后–>前
然后,先从后往前找小于10的数,j递减,i=0,j=8
下标 | i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | j |
A[N] | 10 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
11比10大,不符合条件,略过,继续向前找,i=0,j=7
下标 | i | 1 | 2 | 3 | 4 | 5 | 6 | j | 8 |
A[N] | 10 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
99比10大,不符合条件,略过,继续向前找,i=0,j=6
下标 | i | 1 | 2 | 3 | 4 | 5 | j | 7 | 8 |
A[N] | 10 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
-1比10小,符合条件,将-1拷贝到参考值10的位置A[i]去,则此时A[j]位置的数据已经没有意义了,我们可以将它置0或者不管也行,将来会将别的值拷贝到此位置,i=0,j=6
下标 | i | 1 | 2 | 3 | 4 | 5 | j | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
停止当前方向查找,转向从前往后找。
2>前–>后
接上一步,这次以原来参考值所在位置A[0+1],从前向后查找大于10的数,i递增,i=1,j=6
下标 | 0 | i | 2 | 3 | 4 | 5 | j | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
-3比10小,不符合条件,略过,继续向后找,i=2,j=6
下标 | 0 | 1 | i | 3 | 4 | 5 | j | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | -1 | 99 | 11 |
28比10大,符合条件,将28拷贝A[j]去,则此时A[i]位置的数据已经没有意义了,我们可以将它置0或者不管也行,将来会将别的值拷贝到此位置,i=2,j=6
下标 | 0 | 1 | i | 3 | 4 | 5 | j | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | 28 | 99 | 11 |
停止当前方向查找,此时发现i依然小于j,对参考值10的整理还没有结束。再转向从后往后前查找,直到i和j相遇为止。
3>后–>前
接上一步,这次从后往前找小于10的数,j递减,i=2,j=5
下标 | 0 | 1 | i | 3 | 4 | j | 6 | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | 28 | 99 | 11 |
55比10大,不符合条件,略过,继续向前找,i=2,j=4
下标 | 0 | 1 | i | 3 | j | 5 | 6 | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | 28 | 99 | 11 |
37比10大,不符合条件,略过,继续向前找,i=2,j=3
下标 | 0 | 1 | i | j | 4 | 5 | 6 | 7 | 8 |
A[N] | -1 | -3 | 28 | 76 | 37 | 55 | 28 | 99 | 11 |
76比10大,不符合条件,略过,继续向前找,i=2,j=2
当i=2,j=2时,此时发现i和j相遇了,则停止查找。
4>参考值归位
i和j已经相遇,将参考值10拷贝到A[i]的位置
下标 | 0 | 1 | i=i | 3 | 4 | 5 | 6 | 7 | 8 |
A[N] | -1 | -3 | 10 | 76 | 37 | 55 | 28 | 99 | 11 |
至此,对参考值10的整理已经结束,可以看到10的左侧都是小于10的数,10的右侧都是大于10的数。
这这是完成了第一轮整理,接下来,还要分两部分递归,将10的左侧{A[0]~A[1]}和10的右侧{A[3]~A[8]}作为子集,分别按以上相同的步骤递归调用函数整理。
2.参考值-1
整理过程就不写了,与参考值10的过程一样,这里直接给出整理完成的结果
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
A[N] | -3 | -1 | 10 | 76 | 37 | 55 | 28 | 99 | 11 |
3.参考值76
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
A[N] | -3 | -1 | 10 | 76 | 37 | 55 | 28 | 99 | 11 |
4.参考值11
这个没有可移动的,跳过
5.参考值37
下标 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
A[N] | -3 | -1 | 10 | 11 | 28 | 37 | 55 | 76 | 99 |
至此整个排序结束,已经是有序队列!
始于2008-10-19,西理工;更新至2016-06-05,杭州。