理解快速排序
快速排序(QuickSort)
1 原理
快速排序是基于分治思想上的排序,由冒泡排序改进而来.排序效率较高,时间复杂度:O(n*lgn),最坏时是:O(n^2).主要思想如下:
1 选取基准元素(一般为第一个或最后一个元素)进行分解
2 将分解后的子数组再排序
3 合并
2 实例
下面结合具体的例子分析:
数组如下:
0 | 1 | 2 | 3 | 4 | 5 |
6 |
5 | 98 | 45 | 134 | 23 | 54 |
78 |
首先 i = 0, j = 6,temp(哨点)=num[i]=5
此时已经有temp这个变量保持num[0]的值了,可理解为在此处挖了个坑,需要其他的数据来填充.下面就从j开始往左一直找到一个比temp小的值,然后放在num[0]处,此例中5为最小的所以直到j变为0跟i相等才会停止.i= j = 0,,这样第一轮就结束,i的值没变仍为0,num[0]=temp.就说明num[0]是最小的,这样就把数组分成了两部分:左边的为空,右边的从num[1]~num[6].
下面要排的就是右边的部分,此时 i = 1, j = 6, temp = num[i] = 98
还是从右边找比temp小的数,78就符合,那么把78赋值给num[i](即num[1]),[注意此时num[6]的指还是78没变!!!,i=1,j=6].
数组变为
0 | 1 | 2 | 3 | 4 | 5 | 6 |
5 | 78 | 45 | 134 | 23 | 54 | 78 |
现在 i = 1, j = 6, temp = 98, 98的值不在数组中但没消失.
然后i++,i = 2,现在从左边开始找比temp= 98 大的数,i加到3时,134符合,就把134赋值给num[j],然后j--;
现在的数组是:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
5 | 78 | 45 | 134 | 23 | 54 | 134 |
现在 i = 3, j = 5, temp = 98,此时一轮分解扔未结束!!(因为仍然有i < j)
现在从 j = 5 从右向左找比98小的数,54符合, num[i= 3]= 54, i++ (i= 4)
现在的数组是
0 | 1 | 2 | 3 | 4 | 5 | 6 |
5 | 78 | 45 | 54 | 23 | 54 | 134 |
现在 i= 4 j = 5
然后从 i = 4 找比temp大的数,23不符合则i++; i = j = 5;然后num[i] = temp = 98;至此第二轮分解完毕.
现在成了
0 | 1 | 2 | 3 | 4 | 5 | 6 |
5 | 78 | 45 | 54 | 23 | 98 | 134 |
现在分成了左边的num[1]~ num[4] 比98小,右边比98 大,然后就排num[1]~num[4],右边就一个数不用排了.
3 代码
经过上面的实例分析,以下为代码
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 /* 快速排序 QuickSort 5 * @Date: 2014-08-05 6 * @Author: cjr 7 */ 8 9 int quicksort(int *num,int l,int r) 10 { 11 int i,j,temp,k; 12 if(l < r) 13 { 14 i = l,j = r,temp = num[l]; 15 while(i < j) 16 { 17 while(num[j] > temp && j > i) // 从右往左找比哨点小的值 18 j--; 19 if(i < j) 20 num[i++] = num[j]; 21 while(num[i] < temp && i < j) // 从左往右找比哨点大的值 22 i++; 23 if(i < j) 24 num[j--] = num[i]; 25 } 26 printf("%d ",i); 27 num[i] = temp; 28 for(k = l; k <= r; k++) 29 printf("%d ",num[k]); 30 printf("\n"); 31 quicksort(num,l,i-1); 32 quicksort(num,i+1,r); 33 } 34 return 0; 35 } 36 37 int main() 38 { 39 int num[7] = {5,98,45,134,23,54,78}; 40 int i; 41 quicksort(num,0,6); 42 for(i = 0; i < 7; i++) 43 printf("%d ",num[i]); 44 return 0; 45 }
4 总结反思
自己写的时候犯的第一个错误:每次找到合适的数时只是进行简单的赋值操作而不是互换,本人依旧像其他排序一样进行了交换.
需要注意理解何时才算是分解完成,不是把while(i < j)中走了一遍而是走到 i = j,走一遍仍可能有 i < j 本例就是如此.
本例中的代码体现的分治的思想还不是很明显;快排还有另外的一种写法,可参考一下文章:
http://www.cnblogs.com/foreverking/articles/2234225.html
http://blog.csdn.net/morewindows/article/details/6684558