有没有办法衡量列表的排序方式?

时间:2013-06-08 00:11:00

标签: arrays algorithm list sorting

有没有办法衡量列表的排序方式?

我的意思是,它不是要知道列表是否排序(布尔值),而是类似“排序”的比例,类似于统计中的相关系数。

例如,

  • 如果列表中的项目按升序排列,那么其费率将为1.0

  • 如果列表按降序排序,则其速率将为-1.0

  • 如果列表几乎按升序排序,则其速率为0.9或某个值接近1。

  • 如果列表根本没有排序(随机),其费率将接近0

我正在Scala写一个小型图书馆进行练习。我认为排序率会很有用,但我找不到任何类似的信息。也许我不知道这个概念的适当术语。

9 个答案:

答案 0 :(得分:141)

您只需计算列表中的反转次数即可。

反演

T类型元素序列中的反转是一对序列元素,它们根据<的集合上的某些排序T按顺序出现。< / p>

来自Wikipedia

  

正式地,让A(1), A(2), ..., A(n)成为n个数字序列。
如果i < jA(i) > A(j),那么(i,j)对称为A反转

     

序列的反转数是其排序性的一个常用度量。
正式地,反转数被定义为反转次数,即

     

definition

为了使这些定义更清晰,请考虑示例序列9, 5, 7, 6。此序列包含反转 (0,1), (0,2), (0,3), (2,3)反转数 4

如果您想要01之间的值,则可以将反转数除以N choose 2

要实际创建一个算法来计算列表排序方式的分数,您有两种方法:

方法1(确定性)

修改您喜欢的排序算法,以跟踪它在运行时纠正的反转次数。虽然这是非常重要的,并且根据您选择的排序算法具有不同的实现,但最终会得到一种算法,与您开始使用的排序算法相比,这种算法不会更复杂(在复杂性方面)。

如果采取这种方式,请注意它并不像计算“交换”那么简单。例如,Mergesort是最坏情况O(N log N),但如果它在按降序排序的列表上运行,它将纠正所有N choose 2个反转。在O(N^2)操作中纠正了O(N log N)次反转。因此,一些操作必然会一次纠正一次以上的反转。你必须小心你的实现。 注意:您可以使用O(N log N)复杂度执行此操作,这非常棘手。

相关:calculating the number of “inversions” in a permutation

方法2(随机)

  • 随机抽样对(i,j),其中i != j
  • 对于每对,确定list[min(i,j)] < list[max(i,j)](0或1)
  • 计算这些比较的平均值,然后按N choose 2
  • 进行标准化

我个人会采用随机方法,除非你有一个正确的要求 - 只是因为它很容易实现。


如果你真正想要的是z'(按降序排序)到-1(升序排序)之间的值(1),你可以简单地映射上面的值({{1使用以下公式将z(按升序排序)和0(按降序排序)之间的值放在此范围内:

1

答案 1 :(得分:24)

对列表(或其他顺序结构)进行排序的传统方法是反转次数。

反转次数是a的对(a,b)st指数的数量。 b AND b << a。出于这些目的,<<表示您为特定排序选择的任何排序关系。

完全排序的列表没有反转,完全颠倒的列表具有最大的反转次数。

答案 2 :(得分:17)

您可以使用实际相关性。

假设对于排序列表中的每个项目,您指定从零开始的整数排名。请注意,元素位置索引与排名的关系图看起来像直线上的点(位置和排名之间的相关性为1.0)。

您可以计算此数据的相关性。对于反向排序,您将获得-1,依此类推。

答案 3 :(得分:4)

有很好的答案,我想为完整性添加一个数学方面:

  • 您可以通过衡量列表与排序列表的相关程度来衡量列表的排序方式。为此,您可以使用等级相关性(最常见的是Spearman's),这与通常的相关性完全相同,但它使用列表中的元素等级而不是其项目的模拟值

  • 存在许多扩展,例如相关系数(精确排序为+1,精确倒置为-1)

  • 这允许您具有此度量的统计属性,例如置换中心极限定理,它允许您了解此度量随机列表的分布。

答案 4 :(得分:3)

除了反转计数之外,对于数字列表,可以想象与排序状态的均方距离:

#! 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

答案 5 :(得分:1)

我不确定“最佳”方法,但一个简单的方法是将每个元素与后面的元素进行比较,如果element2&gt;则递增计数器。元素1(或任何你想测试的)然后除以元素的总数。它应该给你一个百分比。

答案 6 :(得分:1)

我会计算比较并将其除以总比较数。这是一个简单的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

答案 7 :(得分:0)

如果您获取列表,请计算该列表中值的排名并调用排名列表Y和另一个列表X,其中包含从1到{的整数{1}},您可以通过计算两个列表之间的correlation coefficientlength(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.0r=-1.0在这些限制之间因不同的排序程度而异。

这种方法可能存在的问题,取决于应用程序,计算列表中每个项目的等级等同于对其进行排序,因此它是O(n log n)操作。

答案 8 :(得分:0)

这样的事情怎么样?

#!/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()