排序算法的下界和如何超越下界——python实现Thomas H.Cormen算法基础中的算法

2023-10-11 21:10

本文主要是介绍排序算法的下界和如何超越下界——python实现Thomas H.Cormen算法基础中的算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、排序算法分类
    • 二、算法复杂度
    • 三、时间复杂度下界
    • 四、超越下界
      • 1.范例1——严格的约束(排序仅有两个值)
      • 2.范例2——扩展1至每个元素可以取m个连续整数中的一个

一、排序算法分类

  • 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序。
  • 非比较类排序:不通过比较来决定元素间的相对次序,它可以突破基于比较排序的时间下界,以线性时间运行,因此也称为线性时间非比较类排序。

排序算法分类

二、算法复杂度

算法复杂度
相关概念:

  • 稳定:如果a原本在b的前面,而a=b,排序之后a仍然在b的前面
  • 不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面
  • 时间复杂度:对排序数据的总的操作次数。反映当n发生变化的时候,操作次数呈现什么规律
  • 空间复杂度:算法在计算机中执行时所需要存储空间的度量,是数据规模n的函数

三、时间复杂度下界

观察插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序的时间复杂度,在没有特殊规则的时候时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)就是最优的排序算法了

也就是说通用排序算法的时间复杂度下界就是 O ( n l o g n ) O(nlogn) O(nlogn)

如果限定一些规则,是可以打破这个下界的。

下面说一下尽在O(n)时间内就能实现对数组排序的算法、

四、超越下界

问题:基于什么样的规则才能突破排序的下界呢?

基础思想:我们需要分析一下排序消耗的时间。排序需要遍历,比较,交换。能否省略其中的一些步骤呢?这就是要定义的规则,通过规则减少排序步骤。

1.范例1——严格的约束(排序仅有两个值)

一组待排序的元素仅有1和2,没有其它值,对这组数进行排序。

输入 A 0 , A 1 , A 2 , A 3 . . . . . . A n − 1 A_0,A_1,A_2,A_3......A_{n-1} A0A1,A2,A3......An1,Ai为1或者2

排序步骤

  1. 令k=0
  2. 令i从0到n-1依次取值,如果A[i]=1,k自增1
  3. 令i从0到k-1依次取值,将A[i]赋值为1
  4. 令i从k到n-1依次取值,将A[i]赋值为2

这样我们完成了排序,花费的时间为O(n)
之前我们所说的算法都是通过比较元素对来确定顺序,那种排序叫做比较排序。凡是比较排序,通用下界为O(nlogn)

# 非常简单的实现,每一步都对应于上述四个步骤
A = [1,2,1,1,1,2,1,2,1,2,1]
print('排序前:',A)
n = len(A)
k = 0
for i in range(0,n):if A[i]==1:k+=1for i in range(0,k):A[i] = 1for i in range(k,n):A[i] = 2print('排序后:',A)

结果:

排序前: [1, 2, 1, 1, 1, 2, 1, 2, 1, 2, 1]
排序后: [1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2]

2.范例2——扩展1至每个元素可以取m个连续整数中的一个

只要每个元素在m个连续整数值中取值,算法都是通用的

该算法的实现需要三个基本方法:

COUNT-KEY-EQUAL(A,n,m)

输入:A 一个数组,n 数组A中的元素个数m数组A中元素的取值范围
输出:一个数组 e q u a l [ 0...... m ] equal[0......m] equal[0......m],是 e q u a l [ j ] equal[j] equal[j]等于数组A中元素值为j的元素个数

  1. 创建一个新数组 e q u a l [ 0...... m ] equal[0......m] equal[0......m]
  2. e q u a l equal equal数组每个元素都为0
  3. i从0到n-1依次取值,每次将 e q u a l [ A [ i ] ] equal[A[i]] equal[A[i]]的值自增1
  4. 返回 e q u a l equal equal

COUNT-KEY-LESS(equal,m)

输入值COUNT-KEY-EQUAL方法对应的值 e q u a l , m equal,m equalm
输出一个数组 l e s s [ 0...... m ] , l e s s [ j ] = e q u a l [ 0 ] + e q u a l [ 1 ] + . . . . . . + e q u a l [ j − 1 ] less[0......m],less[j]=equal[0]+equal[1]+......+equal[j-1] less[0......m],less[j]=equal[0]+equal[1]+......+equal[j1]

  1. 创建一个新数组 l e s s [ 0... m ] less[0...m] less[0...m]
  2. l e s s [ 0 ] = 0 less[0]=0 less[0]=0
  3. j从1取到m, l e s s [ j ] = l e s s [ j − 1 ] + e q u a l [ j − 1 ] less[j]=less[j-1]+equal[j-1] less[j]=less[j1]+equal[j1](这是普通的迭代算法)
  4. 返回 l e s s less less

REARRANGE(A,less,n,m)

输入COUNT-KEY-EQUAL COUNT-KEY-LESS方法对应的 A , l e s s , n , m A,less,n,m Aless,n,m
输出数组B,B中包含A中所有元素,并且已经排好序

  1. 创建新数组 B [ 0... n − 1 ] , n e x t [ 0..... m ] B[0...n-1],next[0.....m] B[0...n1],next[0.....m]
  2. j从0到m依次取值
    n e x t [ j ] = l e s s [ j ] + 1 next[j]=less[j]+1 next[j]=less[j]+1
  3. 令i从0到n-1依次取值
    k e y = A [ i ] ; i n d e x = n e x t [ k e y ] , B [ i n d e x ] = A [ i ] , n e x t [ k e y ] + + key=A[i];index=next[key],B[index]=A[i],next[key]++ key=A[i];index=next[key],B[index]=A[i],next[key]++
  4. 返回数组B
## 代码实现:
import numpy as np
def CountKeyEqual(A,n,m):equal = np.zeros(m+1)for i in range(0,n):equal[A[i]]+=1return equal
def CountKeyLess(equal,m):less = np.ones(m+1)less[0] = 0 for j in range(1,m+1):less[j] = less[j-1]+equal[j-1]return less
def Rearrange(A,less,n,m):B = np.ones(n)next_ = np.ones(m+1)for j in range(m+1):next_[j] = less[j]+1for i in range(n):key = A[i]index = next_[key]B[int(index)-1] = A[i] # 注意这里与文本序数有些把不同在于B的索引大小应该与A的一致next_[key]+=1return B
if __name__=='__main__':A = [4,1,5,0,1,6,5,1,5,3]n = len(A)m = 6print('排序前:',A)equal = CountKeyEqual(A,n,m)less = CountKeyLess(equal,m)B = Rearrange(A,less,n,m)B = B.astype(np.int).tolist()print('排序后:',B)

结果:

排序前: [4, 1, 5, 0, 1, 6, 5, 1, 5, 3]
排序后: [0, 1, 1, 1, 3, 4, 5, 5, 5, 6]

这篇关于排序算法的下界和如何超越下界——python实现Thomas H.Cormen算法基础中的算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/190839

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python调用Orator ORM进行数据库操作

《Python调用OratorORM进行数据库操作》OratorORM是一个功能丰富且灵活的PythonORM库,旨在简化数据库操作,它支持多种数据库并提供了简洁且直观的API,下面我们就... 目录Orator ORM 主要特点安装使用示例总结Orator ORM 是一个功能丰富且灵活的 python O

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

python使用fastapi实现多语言国际化的操作指南

《python使用fastapi实现多语言国际化的操作指南》本文介绍了使用Python和FastAPI实现多语言国际化的操作指南,包括多语言架构技术栈、翻译管理、前端本地化、语言切换机制以及常见陷阱和... 目录多语言国际化实现指南项目多语言架构技术栈目录结构翻译工作流1. 翻译数据存储2. 翻译生成脚本

如何通过Python实现一个消息队列

《如何通过Python实现一个消息队列》这篇文章主要为大家详细介绍了如何通过Python实现一个简单的消息队列,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录如何通过 python 实现消息队列如何把 http 请求放在队列中执行1. 使用 queue.Queue 和 reque

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形