Python的sort()与sorted()排序函数的区别

一、工具

Python 3.10.0
pycharm 2022

二、需求

最近做项目的时候用到了这两个函数,以前没注意,仔细研究一下,这两个函数还是有很大区别的

三、简单的使用例子

在Python中,你可以使用内置的sort()方法或者sorted()函数对列表进行排序。

  1. sort() 方法 - 会修改原始列表,使其元素按照一定顺序排列。默认情况下,排序是升序的。
my_list = [3, 1, 4, 1, 5, 9, 2, 6]
my_list.sort()
print(my_list)  # 输出: [1, 1, 2, 3, 4, 5, 6, 9]

如果你要按照降序排序,可以传递一个参数reverse=Truesort()方法:

my_list = [3, 1, 4, 1, 5, 9, 2, 6]
my_list.sort(reverse=True)
print(my_list)  # 输出: [9, 6, 5, 4, 3, 2, 1, 1]

你还可以提供一个自定义的关键字参数key来实现自定义排序逻辑:

my_list = ['apple', 'banana', 'cherry', 'date']
my_list.sort(key=len)  # 根据字符串长度排序
print(my_list)  # 输出: ['date', 'apple', 'banana', 'cherry']
  1. sorted() 函数 - 会返回一个新的列表,并且不会改变原始的列表。用法和sort()类似,但是它可以用于任何可迭代对象:
my_list = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_list = sorted(my_list)
print(sorted_list)  # 输出: [1, 1, 2, 3, 4, 5, 6, 9]

同样地,你也可以使用reversekey参数:

my_list = ['apple', 'banana', 'cherry', 'date']
sorted_list = sorted(my_list, key=len, reverse=True)
print(sorted_list)  # 输出: ['banana', 'cherry', 'apple', 'date']

这里的len是Python内置函数,用来获取列表中每个元素的长度作为排序的依据(即排序键)。sort()和sorted()都支持自定义的函数作为key参数,这允许你进行更复杂的排序操作。

选择sort()方法还是sorted()函数取决于是否需要保留原始列表不变,以及是否需要对任意可迭代对象进行排序

四、原理分析

在Python中,sort()方法和sorted()函数背后的排序机制是基于Tim Peters开发的Timsort算法。Timsort是一种混合型排序算法,它源自归并排序(Merge Sort)和插入排序(Insertion Sort)。Timsort算法在2002年被引入到Python中,并且因为其卓越性能成为Python的默认排序算法。

Timsort算法主要特点:

  1. 稳定性:如果列表中存在相等的元素,它们原始的顺序不会改变。
  2. 自适应性:在接近排好序的数据集上表现更佳。
  3. 复杂度: 最坏情况时间复杂度为O(n log n)。 最优情况(已经排好序的数据集)时间复杂度为O(n)。 平均情况时间复杂度也是O(n log n)。

Timsort算法的工作原理:

  1. 查找或创建自然运行:Timsort首先遍历数据,查找自然有序的小段,称为“运行”(runs),这些可以是已经排好序的子列表。如果没有找到足够大小的运行,则使用二分插入排序将它们扩展到最小运行大小(通常为32或64个元素)。这一步骤允许算法利用输入数据中的任何固有顺序。

  2. 运行堆积(Run Stacking):一旦识别出所有的运行之后,Timsort会按照一定规则将它们合并,直到只剩下一个运行为止。这个过程中,Timsort会尽可能地合并那些长度相近的相邻运行。

  3. 归并排序:合并过程是通过归并排序完成的,这是一种将两个或多个有序列表组合成单一有序列表的技术。通过重复此过程,直到整个数组变得有序。

sort() 方法和 sorted() 函数的差异:

  1. sort() 方法:

是列表(list)的内置方法。
会就地(in-place)对列表进行排序,即不需要额外的存储空间来创建新列表,但原始列表内容会被改变。
2. sorted() 函数:

是内建函数,可以对任意可迭代对象进行排序操作。
返回一个新的列表,原始输入数据不会被修改。
尽管sort()和sorted()使用相同的排序算法(Timsort),它们在数据处理方式上存在差异,体现在是否会改变原始数据以及它们各自的适用范围。

在高级实现中,Timsort还涉及很多优化措施,比如对小数组使用插入排序、合并时考虑已排序的序列以及优化的比较和移动过程等。这些细微的优化使得Timsort成为一种非常快速且高效的排序算法,在现代编程语言中得到广泛采用。

五、Python中的单例实现简单示例

要实现一个只需实例化一次的类,你可以使用设计模式中的单例模式。在Python中,有多种方式实现单例模式。下面给出两种常见的实现方式:

  1. 使用类变量:
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
        return cls._instance

# 使用示例
singleton1 = Singleton()
singleton2 = Singleton()

assert singleton1 is singleton2  # 检查singleton1和singleton2是否是同一个实例

在这个例子中,我们重写了__new__方法,它是在创建实例之前被调用的特殊方法。__new__方法确保只创建单例类的一个实例,并且后续尝试创建新实例时都返回第一个创建的实例。

  1. 使用装饰器:
def singleton(cls):
    instances = {}
    
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    
    return get_instance

@singleton
class MySingleton:
    pass

# 使用示例
singleton1 = MySingleton()
singleton2 = MySingleton()

assert singleton1 is singleton2  # 检查singleton1和singleton2是否是同一个实例

在这个例子中,我们使用了一个装饰器singleton,它接收一个类并返回一个函数get_instance。这个函数检查该类是否已经有一个实例存在于字典instances中,如果不存在就创建一个新的实例。如果已经存在,就返回那个实例。当你用@singleton装饰一个类时,你实际上把这个类替换成了get_instance函数。

两种方法都能够确保一个类在程序运行期间只有一个实例。选择哪种方式取决于你的具体需求和偏好。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QuietNightThought

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值