引用
http://www.ahhf45.com/info/Data_Structures_and_Algorithms/algorithm/commonalg/sort/internal_sorting/chapter1.htm
对排序算法计算时间的分析可以遵循若干种不同的准则,通常以排序过程所需要的算法步数作为度量,有时也以排序过程中所作的键比较次数作为度量。特别是当作一次键比较需要较长时间,例如,当键是较长的字符串时,常以键比较次数作为排序算法计算时间复杂性的度量。当排序时需要移动记录,且记录都很大时,还应该考虑记录的移动次数。究竟采用哪种度量方法比较合适要根据具体情况而定。在下面的讨论中我们主要考虑用比较的次数作为复杂性的度量。
为了对有n个元素的线性表进行排序,至少必须扫描线性表一遍以获取这n个元素的信息,因此排序问题的计算复杂性下界为Ω(n)。
如果我们对输入的数据不做任何要求,我们所能获得的唯一信息就是各个元素的具体的值,我们仅能通过比较来确定输入序列<a1,a2,..,an>的元素间次序。即给定两个元素ai和aj,通过测试ai<aj ,ai≤aj ,ai=aj ,ai≥aj ,ai>aj 中的哪一个成立来确定ai和aj间的相对次序。这样的排序算法称为比较排序算法。下面我们讨论一下比较排序算法在最坏情况下至少需要多少次比较,即比较排序算法的最坏情况复杂性下界。
我们假设每次比较只测试ai≤aj ,如果ai≤aj 成立则ai排在aj 前面,否则ai排在aj 后面。任何一个比较排序算法可以描述为一串比较序列:
(ai,aj),(ak,al),..,(am,an),...
表示我们首先比较(ai,aj),然后比较(ak,al),...,比较(am,an),...,直到我们获取了足够的信息可以确定所有元素的顺序。显而易见,如果我们对所有的元素两两进行一次比较的话(总共比较了Cn2次),就一定可以确定所有元素的顺序。但是,如果我们运气足够好的话,我们可能不必对所有元素两两进行一次比较。比如说对于有三个元素a1,a2,a3的线性表进行排序,如果我们先比较a1和a2,得到a1≤a2;然后比较a2和a3,得到a2≤a3;则不必比较a1和a3,因为根据偏序集的传递性,必有a1≤a3;但是如果a2≥a3,我们还必须比较a1和a3才能确定a1和a3的相对位置。如果我们适当的安排比较的次序的话,也可以减少比较的次数。这样我们可以用一棵二叉树表示比较的顺序,如下图所示:
该树的每一个非叶节点表示一次比较,每一根树枝表示一种比较结果,每一个叶节点表示一种排列顺序。这样的一棵二叉树叫做决策树,它用树枝表示了每次决策做出的选择。如此我们可以将任何一个比较排序算法用一棵决策树来表示。
请注意上图只表明了对三个元素的一种比较算法,这种比较算法依次比较(a1,a2)(a2,a3)(a1,a3),一旦中间某步得到足够的信息就可以停止比较,但是当算法执行完后(三次比较后),一定可以确定三个元素间的次序。因此我们有理由将算法在最坏情况下的比较次数作为算法复杂性的度量,对于本例该算法在最坏情况下要进行C32=3次比较。
显然,一棵决策树中最高叶节点的高度就是该决策树对应的算法在最坏情况下所需的比较次数,而决策树中最低叶节点的高度就是该决策树对应的算法在最好情况下所需的比较次数。
我们的问题就变为:对于任意一棵决策树(任意一种比较排序算法),它的最高的树叶的高度是多少?这个高度就对应于比较排序算法所需的最多比较次数(在运气最坏的情况下);换句话说,对于任何一个输入,该算法至少需要比较多少次就可以对元素进行排序。
我们发现,决策树的每个叶节点对应一个n个元素的排列,其中可能有重复的;但是由于决策树表明了所有可能遇到的情况,因而n个元素的所有排列都在决策树中出现过。n个元素共有n!种排列,即决策树的叶节点数目至少为n!。又因为一棵高度为h的二叉树(指二叉树的最高树叶高度为h)的叶节点数目最多为2h个(这时正好是满二叉树,即每个非叶节点都有两个子节点),因此n!≤2h,得到h≥log(n!),其中log以2为底。根据Stirling公式有n!>(n/e)n,于是h>nlogn-nloge,即h=Ω(nlogn)。
这样我们就证明了对于任意一种利用比较来确定元素间相对位置的排序算法,其最坏情况下复杂性为Ω(nlogn)。
在下文中我们将讨论几种比较排序算法,其中快速排序在平均情况下复杂性为O(nlogn),最坏情况下复杂性为O(n2);堆排序和合并排序在最坏情况下复杂性为O(nlogn),因此堆排序和合并排序是渐进最优的比较排序算法。
排序算法是否还能够改进呢?从前文我们知道,如果要改进排序算法的效率,就不能只利用比较来确定元素间相对位置。因此我们还需要知道元素的其他附加信息,光知道元素的大小信息是不够的。下文中我们介绍的计数排序,基数排序和桶排序是具有线性时间复杂性的排序算法,这些算法无一例外地对输入数据作了某些附加限制,从而增加已知的信息,因此可以不通过比较来确定元素间的相对位置。
分享到:
相关推荐
常见的算法复杂性问题包括排序和搜索。例如,冒泡排序的时间复杂性为O(n^2),而快速排序的平均时间复杂性为O(n log n),在处理大规模数据时,快速排序的效率更高。线性搜索的时间复杂性为O(n),而二分搜索在有序数组...
计算复杂性理论是计算机科学的一个分支,研究算法的效率和问题的困难程度。计算复杂性理论的核心在于如何量化算法所需的资源。理解算法的复杂性有助于我们在现实世界中选择最优解决方案。 衡量算法的复杂性可以从两...
最后,遗传算法是一种受到生物进化启发的计算方法,它用于解决计算复杂性问题。遗传算法通过模拟自然选择、基因重组和突变等生物过程来寻找优化解决方案。在处理难以解决的问题时,遗传算法能从初始的随机解群体中...
8. **复杂性类**:P、NP、NPC等复杂性类的概念是理解计算复杂性的基石。书中会讨论这些问题的可解性和复杂性,以及它们在现实世界问题中的应用。 9. **概率与随机化算法**:书中可能包含一些使用概率和随机性来设计...
此外,由于归并排序的可并行性,它也常被用在并行计算环境中。 在编程实现上,归并排序通常采用递归的方式,但也存在非递归的迭代版本。例如,使用栈来模拟递归调用的过程,也可以达到相同的效果,但代码实现相对...
在这个主题中,我们主要关注如何在控制台应用程序(Console应用)中处理数组的排序和计算问题。"A.3.4 数组排序和计算(Console).zip"文件很可能包含了一些示例代码或者教程,用于教导用户如何在C#或类似的命令行...
* 空间复杂性:介绍了算法的空间复杂性分析,包括时间复杂性和空间复杂性的定义、计算方法和应用场景。 * 时间复杂性:介绍了算法的时间复杂性分析,包括时间复杂性的定义、计算方法和应用场景。 * 渐进符号:介绍了...
另一种是将复杂问题逐步简化为已知解的简单问题。递推法在求解数列问题中尤为常见。 **3. 递归法**:是一种自我调用的方法,通常用于处理可以分解为子问题的复杂问题。递归算法的设计依赖于递归基和递归规则两个...
算法分析与复杂性理论是计算机科学的核心领域,它探讨如何有效地设计和评估算法,以及算法在计算上的局限性。北京大学2012年的这门课程深入浅出地讲解了这些关键概念,为工程技术人员和算法爱好者提供了宝贵的资源。...
本压缩包文件中的内容涉及“LUT算法”、“排序重构问题”和“教学学计划编制问题”,这些都是计算机科学教育中常见的实践课题。让我们逐一深入探讨这些知识点。 首先,LUT(查找表,Look-Up Table)是一种在计算和...
在本课程设计中,学生被要求使用复杂模型机来实现冒泡排序算法,这既是对理论知识的实践应用,也是对逻辑思维和工程能力的锻炼。 首先,项目任务明确要求学生通过复杂模型机实现冒泡排序,这是一种基础的排序算法,...
陕西科技大学学校的排序算法实验,最近小咲...2. 使用不同的数据结合计算各种算法的运行时间,验证算法的时间复杂性 3. 能够运用二路归并算法进行外排序 4. 了解败者树算法,并运用多路归并算法进行外排序(未能实现)
8. **复杂性理论**:P类问题、NP类问题、NPC问题以及P=NP问题的探讨,这是理论计算机科学的重要研究领域。 9. **算法设计技巧**:如分治、动态规划、贪心、回溯等方法的适用场景和设计原则。 10. **近似算法和随机...
在多边形渲染时,通过计算顶点的凸包,可以简化处理,提高效率,同时保持图形的可见性。 三、路径绘制 OpenGL提供了一些API,如GLUtessellator,用于在屏幕上绘制复杂的曲线和二维路径。这在字体渲染、图标设计或...
该书专注于介绍计算理论的核心部分,具体涵盖自动机与语言理论、可计算性理论以及计算复杂性理论三大板块,这些理论构成了计算机科学的理论基础。 在自动机与语言理论部分,内容主要介绍不同类型的自动机,包括有限...
评价排序算法优劣的主要标准是算法的效率,这通常通过时间复杂性和空间复杂性来衡量。时间复杂性关注的是算法执行所需的比较次数和元素移动次数;而空间复杂性关注的是算法运行时额外所需的存储空间。稳定性和不稳定...
排序熵是一种衡量序列或数据集复杂度的统计量,它基于信息熵的概念,但通过排序而非频率...总的来说,通过MATLAB程序实现排序熵计算,我们可以对数据的内在复杂性有更直观的理解,这在数据分析和研究中具有重要的价值。
在这个PPT学习教案中,首先通过一个改进的冒泡排序算法实例来引入时间复杂性的概念。冒泡排序在不同情况下,如输入数据已排序或完全无序,所需的基本操作次数差异显著,这揭示了对于大规模问题,了解算法在各种输入...