9

EDIT: Ничего себе, много больших ответов. Да, я использую это как функцию пригодности для оценки качества сортировки, выполняемой генетическим алгоритмом. Таким образом, в стоимости оценки является важным (то есть, он должен быть быстрым, предпочтительно O(n).)Алгоритм рейтинга монотонности массива (то есть, судя по «sortedness» массив)


В рамках приложения 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; 
} 

Это хорошее начало, но он не принимает во внимание возможность что могут быть «комки» отсортированных подпоследовательностей. Например:

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

Этот массив разбит на три сортированные подпоследовательности. Мой алгоритм будет оценивать его как только 40% отсортировано, но интуитивно, он должен получить более высокий балл, чем это. Есть ли стандартный алгоритм для такого рода вещей?

+1

Даже если это в контексте программирования, вы можете спросить об этом на mathoverflow.com ... они могут быть лучше подходят для предоставления полезного ответа. –

+1

Это поможет, если вы дадите нам более подробную информацию о том, какие решения ваше приложение AI будет делать на основе «сортировки» –

+0

@ Майкл Брей: это действительно http://mathoverflow.net/. Странно, mathoverflow.com разрешает один и тот же IP-адрес, но он здесь не работает. –

ответ

3

Я ожидаю, что выбор функции для использования очень сильно зависит от того, для чего вы собираетесь ее использовать. Исходя из вашего вопроса, я бы предположил, что вы используете генетическую систему для создания программы сортировки, и это должна быть функция ранжирования. Если это так, то скорость выполнения имеет решающее значение. Исходя из этого, держу пари, что ваш алгоритм с самой длинной сортировкой-подпоследовательностью будет работать очень хорошо. Похоже, он должен хорошо определить фитнес.

5

Это кажется хорошим кандидатом для Levenshtein Damerau–Levenshtein расстояния - количество свопов, необходимых для сортировки массива. Это должно быть пропорционально тому, как далеко каждый элемент находится от того места, где он должен находиться в сортированном массиве.

Вот простой алгоритм рубина, который суммирует квадраты расстояний. Кажется хорошей мерой сортировки - результат уменьшается каждый раз, когда заменяются два элемента вне порядка.

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

Но это не то, что расстояние levenshtein. levenshtein distance - расстояние редактирования, минимальное количество операций редактирования (вставка, удаление и замена) для перехода от одной последовательности к другой. – nlucaroni

+0

Общий подход интересен, можно попытаться выяснить, сколько операций «swap 2 interval from the sequence» необходимы для сортировки массива. Но я подозреваю, что на практике это очень сложно вычислить. –

+0

@Doc, опять же, обменное расстояние не levenshtein расстояние. – nlucaroni

1

Я бы предложил посмотреть на Pancake Problem и на разворотные расстояния перестановок. Эти алгоритмы часто используются для нахождения расстояния между двумя перестановками (Identity и перестановочная строка). Эта дистанционная мера должна учитывать больше скоплений значений порядка, а также развороты (монотонно уменьшаясь, а не увеличивая подпоследовательности). Есть также approximations that are polynomial time[PDF].

Это действительно все зависит от того, что означает число, и если эта функция расстояния имеет смысл в вашем контексте.

+0

Рассматривая проблему как проблему блинов, если массив отсортирован по убыванию, для его сортировки требуется только одна операция «флип», поэтому она будет рассматриваться как «почти отсортированная». Я подозреваю, что это не то, чего хочет OP. –

+0

Это почти сортировка. Кроме того, он сказал только монотонность. По убыванию или по возрастанию, все же, он показывает сущность сортировки. Я бы сказал, что 7654321 больше отсортирован, чем 4237516. Он решает проблему «сжимания». – nlucaroni

0

Это очень зависит от того, на что вы намерены использовать меру, но один простой способ сделать это - передать массив в стандартный алгоритм сортировки и измерить, сколько операций (свопов и/или сравнений) необходимо для сортировки массива.

+0

Это, скорее всего, даст * очень разные результаты в соответствии с используемым алгоритмом. –

+1

Это правда, конечно, хотя любой разумно-умный алгоритм сортировки, такой как mergesort или quicksort, будет в целом уменьшать время для «более сортированного» ввода. –

+2

Наивный вариант quicksort, в котором первый элемент каждого поддиапазона считается элементом секционирования, будет классно быть O (n^2) для уже отсортированного списка, поэтому вам нужно быть осторожным в этом! Согласно Sedgewick, сортировка вставки - ваш лучший выбор для наиболее упорядоченного списка. –

2

Вот один, который я только что составил.

Для каждой пары смежных значений вычислите числовое различие между ними.Если второе значение больше или равно первому, добавьте его к сумме sorted, в противном случае добавьте к сумме unsorted. Когда это будет сделано, возьмите соотношение двух.

2

Вычислите длины всех отсортированных подпоследовательностей, затем соберите их и добавьте их. Если вы хотите откалибровать, сколько удержаний вы нанесете наибольшим, используйте силу, отличную от 2.

Я не уверен, что лучший способ нормализовать эту длину по длине, возможно, разделить ее на квадрат длины?

0

Некоторые эксперименты с модификатором Ratcliff & 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 

Так вроде делает то, что ему нужно. Не слишком уверен, как это доказать.

2

Возможно, вы искали Kendall Tau. Это взаимно однозначная функция расстояния сортировки пузырьков между двумя массивами. Чтобы проверить, является ли массив «почти отсортированным», вычислите его Kendall Tau против отсортированного массива.

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%), чем ваш алгоритм с самым длинным сортированным пробегом.

0

Как насчет подсчета количества шагов с увеличением значения по сравнению с количеством общих шагов. Это O(n).