Берроуз-Уилер выходит на передний план

Для проекта, над которым я работаю, мне нужно реализовать преобразование Берроуза-Уилера MoveToFront в пространстве O(n). Однако по какой-то причине мой код работает с большинством значений, которые я ему подбрасываю, но не со всеми.

Моя реализация выглядит примерно так:

public byte[] transform (byte[] input)
{
    if (input.length == 0)
         return input;
    IndexedByte[] bytes = new IndexedByte[input.length];
    for (int i = 0; i < input.length; i++)
    {
        bytes[i] = new IndexedByte(input[i],i);
    }
    for (int i = 0; i < input.length -1; i++)
    {
        bytes[i].next = bytes[i+1];
    }
    bytes[input.length - 1].next = bytes[0];
    Arrays.sort(bytes);

    byte[] newBytes = new byte[input.length];
    for (int i = 0; i < bytes.length; i++)
        newBytes[i] = bytes[i].b;

    int[] indexes = new int[input.length];
    for (int i = 0; i < indexes.length; i++)
        indexes[i] = (bytes[i].origIndex + (input.length - 1)) % input.length;
    int x = 0;
    String str = new String(input); 
    for (int i = 0; i < input.length; i++)
    {
        if (bytes[i].origIndex == 0)
        {
            x = i;
            break;
        }
    }   
            byte[] header = intToByteArray(x);
    byte[] result = new byte[indexes.length+header.length];
    for (int i = 0; i < header.length; i++)
        result[i] = header[i];
    for (int i = 0; i < indexes.length; i++)
        result[i+header.length] = input[indexes[i]];
    return result;
}

Любые советы о том, что я делаю неправильно здесь? Кажется, что это не работает, когда встречается небуквенно-цифровой символ (т.е. само кодирование, кажется, что /* и т. д. испортят его).


person Jason    schedule 30.07.2009    source источник
comment
Строка String str = new String(input); не нужна, но вряд ли она будет вашей проблемой.   -  person Matthew Murdoch    schedule 30.07.2009
comment
Возможно, вы захотите включить код для intToByteArray   -  person Laurence Gonsalves    schedule 30.07.2009
comment
К сожалению, извините: pastebin.com/d6726a4ab   -  person Jason    schedule 30.07.2009
comment
Кажется, что это не работает, когда встречается небуквенно-цифровой символ (т.е. само кодирование, кажется, что /* и т. д. испортят его).   -  person Jason    schedule 30.07.2009
comment
intToByteArray - это просто битовый сдвиг от int до 4 байтов.   -  person Jason    schedule 30.07.2009
comment
Метод IndexedByte.compareTo(Object) выглядит немного странно (где он делегирует сравнение со следующим IndexedByte). Это какая-то оптимизация?   -  person Matthew Murdoch    schedule 30.07.2009
comment
Создание newBytes также кажется ненужным (к нему не обращаются после заполнения).   -  person Matthew Murdoch    schedule 30.07.2009
comment
Просто перепроверьте (или покажите) метод inToByteArray - простые битовые сдвиги часто приводят к ошибкам, потому что мы имеем дело со значениями со знаком... просто мой опыт   -  person Andreas Dolk    schedule 30.07.2009
comment
private byte[] intToByteArray (final int integer) { byte[] byteArray = new byte[4]; byteArray[3] = (байт) целое число; byteArray[2] = (byte) (integer ››(8)); byteArray[1] = (byte) (integer ›› (16)); byteArray[0] = (байт) (целое число ›› (24)); возврат (массив байтов); } public static final int byteArrayToInt(byte [] b) { return (b[0] ‹‹ 24) + ((b[1] ) ‹‹ 16) + ((b[2] ) ‹‹ 8) + (b [3]); }   -  person Jason    schedule 30.07.2009
comment
CompareTo должен сравнивать со следующим IndexedByte в списке в случае, если есть две строки aab и aac, aab должен стоять первым.   -  person Jason    schedule 30.07.2009


Ответы (1)


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

System.out.println(byteArrayToInt(intToByteArray(128)));

Попробуйте изменить код на:

private int byteArrayToInt(byte[] b) {
    return (b[0] << 24) + 
          ((b[1] & 0xFF) << 16) + 
          ((b[2] & 0xFF) << 8) +
           (b[3] & 0xFF);
}

Кроме того, предел MAXIMUM = 50000 в пределах IndexedByte.compareTo никогда не достигается. Я получил java.lang.StackOverflowError с входным массивом длиной 5214. Я бы предложил изменить его на итеративный, а не на рекурсивный (это должно быть довольно просто, поскольку вы знаете длину входного массива, а также предотвратит избыточное зацикливание в патологическом случае где все байты во входном массиве равны).

person Matthew Murdoch    schedule 30.07.2009