您的位置:首页 > 编程语言 > C语言/C++

快速排序的复杂度分析以及使用插入排序优化的快速排序

2017-08-11 23:13 681 查看
首先,对快速排序分析可知,在一个包含n个元素的数组上运行快速排序时,记总共的两个元素之间的比较次数为X,则快速排序的运行时间为O(n+X)(算法导论第三版7.4.2节引理7.1)。因此,必须了解算法在什么时候对数组中的两个元素进行比较,什么时候不进行比较。

将数组A中的各个元素重新命名为z1,z2,z3,...,zn,其中zi是数组中第i小的元素。定义Zij=zi,zi+1,zi+2,...,zj为zi和zj之间(含i和j)的元素集合。定义指示器随机变量:

Xij=I{zi与zj进行比较}

则算法的总共的比较次数为:

X=∑n−1i=1∑nj=i+1Xij

对上述式子两边取期望可得:

E[X]=E[∑n−1i=1∑nj=i+1Xij]=∑n−1i=1∑nj=i+1E[Xij]=∑n−1i=1∑nj=i+1Pr{zi与zj进行比较}

通常,假设每个元素的值是互异的,因此,一旦一个满足zi<x<zj的主元被选择后,zi和zj就再也不可能被比较了,因为zi和zj已经被划分到两个不同的划分中。然而,若是zi在Zij中的其他所有元素之前被选为主元,那么zi将和Zij中除了它自身之外的所有元素进行比较。因此,zi和zj当且仅当Zij中第一个被选为主元的元素是zi或者zj。

接着计算这一事件发生的概率。在任意一个Zij内的元素被选择为主元之前,整个集合均在一个划分的同一个分区之中。因此,每个Zij中的元素被选为主元的概率相等。因为集合中有j−i+1个元素,并且主元的选择是独立且随机的,所以任何元素首先被选为主元的概率为1j−i+1。于是:

Pr{zi于zj相比较}=Pr{zi或者zj是集合中首先被选择作为主元的元素}=2j−i+1

所以有:

E[X]=∑n−1i=1∑nj=i+12j−i+1

所以,可以有:

E[X]=∑n−1i=1∑nj=i+12j−i+1=∑n−1i=1∑n−ik=12k+1<∑n−1i=1∑n−ik=12k=∑n−1i=1O(lgn)=O(nlgn)

由此可得,在输入元素均不相同的情况下,随机化的快速排序算法的期望运行时间是O(nlgn)。

对于上式,又有:

E[X]=∑n−1i=1∑nj=i+12j−i+1=∑n−1i=1∑n−ik=12k+1≥∑n−1i=1∑n−ik=122k≥∑n−1i=1Ω(lgn)=Ω(nlgn)

所以,又有,随机化的快速排序算法的期望运行时间为Ω(nlgn)。由上可知,随机化的快速排序算法的期望运行时间为Θ(nlgn)。

当输入数据已经几乎有序时,插入排序的速度很快。在实际应用中,可以利用这一特点来提高快速排序的速度。当对一个长度小于k的子数组调用快速排序时,可以让它不做任何处理就返回。当上层快速排序调用返回后,对整个数组进行插入排序来完成排序过程。该算法的期望时间复杂度为O(nk+nlg(n/k))。该算法的时间复杂度分析如下:

对于快速排序结束后的插入排序,假设每一小结的插入排序时间复杂度为O(k^2),则n/k个小结的时间复杂度为nkO(k2)=O(nk)。

对于随机的快速排序过程,时间复杂度是O(nlg(n/k)),网上很多解答说这个利用指示器随机变量,然后计算j与i的距离大于k的均值即可,但是笔者认为,在划分过程中,j于i之间的距离小于k时的比较也可能出现,所以不可以单单这样计算,然而想不出正确解法,故留待之后解决。

C语言实现优化的快速排序如下:

void insertion_sort(int *source, int head, int tail) {
if (head > tail) {
fprintf(stderr, "Error head and tail\n");
return;
}
int i = head + 1;
int j = head;
int temp;
for (i = head + 1; i <= tail; i++) {
temp = source[i];
for (j = i - 1; j >= head && source[j] > temp; j--) {
source[j + 1] = source[j];
}
source[j + 1] = temp;
}
}

int randomized_partition(int *source, int head, int tail) {
swap(source + rand() % (tail - head + 1) + head, source + tail);
int x = source[tail];
int i = head - 1, j = head;
for (j = head; j < tail; j++) {
if (source[j] <= x) {
i++;
swap(source + j, source + i);
}
}
swap(source + tail, source + i + 1);
return i + 1;
}

void limited_quick_sort(int *source, int head, int tail, int k) {
if (tail - head >= k)
return;
int mid = randomized_partition(source, head, tail);
limited_quick_sort(source, head, mid - 1, k);
limited_quick_sort(source, mid + 1, tail, k);
}

void insertion_optimized_quick_sort(int *source, int head, int tail, int k) {
limited_quick_sort(source, head, tail, k);
insertion_sort(source, head, tail);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐