排序算法效率比较

时间:2014-10-07 02:59:09

标签: python algorithm sorting insertion-sort

我正在使用简单的排序算法来熟悉它们,并试图从算法的描述而不是伪代码创建插入排序。我制作了一个有效的算法,我认为符合描述:

import random
nums = []
for i in range(10000):
    nums.append(random.randrange(0, 1000))

def getSortedIndexForEle(ele, sorted):
    for i in range(0, len(sorted)):
        if ele < sorted[i]:
            return i
    return len(sorted)

def sort(lst):
    sorted = []
    for ele in lst:
        sorted.insert(getSortedIndexForEle(ele, sorted), ele)
    return sorted

print(sort(nums))

然而,代码与算法编译方式不匹配(但仍然产生了正确的结果),所以我又进行了一次尝试:

import random
nums = []
for i in range(10000):
    nums.append(random.randrange(0, 1000))

def sort(lst):
    for i in range(1, len(lst)):
        ele = lst[i]
        j = i - 1
        for k in range(j, -2, -1):
            if ele >= lst[k]:
                break
            lst[k + 1] = lst[k]
        lst[k + 1] = ele


sort(nums)
print(nums)

我相信这个是正确的,我将它与伪代码进行了比较,它确实有效。

我的问题是我制作的第一个算法,它不适合算法,在我的机器上的实际物体的大约一半时间内执行(使用长度为10000的列表,每个元素都是一个随机数)。这怎么可能?我的第二个算法不正确吗?我甚至尝试了算法的python示例,这也比我的第一个花了更长的时间......

2 个答案:

答案 0 :(得分:1)

第二个就地排序,第一个没有。

在第二个算法中,您在原始数组中插入每个元素,之后的每个元素都必须移动以适应它。时间复杂度为O(n2),但它只需要恒定的O(1)额外内存。

在第一个中,您将元素插入到单独的数组中,并且只有已经排序的较大元素必须被移位。所以时间复杂度介于O(n)和O(n2)之间,但需要额外的O(n)内存。

答案 1 :(得分:0)

下面是一个插入排序(对不起它的伪代码,但它应该让你基本了解它是如何工作的。)

for (int index = 1; index < array.length; index++) {
    for (int insertion = index; insertion > 0 && array[insertion] < array[insertion - 1]; --insertion) {
        swap(array[insertion], array[insertion - 1];
    } 
}

以这种方式思考,我们有两个移动游标:

for (int index = 1; index < array.length; index++)

这一项的工作是一直滑到收集的末尾(注意我们从第二项开始,而不是第一项!)。

然后我们有这个:

for (int insertion = index - 1; array[insertion] < array[insertion - 1] && insertion > 0; --insertion)

这个很长,所以我将它拆开:

for (int insertion = index; ...; --insertion)

这意味着我们的比较点从index点开始,并在每次迭代后向后移动 。 (嗯,为什么倒退?)

for (; insertion > 0 && array[insertion] < array[insertion - 1];)

当我们向后滑动时,我们需要进行两次比较:

(1)插入索引是否大于零?显然,如果我们到达基地&#39;收藏品,我们显然已经完成了。无需继续,我们让index向前迈出一步。

(2)insertion指向的项目是否小于之前的项目?那不对,我们需要交换它们。实际上,我们会继续向后交换项目对,直到index左侧的所有内容都被排序。

基本上这种for语句的组合仍然存在:

(1)将index置于1,然后对其左侧的所有内容进行排序。只有两个项[0]和[1],所以很容易。

(2)向前移动指数,现在有三个项目。排序[0],[1]和[2]。继续向前移动索引,并在我们前进时对左侧进行排序。

(3)我们排序&#39;确保通过移动index向前引入的新项目向后滑动到位。这是array[insertion] < array[insertion - 1]的重点。换句话说,向后滑动新引入的物品直到它们就位。

(4)由于左侧始终按定义排序,因此在递增index之后我们需要做的就是确保将新项目移动到位。

增量,然后将新项目滑动到位。冲洗并重复。

目视:

[1, 2, 3, 4, 0]

零不合适,所以当index = 4insertion = 4时也是如此。然后我们开始向后比较。

是数组[4]&lt;数组[4 - 1]?是的,0&lt; 4,所以我们互换:

[1, 2, 3, 0, 4]

再次,是数组[3]&lt;数组[3 - 1]?是的,0&lt; 3交换:

[1, 2, 0, 3, 4]

一次又一次,直到我们将0移动到第一个位置,因为那个点数组[插入]&lt; array [insert - 1]将为false。

基本上,您所做的只是确保index的左侧没有项目,以便数组[插入]&lt; array [insert - 1]。如果2个元素的确如此,那么我们检查三个,然后检查四个等等。

有趣的是,我们不需要每次检查整个左侧,因为一旦排序,唯一可能不合适的元素是 NEW 元素介绍通过递增index。也就是说,如果我们添加一个新项目, ONLY 该项目可能不合适,那么一旦我们将其移动到位,根据定义,整个左侧都会被排序!