有没有一种方法可以衡量列表的排序方式?
我的意思是,这不是要知道列表是否已排序(布尔值),而是诸如“排序”之比,诸如统计中的相关系数之类的东西。
例如,
如果列表中的项目按升序排列,则其比率为1.0
如果列表降序排列,则其速率将为-1.0
如果list几乎升序排列,则其比率将是0.9或接近1的某个值。
如果列表根本不排序(随机),则其速率将接近0
我正在Scala中编写一个小型图书馆进行练习。我认为排序速率会很有用,但我找不到有关此类信息的任何信息。也许我不知道这个概念的适当术语。
有没有一种方法可以衡量列表的排序方式?
我的意思是,这不是要知道列表是否已排序(布尔值),而是诸如“排序”之比,诸如统计中的相关系数之类的东西。
例如,
如果列表中的项目按升序排列,则其比率为1.0
如果列表降序排列,则其速率将为-1.0
如果list几乎升序排列,则其比率将是0.9或接近1的某个值。
如果列表根本不排序(随机),则其速率将接近0
我正在Scala中编写一个小型图书馆进行练习。我认为排序速率会很有用,但我找不到有关此类信息的任何信息。也许我不知道这个概念的适当术语。
Answers:
您可以简单地计算列表中的反转次数。
类型的元素序列中的一个反转T
是一对序列元素,它们根据<
的集合上的某些顺序乱序出现T
。
从维基百科:
正式地,让数字
A(1), A(2), ..., A(n)
序列n
。
如果i < j
和A(i) > A(j)
,然后在一对(i,j)
被称为反转的A
。的反转数的序列的是它的有序性的一个公共量度。
形式上,将反转数定义为反转数,即
为了使这些定义更清楚,请考虑示例序列9, 5, 7, 6
。该序列具有反演 (0,1), (0,2), (0,3), (2,3)
和反演编号 4
。
如果您想要介于0
和之间的值1
,则可以将反转数除以N choose 2
。
要实际创建一种算法来计算此分数对列表的排序方式,您有两种方法:
修改您喜欢的排序算法,以跟踪其运行时正在纠正的反转次数。尽管这是不平凡的,并且根据您选择的排序算法有不同的实现方式,但是最终您得到的算法(就复杂性而言)不会比开始时的排序算法昂贵。
如果您采用这种方式,请注意,这并不像计算“掉期”那么简单。例如,Mergesort是最坏的情况O(N log N)
,但是如果它在以降序排列的列表上运行,它将纠正所有N choose 2
反转。O(N^2)
在O(N log N)
操作中纠正了这种反转。因此,某些操作不可避免地必须一次校正多个反转。您必须小心执行。注意:您可以非常O(N log N)
复杂地完成此操作,这很棘手。
相关:计算排列中的“反转”数
(i,j)
,其中i != j
list[min(i,j)] < list[max(i,j)]
(0还是1)N choose 2
除非您对准确性有要求,否则我个人会采用随机方法-仅仅是因为它很容易实现。
如果您真正想要的是(降序排列)到(升序排列z'
)之间的值(),则可以使用以下公式将((升序排列)和(降序排列)之间的()以上的值简单地映射到此范围:-1
1
z
0
1
z' = -2 * z + 1
您可以使用实际的相关性。
假设您为排序列表中的每个项目分配了一个从零开始的整数等级。请注意,元素位置索引与等级的关系图看起来像直线上的点(位置与等级之间的相关系数为1.0)。
您可以计算此数据的相关性。对于反向排序,您将得到-1,依此类推。
除了倒数,对于数字列表,可以想象到距排序状态的均方距离:
#! ruby
d = -> a { a.zip( a.sort ).map { |u, v| ( u - v ) ** 2 }.reduce( :+ ) ** 0.5 }
a = 8, 7, 3, 4, 10, 9, 6, 2, 5, 1
d.( a ) #=> 15.556
d.( a.sort ) #=> 0.0
d.( a.sort.reverse ) # => 18.166 is the worrst case
我会计算比较数并将其除以比较总数。这是一个简单的Python示例。
my_list = [1,4,5,6,9,-1,5,3,55,11,12,13,14]
right_comparison_count = 0
for i in range(len(my_list)-1):
if my_list[i] < my_list[i+1]: # Assume you want to it ascending order
right_comparison_count += 1
if right_comparison_count == 0:
result = -1
else:
result = float(right_comparison_count) / float((len(my_list) - 1))
print result
这样的事情怎么样?
#!/usr/bin/python3
def sign(x, y):
if x < y:
return 1
elif x > y:
return -1
else:
return 0
def mean(list_):
return float(sum(list_)) / float(len(list_))
def main():
list_ = [ 1, 2, 3, 4, 6, 5, 7, 8 ]
signs = []
# this zip is pairing up element 0, 1, then 1, 2, then 2, 3, etc...
for elem1, elem2 in zip(list_[:-1], list_[1:]):
signs.append(sign(elem1, elem2))
# This should print 1 for a sorted list, -1 for a list that is in reverse order
# and 0 for a run of the same numbers, like all 4's
print(mean(signs))
main()
如果您使用列表,请计算该列表中值的等级,然后调用该等级Y
列表,然后调用另一个列表,X
该列表包含从1
到的整数length(Y)
,您可以通过计算相关系数来获得所需的排序量度。,,r
两个列表之间。
r = \frac{\sum ^n _{i=1}(X_i - \bar{X})(Y_i - \bar{Y})}{\sqrt{\sum ^n _{i=1}(X_i - \bar{X})^2} \sqrt{\sum ^n _{i=1}(Y_i - \bar{Y})^2}}
对于完全排序的列表,r = 1.0
对于反向排序的列表r=-1.0
,以及r
这些限制之间的差异,以实现不同程度的排序。
取决于应用程序,此方法可能存在的问题是,计算列表中每个项目的等级等同于对其进行排序,因此它是O(n log n)操作。