в java измените размер массива символов с нулевым символом

В следующем коде (из «Интервью по взлому кода» от Gaale Laakman) показано, как удалить повторяющиеся символы в массиве char без использования копии массива, чтобы избежать дополнительного использования памяти. Он перезаписывает последние символы в первом массиве со смещением. Поскольку последний массив меньше предыдущего, нулевой символ устанавливается в позиции, следующей за конечными символами, как бы говоря, что массив останавливается на этом:

    str[tail] = 0;

Мне было интересно, изменится ли при этом переменная «длина» массива. Если нет, то я не понимаю, почему этот пример работает. Или это просто пример, в котором мы должны проверить, где находится нулевой символ, чтобы найти длину массива и не использовать рассматриваемую переменную длины?

Вот весь код:

    public static void removeDuplicates(char[] str) {
        if (str == null) return;
        int len = str.length;
        if (len < 2) return;
        int tail = 1;
        for (int i = 1; i < len; ++i) {
            int j;
            for (j = 0; j < tail; ++j) {
                if (str[i] == str[j]) break;
            }
            if (j == tail) {
                str[tail] = str[i];
                ++tail;
            }
        }
        str[tail] = 0;
    }

person sarah vb    schedule 01.03.2017    source источник
comment
Пожалуйста, размещайте код в виде текста, а не изображения. Мы хотели бы иметь возможность копировать его полностью или частично.   -  person Ole V.V.    schedule 01.03.2017
comment
Я проголосовал против. Я предполагаю, что это идея какого-то академического умника из пещерных веков программирования (C или даже раньше) ... Абсолютно бесполезное упражнение (особенно на Java) с достаточно очень плохими побочными эффектами.   -  person Vadim    schedule 01.03.2017
comment
to Оле В.В., спасибо за комментарий, сделанный в редакции.   -  person sarah vb    schedule 03.03.2017
comment
Для Водема код действительно не кажется правильным для java. Я полагаю, что цель упражнения - подумать об оптимизации памяти, потому что в случае, если строка очень длинная... но вы правы, это не совсем реалистично.   -  person sarah vb    schedule 03.03.2017


Ответы (3)


Массив имеет фиксированную длину при создании. В примере они хотят сэкономить время, всегда повторно используя один и тот же массив для каждой итерации. Так как сжать массив невозможно (так как длина определяется при создании), они используют обходной путь, ставя ноль в том месте, где должен заканчиваться массив. Когда их цикл достигает нуля, он знает, что находится в концептуальном «конце» массива.

person rdhaese    schedule 01.03.2017
comment
Спасибо, я так и думал, но хотел убедиться! - person sarah vb; 01.03.2017

Звучит как вопрос, переведенный с C или C++. В этих языках вы используете нулевой символ в конце строки (которая, в свою очередь, представляет собой массив char). В Java это не работает; массив никогда не меняет своей длины.

Если вызывающая сторона знает, что этот нулевой символ вставлен, он, конечно, может использовать эту информацию и игнорировать символы после нулевого. Они не могут использовать переменную len, так как она существует только внутри метода и не существует, когда метод возвращается.

В Java вы обычно делаете:

str = Arrays.copyOf(str, tail);

Это создаст новый массив нужной длины и скопирует все символы (это то, на что направлен пример кода).

Кстати, я получаю ArrayIndexOutOfBoundsException в строке str[tail] = 0; в конце, если не было найдено дубликатов. В этом случае tail равно длине массива и, следовательно, на 1 позицию дальше последнего элемента.

person Ole V.V.    schedule 01.03.2017
comment
Вы правы насчет исключения. Как ни странно, чуть дальше в книге есть пример, когда массив увеличивается в размере (замените пробелы на '%20'). И автор снова определяет значения массива за пределами границ. Может быть, мы не используем ту же версию Java... - person sarah vb; 03.03.2017
comment
Так было во всех версиях Java. В основном это звучит как плохой перевод с C или C++, но могут быть и другие объяснения. - person Ole V.V.; 03.03.2017

Массив неизменяем, поэтому длина не меняется, пустое пространство заполняется нулевыми значениями.

public class MainClass {

public static void main(String[] args) {
char[] org={'a','b','b','c'};
System.out.println(org.length);
System.out.println(org);
removeDuplicate(org);
System.out.println(org.length);
   System.out.println(org);

}
public static void removeDuplicate(char[]str){
if(str==null)return;
int len=str.length;
if(len<2)return;
int tail=1;
for(int i=1;i<len;++i){
    int j;
    for(j=0;j<tail;++j){
        if(str[i]==str[j])break;
    }
    if(j==tail){
    str[tail]=str[i];
    ++tail;
    }
}
   str[tail]=0;
  }
 }

**Results**
   4
  abbc
   4
  abc
person Joe ONeil    schedule 01.03.2017
comment
Просто придирки, массив не является неизменным в обычном смысле этого слова, поскольку вы можете перезаписывать элементы. Вы правы, длину изменить нельзя. - person Ole V.V.; 01.03.2017
comment
поскольку он помещает в массив только один нулевой символ, вывод 'abbbc' будет 'abcc'. Это означает, что функция println не считает нулевой символ концом строки. - person sarah vb; 03.03.2017