编程语言
首页 > 编程语言> > python – 保持数字有序的有效方法

python – 保持数字有序的有效方法

作者:互联网

这是一个可以应用于任何语言的问题,但我将使用python来显示它.

假设你有一个数字列表,ls = [0,100,200,300,400]

您可以在任何索引处插入元素,但元素必须始终按数字顺序排列.不允许重复.

例如,ls.insert(2,150)导致ls = [0,100,150,200,300,400].元素的顺序正确,所以这是正确的.

但是,ls.insert(3,190)导致ls = [0,100,200,190,300,400].这是不正确的.

对于任何索引i,在ls.insert(i,x)中使用的最佳数字x是什么,以最小化排序数量?

我的第一个直觉是将前一个和下一个数字之间的差异加到前一个数字上.因此,要在索引3处插入一个数字,x将等于200(300-200)或250.但是这对渐近线来说太快了.当差异太接近0时,我可以通过循环并更改每个数字来恢复差异,以产生更大的差异.我想为x选择最佳数字,以尽量减少我需要重置的次数.

编辑

我正在应用此问题的具体问题是具有列表视图的iOS应用程序.列表中的项目在Set中表示,每个对象都有一个属性orderingValue.我无法使用数组来表示列表(由于缓存服务器同步问题),因此每次向用户显示列表时都必须对该集进行排序.为此,ordersValue必须存储在ListItem对象上.

另外一个细节是,由于UI的性质,用户可能更有可能将项目添加到列表的顶部或底部而不是将其插入中间.

解决方法:

如果使用字符串而不是整数,则可以无限期地生成排序键.这是因为字符串的字典顺序在任意两个字符串之间放置了无数个值(只要较大的字符串不是较小的字符串,后跟“a”).

这是一个在两个其他键之间生成小写字符串键的函数:

def get_key_str(low="a", high="z"):
    if low == "":
        low = "a"
    assert(low < high)
    for i, (a, b) in enumerate(zip(low, high)):
        if a < b:
            mid = chr((ord(a) + ord(b))//2) # get the character half-way between a and b
            if mid != a:
                return low[:i] + mid
            else:
                return low[:i+1] + get_key_str(low[i+1:], "z")
    return low + get_key_str("a", high[len(low):])

它总是返回一个字符串s,使得“a”< = low< s<高< =“z”. “a”和“z”从不用作键,它们是表示可能结果边界的特殊值. 您可以使用get_key_str([lst [i-1],lst [i])调用它来获取要在索引i处的值之前插入的值.您可以使用lst.insert(i,get_key_str(lst [i-1],lst [i]))一次插入并生成一个值.显然,列表的末尾需要特殊处理. 设置默认值,以便您可以省略参数以获取要在开头或结尾插入的值.也就是说,调用get_key_str(high = lst [0])来获取一个值放在列表的开头或get_key_str(lst [-1])以获得一个值,以便在末尾追加.你也可以明确地将“a”作为低或“z”传递给高,如果这更容易.如果没有参数,它将返回“m”,这是放入空列表的合理的第一个值. 当您在开始或结束时大部分添加时,您可以稍微调整一下以提供更短的键,但这会更复杂一些.如果您随机插入,此版本的键应大致均匀增长. 这是一个做一些随机插入的例子:

>>> import random
>>> lst = []
>>> for _ in range(10):
    index = random.randint(0, len(lst))
    print("inserting at", index)
    if index == 0:
        low = "a"
    else:
        low = lst[index-1]
    if index == len(lst):
        high = "z"
    else:
        high = lst[index]
    lst.insert(index, get_key_str(low, high))
    print(lst)


inserting at 0
['m']
inserting at 1
['m', 's']
inserting at 2
['m', 's', 'v']
inserting at 2
['m', 's', 't', 'v']
inserting at 2
['m', 's', 'sm', 't', 'v']
inserting at 0
['g', 'm', 's', 'sm', 't', 'v']
inserting at 3
['g', 'm', 's', 'sg', 'sm', 't', 'v']
inserting at 2
['g', 'm', 'p', 's', 'sg', 'sm', 't', 'v']
inserting at 2
['g', 'm', 'n', 'p', 's', 'sg', 'sm', 't', 'v']
inserting at 3
['g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v']

如果我们在开始和结束时执行一堆插入,它的行为方式如下:

>>> for _ in range(10):
    lst.insert(0, get_key_str(high=lst[0]))  # start
    lst.insert(len(lst), get_key_str(low=lst[-1])) # end
    print(lst)


['d', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x']
['b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y']
['am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym']
['ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys']
['ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv']
['ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx']
['aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy']
['aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym']
['aad', 'aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym', 'yys']
['aab', 'aad', 'aag', 'aam', 'ab', 'ad', 'ag', 'am', 'b', 'd', 'g', 'm', 'n', 'o', 'p', 's', 'sg', 'sm', 't', 'v', 'x', 'y', 'ym', 'ys', 'yv', 'yx', 'yy', 'yym', 'yys', 'yyv']

所以在开始时你最终会得到以as为前缀的键,最后你会得到以y为前缀的键.

标签:python,algorithm,computer-science,sorting,performance
来源: https://codeday.me/bug/20190629/1324425.html