示例
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 6 | 2 | 7 | 3 | 8 | 9 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 3 | 2 | 7 | 6 | 8 | 9 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 3 | 2 | 6 | 7 | 8 | 9 |
下标 | 0 | 1 | 2 | 3 | 4 | 5 |
数据 | 3 | 2 | 6 | 7 | 8 | 9 |
1 Array.prototype.partition = function (start, end) { 2 var i = start; //首元素 3 var j = end; //最后一个元素 4 var key = this[i]; //设置标兵 5 var temp; 6 while (j > i) { //随着j--和i++,必然会相遇,这时候当前小标两边都排好序了 7 8 //注意,如果右边换过一次,跳出循环,再从左边开始找。 9 while (j > i) {10 if (this[j] < key) {11 temp = this[j];12 this[j] = this[i];13 this[i] = temp;14 break;15 } else {16 --j;17 }18 }19 20 while (j > i) {21 if (this[i] > key) {22 temp = this[i];23 this[i] = this[j];24 this[j] = temp;25 26 break;27 }28 ++i;29 }30 31 }32 console.log(i);33 console.log(A);34 35 return i;36 };37 38 Array.prototype.QUICK_SORT = function (start, end) {39 if (end > start) {40 var q = this.partition(start, end);41 arguments.callee.call(this,start, q - 1);42 arguments.callee.call(this,q + 1, end);43 }44 };45 46 var A = [3, 3, 4, 2,6,3,7,21,734,3265,2,4,60,0];47 console.log(A);48 A.QUICK_SORT(0, A.length-1);
下面给出算法导论里的伪代码,它的伪代码其实更加优秀:修改的只是partition部分。
先给出伪代码和过程:
下面给出实现代码:
1 Array.prototype.partition = function (p, r) { 2 var x = this[r]; 3 var i = p - 1; 4 5 for (var j = p; j < r; j++) { 6 if (this[j] <= x) { 7 i++; 8 this.swap(i, j); 9 }10 }11 this.swap(i + 1, r);12 return i + 1;13 };14 15 Array.prototype.swap = function (i, j) {16 var temp = this[i];17 this[i] = this[j];18 this[j] = temp;19 };20 21 Array.prototype.QUICK_SORT = function (p, r) {22 if (r > p) {23 var q = this.partition(p, r);24 arguments.callee.call(this, p, q - 1);25 arguments.callee.call(this, q + 1, r);26 }27 };28 29 var A = [3, 3, 4, 2, 6, 3, 7, 21, 734, 3265, 2, 4, 60, 0];30 console.log(A);31 A.QUICK_SORT(0, A.length - 1);32 console.log(A);
这个代码的优势很明显:首先不需要考虑越界了,然后就是循环少了。
下面来探讨它的性能问题:
我们用代换法来证明T(n) = T(n-1)+ T(0) + theta(n) = T(n-1) + theta(n); T(n) = T(n - 1) + theta(n) = theta(n) + theta(n-1) + ... + theta(1) = theta(n^2)
思考:
当数组A的所有元素都具有相同值时,QUICKSORT的时间复杂度是什么?
分析:
当数组A所有元素相同时,QUICKSORT中的划分时极为不平衡的,n-1:0的划分,T(n)=T(n-1)+Θ(n)解这个递归式T(n)=Θ(n^2)
思考:
银行经常会按照交易时间,来记录某一账户的交易情况。但是,很多人却喜欢收到银行对账单是按照支票号码的顺序来排列的。这是因为,人们通常 都是按照支票号码的顺序来开出支票的,而商人也通常都是根据支票编号的顺序兑付支票。这一问题时按照交易时间排序的序列转换成按支票号排序的序列,它是指上是一个对几乎有序的输入序列进行排序的问题。请证明:在这个问题上,INSERTION-SORT的性能往往要优于QUICKSORT?
分析:
插入排序在基本有序的情况下,基本无需移动任何元素来插入,所以只有外层循环了n次,所以时间复杂度为O(n)
快速排序在基本有序的情况下,在划分数组时,划分得非常不平衡,那么其时间复杂度是O(nlgn),而达到完全有序时,时间 复杂度达到O(n^2),所以总之插入排序要优于快速排序。
思考:
假设快速排序的每一层所做的划分的比例都是1-a:a,其中0<a<=1/2且是一个常数。是证明,在相应的递归树中,叶结点的最小深度大约是 -lgn/lga,最大深度大约是-lgn/lg(1-a)(无需考虑整数舍入问题)
分析:
最小深度为每次划分后都是选择最小的一部分继续往下走,每次乘以a。一次迭代减少的元素数从n到an,迭代m次直到剩下的元素为1。
则(a^m)*n = 1, a^m = 1/n,取对数得mlga = -lgn,m = -lgn/lga。
同理可得((1-a)^M)*n = 1,M = -lgn/lg(1-a)。
思考:
试证明:在一个随机输入数组上,对于任何常数0<a<=1/2,PARTITION产生比1-a:a更平衡的划分的概率约为1-2a
证明:
则X+Y=n 那么根据书上根据平衡的定义,X-Y差值越大,比例就越高,那么越不平衡,只有X-Y差值越小,越接近0,X约等于Y的时候 越平衡。
分三种情况讨论:1)当X/n<a时,那么Y/n>1-a, |X-Y|/n>1-2a>0
2)当X/n>1-a时,那么Y<a, |X-Y|/n>1-2a>0
3)当a<X/n<1-a时,那么a<Y<1-a,0<|X-Y|/n<1-2a
只有当|X-Y|/n距离小于一个数时,才可能X-Y差值趋向于0,划分的就越平衡。所以我们选择情况3的这种划分。 在an与(1-a)n之间取X的值,因为划分X落在区间[0,n]上是等可能性的,所以符合均匀分布,落在[an,(1-a)n}]上的任意一点 的概率也是等可能的,所以P{an≤x≤(1-a)n}=((1-a)n-an)/(n-0)=1-2a。得证!
思考:为什么我们分析随机化算法的期望运行时间,而不是其最坏运行时间呢?
分析:随机化算法不能改变最坏情况下得运行时间,但是能降低最坏情况发生的概率。
思考:
在RANDOMIZED-QUICKSORT的运行过程中,在最坏情况下,随机数生成器RANDOM被调用了多少次?在最好情况下呢?
分析:
最好情况是均匀划分,其时间复杂度 T(n)=2T(n/2)+1 =>主定理case1得T(n)=Θ(n)
最坏情况是分成不平衡的划分,其时间复杂度 T(n)=T(n-1)+T(0)+1 各式相加得=>T(n)=Θ(n)