快速排序
看了《程序设计实践》的开头,就碰到一个习题叫用用循环实现快速排序,开始准备pass掉的,但是一想学习过程中要注意细节,也就决定去写了,零零散散的花了不少时间,可见其中的一些微妙之处。喜欢其中的一句话,算是激励的:“Hoare描述了用循环写快速排序是如何困难的,进而发现用递归做快速排序实在是太方便了”,也就更有一些动力了,^_^。
首先,写了一个递归的快速排序。
int quick_sort(int array[], int start, int end) { if (start >= end) return 0; int nPoint = array[start]; int nLast = start+1; for (int i = start+1; i < end; i++) { if (array[i] < nPoint) { swap(array[i], array[nLast]); nLast++; } } swap(array[start], array[nLast-1]); quick_sort(array, start, nLast-1); quick_sort(array, nLast, end); return 1; }
小结:
(1)自己觉得写完之后,有一种很笨拙的感觉。特别是下标那里,不是很清晰,要调试打印,发现不对之后,再把坐标改成1啊,加个1之类的。自己觉得非常的不专业,也希望老手给点建议和宝贵经验。
(2)写完之后,对于快速排序有了一个清晰的认识:就是找到一个基准点,然后保证基准点两边都是比该点大或者比该点小的。另外一个觉得有点意思的就是,会对算法复杂度认识更清晰一些,简单的考虑一个就是:如果你要和基准点比较,起码要便利一遍(n),二分的规则就是log2n,那就是O(n*log2n)。那最坏情况n^2怎么理解呢?例如,所有元素都相等,那么每次遍历都是比较n次,而二分法在他最坏的情况下,也就是n了,所以就是O(n^2)。对于复杂度,就是静下心来看进去,最后发现也就是1+1=2的清晰逻辑,会很舒服。
接下来,是自己实现的循环实现的快速排序。
// 循环-快速排序 int quick_sort_onetime(int array[], int start, int end); int quick_sort_for(int array[], int start, int end){ int nPoint[32] = {0}; int nPointTemp[32] = {0}; int nNum = 0; int k = 0; //for nPointTemp int nTimes = (int)(log(end)/log(2)); nNum = 1; k = 1; nPoint[0] = 0; for(int i = 0; i <= nTimes; i++) { k = 0;//根据节点循环,第一次是一个 for (int j = 0; j < nNum; j++) {int nSubStart = nPoint[j]; int nSubN = end - nSubStart;if(j+1 < nNum) nSubN = nPoint[j+1]-nSubStart; int nTemp = quick_sort_onetime(array, nSubStart, nSubN); nPointTemp[k++] = nPoint[j]; nPointTemp[k++] = nTemp+1; //从后面一位开始 } for(int i = 0; i < k; i++) nPoint[i] = nPointTemp[i]; nNum = k; } return 1; } int quick_sort_onetime(int array[], int start, int end) { if (end <= 1) return 0; int nPoint = array[start]; int nLast = start+1;for(int i1 = start; i1 < start+end; i1++) printf("%d\n", array[i1]); for (int i = start+1; i < start+end; i++) { if (array[i] < nPoint) { swap(array[i], array[nLast]); nLast++; } } swap(array[start], array[nLast-1]);for(int i2 = start; i2 < start+end; i2++) printf("%d\n", array[i2]); return nLast-1; }
小结:
(1)也是非常的糟糕,像小孩子的作品。
(2)而这,自己却花了相对于不少的时间。一个是,用递归的思路写循环你就是找死。其次,用递归的复杂度去写这个问题,就明晰起来,就是每次遍历一遍,比较n次。中间有很多节点,一节一节的像个火车,每次处理一节车厢,然后找到该节车厢基准点继续把车厢截断成更小的,知道车厢是最小的一个单元的时候,也就不需要比较了。说的有点模糊,看下图:
(3)自己写完之后,搜索了一下别人的结果。下面是一位别人写的,使用栈实现的,看起来就专业很多,但思想还是差不多,主要是保存中间节点的方式不一样。【http://www.cnblogs.com/zhangchaoyang/articles/2234815.html】