用于对数组的单调性进行评级的算法(即,判断数组的“排序性”)

时间:2010-01-20 19:10:04

标签: math artificial-intelligence genetic-algorithm information-theory


编辑:哇,很多很棒的回复。是的,我使用它作为一个适应度函数来判断遗传算法执行的排序质量。因此,评估成本很重要(即,它必须很快,最好是O(n)。)


作为我正在使用的AI应用程序的一部分,我希望能够根据其单调性(也就是其“排序性”)对整数的候选数组进行评级。目前,我正在使用一种计算最长排序运行的启发式算法,然后将其除以数组的长度:

public double monotonicity(int[] array) {
    if (array.length == 0) return 1d;

    int longestRun = longestSortedRun(array);
    return (double) longestRun / (double) array.length;
}

public int longestSortedRun(int[] array) {

    if (array.length == 0) return 0;

    int longestRun = 1;
    int currentRun = 1;

    for (int i = 1; i < array.length; i++) {
        if (array[i] >= array[i - 1]) {
            currentRun++;
        } else {
            currentRun = 1;
        }

        if (currentRun > longestRun) longestRun = currentRun;
    }

    return longestRun;
}

这是一个良好的开端,但它没有考虑到可能存在分类子序列的“团块”的可能性。 E.g:

{ 4, 5, 6, 0, 1, 2, 3, 7, 8, 9}

此数组被划分为三个已排序的子序列。我的算法将它评定为只有40%排序,但直观地说,它应该得到更高的分数。这种事情有标准的算法吗?

11 个答案:

答案 0 :(得分:5)

这似乎是 Levenshtein Damerau–Levenshtein距离的良好候选者 - 对数组进行排序所需的交换次数。这应该与每个项目与排序数组中的位置的距离成比例。

这是一个简单的ruby算法,它总结了距离的平方。它似乎是排序的一个很好的衡量标准 - 每次交换两个无序元素时结果都会变小。

ap = a.sort
sum = 0
a.each_index{|i| j = ap.index(a[i])-i 
  sum += (j*j)
}
dist = sum/(a.size*a.size)

答案 1 :(得分:3)

我希望使用的功能选择非常依赖于您打算使用它的功能。基于你的问题,我猜你正在使用遗传系统来创建一个排序程序,这就是排名功能。如果是这种情况,那么执行速度至关重要。基于此,我打赌你的最长排序子序列算法可以很好地工作。这听起来应该很好地定义健身。

答案 2 :(得分:2)

答案 3 :(得分:2)

这是我刚刚编写的一个。

对于每对相邻值,计算它们之间的数字差异。如果第二个大于或等于第一个,请将其添加到sorted总计,否则添加到unsorted总计。完成后,取两者的比例。

答案 4 :(得分:2)

计算所有已排序子序列的长度,然后对它们进行平方并添加它们。 如果您想校准最大的enphasis,请使用不同于2的功率。

我不确定用长度标准化它的最佳方法是什么,也许它除了每长度的平方?

答案 5 :(得分:2)

您可能正在寻找的是Kendall Tau。它是两个数组之间的冒泡排序距离的一对一功能。要测试数组是否“几乎已排序”,请针对排序数组计算其Kendall Tau。

答案 6 :(得分:1)

我建议查看Pancake Problem和排列的反转距离。这些算法通常用于查找两个排列之间的距离(标识和置换字符串)。该距离测量应考虑更多的顺序值,以及逆转(单调递减而不是增加子序列)。还有approximations that are polynomial time[PDF]

这实际上取决于数字的含义以及此距离函数是否在您的上下文中有意义。

答案 7 :(得分:1)

我有同样的问题(单调性评分),我建议你试试Longest Increasing Subsequence。最有效的算法在O(n log n)中运行,并非如此糟糕。

从问题的例子中,{4, 5, 6, 0, 1, 2, 3, 7, 8, 9}的最长增长序列是{0, 1, 2, 3, 7, 8, 9}(长度为7)。也许它比你运行时间最长的算法更好(70%)。

答案 8 :(得分:0)

这在很大程度上取决于您打算使用该度量的方法,但一种简单的方法是将数组提供给标准排序算法并测量需要进行多少操作(交换和/或比较)完成排序数组。

答案 9 :(得分:0)

使用修饰符Ratcliff&amp; amp; Obershelp

>>> from difflib import SequenceMatcher as sm
>>> a = [ 4, 5, 6, 0, 1, 2, 3, 7, 8, 9 ]
>>> c = [ 0, 1, 9, 2, 8, 3, 6, 4, 7, 5 ]
>>> b = [ 4, 5, 6, 0, 1, 2, 3, 7, 8, 9 ]
>>> b.sort()
>>> s = sm(None, a, b)
>>> s.ratio()
0.69999999999999996
>>> s2 = sm(None, c, b)
>>> s2.ratio()
0.29999999999999999

这样做有什么需要。不太确定如何证明它。

答案 10 :(得分:0)

如何计算增加值的步数以及总步数。那是O(n)