快速排序作为随机算法的一种,不能通过常规方法来计算时间复杂度

wiki上有三种快排平均时间复杂度的分析,本文记录了一种推导方法。

先放快速排序的伪代码,便于回顾、参考

quicksort(int L, int R, int array[]) {
if (L >= R) {
return;
}
int pivot = RANDOM(L, R);
int l = L, r = R;
int support_array[array.length()]
for (i = L -> R) {
if (i == pivot) {
return;
}
else if (array[i] <= array[pivot]){
support_array[l++] = array[i];
}
else {
support_array[r--] = array[i];
}
}
support_array[l] = array[pivot];
array <- support_array;
quicksort(L, l-1, array);
quicksort(l+1, R, array);
}

n为序列长度,对于长度为n的序列,我们总共需要调用n次quicksort函数,我们将序列中元素与pivot的比较操作(代码8-18行,以下简称为“比较”)提出来总体考虑,每调用一次函数,除开比较操作,时间复杂度均为O(1),设x为n次调用函数总共的比较次数,快排的时间复杂度T(n) = O(n+x)

以下为x的计算过程

设ei为原序列中第i小的数,ej为第j小的数, j > i。在对原序列完整排序的整个过程中,每一个位置都会被选作为pivot一次。ei与ej会被比较,当且仅当在ei, ei+1, ei+2 , ... , ej-1, ej 这个子序列中(按照假设,此为非降序序列),ei与ej其中一个最先在这个子序列中被选为pivot ,否则一个大小介于他们中间的数被选为pivot,在一轮比较过后,ei和ej就会被分在两个子序列中,没有被比较且以后也不会被比较。当我们使用的生成随机数算法能保证每个数被选中为pivot的概率相等时,P(ei与ej被比较) = 2 / ( j - i + 1 )。设Y为ei与ej比较的次数,Y = 0 或 1, Y的期望计算如下

\[P(Y=1) = P(e_i与e_j被比较) = 2 / ( j - i + 1 )
\]
\[E(Y) = P(Y=1) * 1 = 2 / ( j - i + 1 )
\]

而在序列中,任意两项比较次数的期望均是 2 / ( j - i + 1 )

x是总共比较次数,则x的期望的表达式为

\[E(x) = \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}2/(j-i+1)
\]

后半部分的求和是调和级数(harmonic series), 调和级数求和公式如下

\[1+1/2+1/3+...+1/n = ln(n+1) + γ
\]

用于计算E(x)

\[\sum_{j=i+1}^{n}2/(j-i+1) = 2 * [ln(n-i+1)-1+γ] = O(logn)
\]
\[E(x) = \sum_{i=1}^{n-1}O(logn) = O(nlogn)
\]
\[T(n) = O(n+x) = O(n + nlogn) = O(nlogn)
\]

到此,快速排序的平均时间复杂度O(nlogn)也就推导完成了。

快速排序平均时间复杂度O(nlogn)的推导的更多相关文章

  1. 平均时间复杂度为O(nlogn)的排序算法

    本文包括 1.快速排序 2.归并排序 3.堆排序 1.快速排序 快速排序的基本思想是:采取分而治之的思想,把大的拆分为小的,每一趟排序,把比选定值小的数字放在它的左边,比它大的值放在右边:重复以上步骤 ...

  2. 快速排序的时间复杂度nlogn是如何推导的??

    本文以快速排序为例,推导了快排的时间复杂度nlogn是如何得来的,其它算法与其类似. 对数据Data = { x1, x2... xn }: T(n)是QuickSort(n)消耗的时间: P(n)是 ...

  3. 最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

    关于最长递增子序列时间复杂度O(n^2)的实现方法在博客http://blog.csdn.net/iniegang/article/details/47379873(最长递增子序列 Java实现)中已 ...

  4. PHP快速排序及其时间复杂度

    <?php function quickSort(&$arr, $l, $r) { if (count($arr)<2 || $l>$r) return; $tmp_l = ...

  5. 稳定排序nlogn之归并排序_一维,二维

    稳定排序nlogn之归并排序_一维,二维 稳定排序:排序时间稳定的排序 稳定排序包括:归并排序(nlogn),基数排序[设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排 ...

  6. php算法之快速排序

    /** * 快速排序 * 原理: * 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists). * 最差时间复杂度 O(n*n) * ...

  7. JS-排序详解-快速排序

    说明 时间复杂度指的是一个算法执行所耗费的时间 空间复杂度指运行完一个程序所需内存的大小 稳定指,如果a=b,a在b的前面,排序后a仍然在b的前面 不稳定指,如果a=b,a在b的前面,排序后可能会交换 ...

  8. 用非递归、不用栈的方法,实现原位(in-place)的快速排序

    大体思路是修改Partition方法将原本枢数的调整放到方法结束后去做.这样因为数组右侧第一个大于当前枢数的位置就应该是未划分的子数组的边界.然后继续进行Partition调整.这种写法照比递归的写法 ...

  9. 快速排序及查找第K个大的数。

    本文提供了一种基于分治法思想的,查找第K个大的数,可以使得时间复杂地低于nlogn. 因为快排的平均时间复杂度为nlogn,但是快排是全部序列的排序, 本文查找第k大的数,则不必对整个序列进行排序.请 ...

随机推荐

  1. 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 百篇博客分析OpenHarmony源码 | v19.03

    百篇博客系列篇.本篇为: v19.xx 鸿蒙内核源码分析(位图管理篇) | 谁能一分钱分两半用 | 51.c.h .o 先看四个宏定义,进程和线程(线程就是任务)最高和最低优先级定义,[0,31]区间 ...

  2. P7514-[省选联考2021A/B卷]卡牌游戏【贪心】

    正题 题目链接:https://www.luogu.com.cn/problem/P7514 题目大意 给出\(n\)个卡牌有\(a_i/b_i\),开始都是\(a_i\)朝上,将不超过\(m\)张卡 ...

  3. Unittest 框架之断言,你学会了吗??

    unittest断言 Python在 unittest.TestCase 类中提供了很多断言方法.断言方法检查你认为应该满足的条件是否确实满足.如果该条件确实满足,你对程序行为的假设就得到了确认,你就 ...

  4. HBase 与 Cassandra 架构对比分析的经验分享

    架构对比 HBase和Cassandra几乎是一个年份发起,又都是在2010年成为Apache的顶级项目,不过如果我们去细品其内部机制,我们会发现其实两者是完全不同的架构风格. HBASE起源于Goo ...

  5. 关于使用antd-vue的卡片无法设置avatar图标/头像问题的解决方案

    在使用antd-vue的卡片a-card时,遇到无法添加avatar图标/头像的问题,原因出在a-avatar,他不支持webpack图片打包. 上代码:       <a-card hover ...

  6. 从工具、工具箱到数字化软件工厂——DevOps 设计理念与工程实践专场 | CIF 精彩看点

    西方经典管理理论认为,组织效率可以归为劳动效率.组织效率和人的效率.美国管理学家泰勒所著的<科学管理原理>被德鲁克誉为"20 世纪最伟大的发明",劳动效率说认为分工提升 ...

  7. 极简SpringBoot指南-Chapter05-SpringBoot中的AOP面向切面编程简介

    仓库地址 w4ngzhen/springboot-simple-guide: This is a project that guides SpringBoot users to get started ...

  8. C#开发BIMFACE系列47 IIS部署并加载离线数据包

    BIMFACE二次开发系列目录     [已更新最新开发文章,点击查看详细] 在前两篇博客<C#开发BIMFACE系列45 服务端API之创建离线数据包>与<C#开发BIMFACE系 ...

  9. Java(9)数组详解

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201564.html 博客主页:https://www.cnblogs.com/testero ...

  10. 【Docker】(11)---Docker的网络概念

    一.实现原理 1.实现原理 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为C ...