【问题标题】:Sorting lowercase letters in python在python中对小写字母进行排序
【发布时间】:2018-03-30 05:06:51
【问题描述】:

我试图说服自己,计数排序比 Python 中的排序方法执行得更快。然而,即使对于像 1000 万个元素这样的大输入,调用 sorted 内置函数似乎也更快。我可以做些什么来加快计数排序?

我生成一个小写字母列表以将示例简化为 26 个唯一值:

letters = [random.choice(string.ascii_lowercase) for i in range(10000000)]

然后我对计数排序进行以下变体:

def sorted_count(letters):
 counts = [0] * 26
 for letter in letters:
     counts[ord(letter) - 97] += 1
 out = [None] * len(letters)
 j = 0
 for i in range(len(counts)):
     while counts[i] > 0:
         out[j] = chr(i + 97)
         counts[i] -= 1
         j += 1
 return out

即使在 10,000,000 个元素上,对 sorted(letters) 的调用也快了约 4 倍。 如何提高排序的速度?

【问题讨论】:

  • 你有完整的timeit脚本吗?
  • 另外,您将纯 Python 代码与优化的 C 代码进行比较。慢 4 倍确实不错,可能被认为是“更快”。
  • 您是在询问(理论上的)算法改进吗?实际上,在纯 Python 中衡量算法的性能几乎没有意义。正如@EricDuminil 提到的,与built-in sort(这是用C 编写的比较排序)的比较是无效的。对于现实世界的用例,使用本地语言(可能是 python 的 C++ 扩展)、并行化、尝试 GPU、在输入数据中查找结构以实现更快的边缘情况处理等。
  • 没有考虑优化的 C 代码。我认为这是一个很好的观点。我的问题是关于 Python 的细节而不是理论上的改进。

标签: python python-3.x performance sorting big-o


【解决方案1】:

而不是在最后的 forloop 中使用 while 循环。 你可以简单地使用

for i in range(len(counts)):
 if counts[i]>0:
     out[j] =counts[i]*chr(i + 97)
 j+=1
return out

【讨论】:

  • 不得不把它改成这个,但速度确实有很大的提高:out = [] for i in range(len(counts)): out += list(counts[i] * chr( i + 97))
  • 是的,我只是概述了如何做到这一点,早些时候它具有大约 O(n^2) 的复杂性,而计数排序实际上具有 O(n+k),这就是它的速度降低的原因显着
  • 这是counts,而不是count。此外,out 现在是一个包含 26 个长字符串和 9999974 Nones 的列表。
【解决方案2】:

这是一个修改后的函数,比建议的快 3 倍,比 sorted 快两倍:

import random
import string
import timeit
N = 1000000
letters = [random.choice(string.ascii_lowercase) for i in range(N)]


def original_sorted_count(letters):
    counts = [0] * 26
    for letter in letters:
        counts[ord(letter) - 97] += 1
    out = [None] * len(letters)
    j = 0
    for i in range(len(counts)):
        while counts[i] > 0:
            out[j] = chr(i + 97)
            counts[i] -= 1
            j += 1
    return out

def eric(letters):
    counts = [0] * 26
    for letter in letters:
        counts[ord(letter) - 97] += 1
    out = []
    for i in range(len(counts)):
        out += [chr(i+97)] * counts[i]
    return out

print('Original : %.3fs' %timeit.timeit(lambda: original_sorted_count(letters), number=20))
print('Sorted   : %.3fs' %timeit.timeit(lambda: sorted(letters), number=20))
print('Eric     : %.3fs' %timeit.timeit(lambda: eric(letters), number=20))

print(eric(letters) == sorted(letters))

它输出:

Original : 9.616s
Sorted   : 6.367s
Eric     : 3.604s
True

【讨论】:

    猜你喜欢
    • 2018-05-04
    • 2018-06-14
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-21
    • 2020-12-24
    • 2019-07-10
    相关资源
    最近更新 更多