Как изменить массив int в Java?


238

Я пытаюсь изменить массив int в Java.

Этот метод не переворачивает массив.

for(int i = 0; i < validData.length; i++)
{
    int temp = validData[i];
    validData[i] = validData[validData.length - i - 1];
    validData[validData.length - i - 1] = temp;
}

Что с этим не так?


31
Я вижу, что я сделал не так. Должно быть validData.length / 2. В противном случае он обратится сам, а затем развернется сам.
— Майкл Скотт

4
См. En.wikipedia.org/wiki/In-place_algorithm, в котором содержится описание правильной версии этого алгоритма.
— Дин Повей

Ответы:


284

Чтобы перевернуть массив int, вы меняете элементы вверх, пока не достигнете средней точки, например:

for(int i = 0; i < validData.length / 2; i++)
{
    int temp = validData[i];
    validData[i] = validData[validData.length - i - 1];
    validData[validData.length - i - 1] = temp;
}

То, как вы это делаете, вы меняете местами каждый элемент дважды, поэтому результат совпадает с исходным списком.


И я хотел бы поставить validData.length / 2часть на внешней стороне цикла.
— Джин Квон

7
@ Джин, я бы не стал. Это только запутывает смысл, и я уверен, что оптимизирующий компилятор все равно сделает это за вас. В любом случае, нет никакого смысла в микрооптимизации, пока у вас нет четких доказательств того, что это необходимо / полезно.
— Нику Стирка

9
@JinKwon Это было бы как делать validData.length >> 1. Это эквивалентно и быстрее, но это сбивает с толку многих программистов, и любой хороший компилятор сделает это автоматически.
— Джастин

2
Вы должны сделать этот расчет только один раз validData.length - i - 1и сохранить его в переменной.

Может ли кто-нибудь предложить изменение без временной переменной !!
— sg28

303

С Commons.Lang вы можете просто использовать

ArrayUtils.reverse(int[] array)

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


3
Я бы предпочел, чтобы он возвращал обратный (переданный) массив для функционально-подобного стиля.
— Лоран Г

2
@ laurent-g, чтобы быть справедливым: обратный способ массива более эффективен, поэтому, вероятно, они и сделали это.
— Sirmyself

4
Моя точка зрения не была копией или не копией. В моем сообщении указано «(передано)», которое должно быть возвращено (после обращения), чтобы его можно было передать в выражении, не требуя отдельного оператора.
— Лоран Г.

52
public class ArrayHandle {
    public static Object[] reverse(Object[] arr) {
        List<Object> list = Arrays.asList(arr);
        Collections.reverse(list);
        return list.toArray();
    }
}

11
Конечно будет. Список может содержать только Объекты, но не примитивы, поэтому все примитивы ( intв данном случае) упакованы в соответствующие оболочки ( Integerв данном случае) и помещены в список. Вы видите, Integerэто объекты. @Tom
— 11684

6
Осторожно: если я не ошибаюсь, исходный массив модифицируется. Чтобы было ясно, вы можете просто ничего не возвращать.
— Андреа Зилио

3
@ 11684 Да, общие списки могут содержать только объекты. Но метод исключает массив. Массивы могут содержать примитивы. Поэтому int[]отличается от Integer[]. Попробуйте: Integer[] array = new int[5]. Вы получите ошибку компиляции. Вот почему Arraysкласс Java определяет набор методов для работы с примитивными массивами. Попытка передать int[]вышеупомянутый метод приведет к чему-то вроде The method reverse(Object[]) in the type MakeSimple is not applicable for the arguments (int[]). @Filip - алгоритм на месте использует меньше памяти и работает быстрее.
— Брайан Маккатон

3
@ Андреа На самом деле это не так. Возвращаемый список Arrays.asList()не ссылается на исходный массив и не возвращает массив. Это одна из проблем этого метода: он использует тройную память и выполняет тройную работу как алгоритм на месте.
— Брайан Маккатон

4
Этот метод сам по себе может работать, но просто нельзя передать его int[]в качестве аргумента ( «несовместимые типы: int [] нельзя преобразовать в Object []» ).
— MC Emperor

47
Collections.reverse(Arrays.asList(yourArray));

java.util.Collections.reverse()может перевернуть java.util.Lists и java.util.Arrays.asList()вернуть список, который оборачивает определенный массив, который вы передаете ему, поэтому yourArrayпереворачивается после вызова Collections.reverse().

Стоимость всего лишь создания одного объекта List, дополнительные библиотеки не требуются.

Подобное решение было представлено в ответе Тарика и его комментаторов, но я думаю, что этот ответ был бы более кратким и более простым для анализа.


15
Для массивов объектов это хорошее решение. Но это не работает для массивов примитивов. Например передача int[]to asList(...)не будет возвращать a List<Integer>, но a List<int[]>, содержащий один элемент. Существует AFAICS нет простой встроенный способ конвертировать int[]в Integer[].
— Мартин Руст

4
Это не будет работать с примитивными массивами ... коллекции не возвращают значение, так что теперь у вас есть бесполезный массив в виде списка в памяти
— NightSkyCode

@MartinRust Java 8+: Arrays.stream(arr).boxed().collect(Collectors.toList())илиArrays.stream(arr).boxed().toArray(Integer[]::new)
— Саймон Форсберг

39

Я думаю, что немного проще следовать логике алгоритма, если вы объявляете явные переменные для отслеживания индексов, которые вы меняете на каждой итерации цикла.

public static void reverse(int[] data) {
    for (int left = 0, right = data.length - 1; left < right; left++, right--) {
        // swap the values at the left and right indices
        int temp = data[left];
        data[left]  = data[right];
        data[right] = temp;
    }
}

Я также думаю, что это легче сделать в цикле while.

public static void reverse(int[] data) {
    int left = 0;
    int right = data.length - 1;

    while( left < right ) {
        // swap the values at the left and right indices
        int temp = data[left];
        data[left] = data[right];
        data[right] = temp;

        // move the left and right index pointers in toward the center
        left++;
        right--;
    }
}

своп старой школы выглядит проще, но да, если задействованы значения индекса массива влево, вправо, ... будет полезно для отладки, если таковые имеются
— Сринат Ганеш,

Вы также можете добавить 'public static void swap (int [] data, int index1, int index2) {...}' и использовать его из 'reverse' следующим образом: swap (data, left, right).
— PM_

13

Здесь уже есть много ответов, в основном направленных на изменение массива на месте. Но для полноты картины, есть другой подход, использующий потоки Java для сохранения исходного массива и создания нового обращенного массива:

    int[] a = {8, 6, 7, 5, 3, 0, 9};
    int[] b = IntStream.rangeClosed(1, a.length).map(i -> a[a.length-i]).toArray();

10

С гуавой:

Collections.reverse(Ints.asList(array));

4
Это великолепно! Коротко и эффективно. Как и все asListметоды, он создает представление, которое записывает непосредственно в резервный (примитивный) массив. Я думаю, что избиратель здесь ошибочно думал, что это вернуло коробочный список или кое-что.
— Люк Ашервуд

@LukeUsherwood, по-видимому, все еще будут некоторые накладные расходы от упаковки и распаковки при вызове get и set для каждого элемента. Но я согласен с вами, что это блестящее решение.
— Патрик Паркер

Действительно, об этом стоит знать. Я не думаю, что это будет иметь большое значение в большинстве кода, с которым я лично работаю - наши «горячие» области четко определены, остальное - это своего рода «клейкий код». В то же время я уверен, что отток памяти также создает дополнительную «скрытую» стоимость, которую профилировщики не приписывают фактической функции.
— Люк Ашервуд

@LukeUsherwood он все еще возвращает коробочный список вместо массива prim
— AnthonyJClink

2
@AnthonyJClink Не уверен, что означает «это», но утилита JDK Collections.reverseявляется пустым методом. Это работает на месте во внутреннем классе Guava, который упаковывает int[](поскольку он никогда не хранит список в штучной упаковке, Integerя бы не назвал этот класс «коробочным списком», а скорее «представлением списка массива»). Но да, он работает через интерфейс, пропускающий Integerобъекты, поэтому, как уже упоминалось, это создаст много временных откатов и коробок объектов. Попробуйте IntStreamбиблиотеку или коллекцию примитивов, где важна производительность. (Trove, Koloboke, Eclipse Collections, ...)
— Люк Ашервуд

10

В случае Java 8 мы также можем использовать IntStreamдля обращения к массиву целых чисел:

int[] sample = new int[]{1,2,3,4,5};
int size = sample.length;
int[] reverseSample = IntStream.range(0,size).map(i -> sample[size-i-1])
                      .toArray(); //Output: [5, 4, 3, 2, 1]

7

Просто для цикла!

for (int start = 0, end = array.length - 1; start <= end; start++, end--) {
    int aux = array[start];
    array[start]=array[end];
    array[end]=aux;
}

4
В будущем, пожалуйста, сообщите спрашивающему конкретно, что они сделали неправильно, и что вы сделали правильно.
— Картик Чаг

1
изменить start <= endнаstart < end
— Леонард Паули


5
for(int i=validData.length-1; i>=0; i--){
  System.out.println(validData[i]);
 }

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

5

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

Я надеюсь, что вы что-то почерпнули из этого.

@Test
public void reverseTest(){
   Integer[] ints = { 1, 2, 3, 4 };
   Integer[] reversedInts = reverse(ints);

   assert ints[0].equals(reversedInts[3]);
   assert ints[1].equals(reversedInts[2]);
   assert ints[2].equals(reversedInts[1]);
   assert ints[3].equals(reversedInts[0]);

   reverseInPlace(reversedInts);
   assert ints[0].equals(reversedInts[0]);
}

@SuppressWarnings("unchecked")
private static <T> T[] reverse(T[] array) {
    if (array == null) {
        return (T[]) new ArrayList<T>().toArray();
    }
    List<T> copyOfArray = Arrays.asList(Arrays.copyOf(array, array.length));
    Collections.reverse(copyOfArray);
    return copyOfArray.toArray(array);
}

private static <T> T[] reverseInPlace(T[] array) {
    if(array == null) {
        // didn't want two unchecked suppressions
        return reverse(array);
    }

    Collections.reverse(Arrays.asList(array));
    return array;
}

2
Не решает исходную проблему с использованием приматов.
— Мелинда Грин

Есть много способов конвертировать простые числа в объекты. Я всегда рекомендую по возможности избегать простых чисел в java, и я также считаю, что это следует поощрять.
— AnthonyJClink

Преобразование массива примитивов неизвестной длины в массив может быть очень плохой идеей, особенно если это сделать, не осознавая этого. Ява не Smalltalk. Примитивы являются частью языка и имеют свое место. Неважно, если они нам не нравятся, мы должны их принять и использовать по мере необходимости.
— Мелинда Грин

1
Вам на самом деле не нужно копировать массив, просто Collections.reverse(asList(arraytoReverse)); return arrayToReverse;. asListэто просто обертка вокруг массива, поэтому исходный массив перевернут.
— Radiodef

3

Ваша программа будет работать только для length = 0, 1. Можешь попробовать :

int i = 0, j = validData.length-1 ; 
while(i < j)
{
     swap(validData, i++, j--);  // code for swap not shown, but easy enough
}

3
Возможно, вы имели в виду swap в качестве псевдокода для встроенного обмена, а не для вызова метода, но в противном случае это не сработает. Java передается по ссылке, поэтому невозможно написать метод подкачки для переменных.
— Дин Повей

Я имел в виду любой способ поменять местами v [i] и v [j]. Я знаю, как вызовы методов работают в Java. Для метода вы можете сделать что-то вроде swap (v, i ++, j--);
— fastcodejava

1
Дин, массив validData - это объект, переданный по ссылке, поэтому метод swap () будет работать отлично.
— Гаэль Оберсон

3

Если вы работаете с более примитивными данными (например, char, byte, int и т. Д.), Вы можете сделать несколько забавных операций XOR.

public static void reverseArray4(int[] array) {
    int len = array.length;
    for (int i = 0; i < len/2; i++) {
        array[i] = array[i] ^ array[len - i  - 1];
        array[len - i  - 1] = array[i] ^ array[len - i  - 1];
        array[i] = array[i] ^ array[len - i  - 1];
    }
}

1
Слишком мило, чтобы на самом деле использовать в производственном коде, но, тем не менее, весело. Для максимальной привлекательности используйте операцию% =, например: массив [i]% = массив [len - i - 1] и т. Д.
— Мелинда Грин,

Похоже, но немного короче:for (int m = x.length, i = --m / 2; ++i <= m;) { x[i] ^= x[m - i]; x[i] ^= x[m - i] ^= x[i]; }
— Томас Мюллер

2

Наиболее эффективно просто перебирать массив в обратном направлении.

Я не уверен, что решение Аарона делает этот vi этот вызов Collections.reverse(list);Кто-нибудь знает?


Итерация в обратном направлении по массиву требует нового массива. Мне нравится решение, опубликованное выше, которое выполняет реверсирование строк без создания нового массива.
— mmcdole

1
@Simucal зачем создавать новый массив? Просто повторяйте это назад.
— Trejkaz

2
public void getDSCSort(int[] data){
        for (int left = 0, right = data.length - 1; left < right; left++, right--){
            // swap the values at the left and right indices
            int temp = data[left];
            data[left]  = data[right];
            data[right] = temp;
        }
    }

1
public void display(){
  String x[]=new String [5];
  for(int i = 4 ; i > = 0 ; i-- ){//runs backwards

    //i is the nums running backwards therefore its printing from       
    //highest element to the lowest(ie the back of the array to the front) as i decrements

    System.out.println(x[i]);
  }
}

1
да, я пробовал такой же и чистый код вместе с выводом int [] a = {1,3,5,2,6,7}; for (int i = a.length-1; i> = 0; i--) {System.out.print (a [i] + "");} `он обратит массив от последнего индекса к первому индексу
— Rocket_03

1

Разве это не будет намного менее вероятно для ошибок?

    int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int[] temp = new int[intArray.length];
    for(int i = intArray.length - 1; i > -1; i --){
            temp[intArray.length - i -1] = intArray[i];
    }
    intArray = temp;

1

Решение с o (n) временной сложностью и o (1) пространственной сложностью.

void reverse(int[] array) {
    int start = 0;
    int end = array.length - 1;
    while (start < end) {
        int temp = array[start];
        array[start] = array[end];
        array[end] = temp;
        start++;
        end--;
    }
}

Просто FYI, это может быть упрощено в комплекс для цикла: for (int start = 0, end = array.length - 1; start < end; start++, end--) { ... }.
— Тим Кук

1

2 способа перевернуть массив.

  1. Используя цикл For и меняйте элементы до средней точки с временной сложностью O (n / 2).

    private static void reverseArray() {
    int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
    
    for (int i = 0; i < array.length / 2; i++) {
        int temp = array[i];
        int index = array.length - i - 1;
        array[i] = array[index];
        array[index] = temp;
    }
    System.out.println(Arrays.toString(array));

    }

  2. Использование встроенной функции (Collections.reverse ())

    private static void reverseArrayUsingBuiltInFun() {
    int[] array = new int[] { 1, 2, 3, 4, 5, 6 };
    
    Collections.reverse(Ints.asList(array));
    System.out.println(Arrays.toString(array));

    }

    Выход: [6, 5, 4, 3, 2, 1]


3
Что такое Ints?
— CodingNow

@CodingNow это один из вспомогательных классов утилит Guava - смотрите здесь
— mrec

1
    public static void main(String args[])    {
        int [] arr = {10, 20, 30, 40, 50}; 
        reverse(arr, arr.length);
    }

    private static void reverse(int[] arr,    int length)    {

        for(int i=length;i>0;i--)    { 
            System.out.println(arr[i-1]); 
        }
    }

1

Есть несколько отличных ответов выше, но вот как я это сделал:

public static int[] test(int[] arr) {

    int[] output = arr.clone();
    for (int i = arr.length - 1; i > -1; i--) {
        output[i] = arr[arr.length - i - 1];
    }
    return output;
}

0

ниже приведена полная программа для запуска на вашем компьютере.

public class ReverseArray {
    public static void main(String[] args) {
        int arr[] = new int[] { 10,20,30,50,70 };
        System.out.println("reversing an array:");
        for(int i = 0; i < arr.length / 2; i++){
            int temp = arr[i];
            arr[i] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = temp;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }   
    }
}

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


0

Используя решение XOR, чтобы избежать временной переменной, ваш код должен выглядеть

for(int i = 0; i < validData.length; i++){
    validData[i] = validData[i] ^ validData[validData.length - i - 1];
    validData[validData.length - i - 1] = validData[i] ^ validData[validData.length - i - 1];
    validData[i] = validData[i] ^ validData[validData.length - i - 1];
}

Смотрите эту ссылку для лучшего объяснения:

http://betterexplained.com/articles/swap-two-variables-using-xor/


0
private static int[] reverse(int[] array){
    int[] reversedArray = new int[array.length];
    for(int i = 0; i < array.length; i++){
        reversedArray[i] = array[array.length - i - 1];
    }
    return reversedArray;
} 

4
Пожалуйста, рассмотрите возможность добавления объяснения к вашему ответу. Ответы только на код ничего не объясняют.
— rgettman

0

Вот простая реализация обратного массива любого типа плюс полная / частичная поддержка.

import java.util.logging.Logger;

public final class ArrayReverser {
 private static final Logger LOGGER = Logger.getLogger(ArrayReverser.class.getName());

 private ArrayReverser () {

 }

 public static <T> void reverse(T[] seed) {
    reverse(seed, 0, seed.length);
 }

 public static <T> void reverse(T[] seed, int startIndexInclusive, int endIndexExclusive) {
    if (seed == null || seed.length == 0) {
        LOGGER.warning("Nothing to rotate");
    }
    int start = startIndexInclusive < 0 ? 0 : startIndexInclusive;
    int end = Math.min(seed.length, endIndexExclusive) - 1;
    while (start < end) {
        swap(seed, start, end);
        start++;
        end--;
    }
}

 private static <T> void swap(T[] seed, int start, int end) {
    T temp =  seed[start];
    seed[start] = seed[end];
    seed[end] = temp;
 }  

}

Вот соответствующий юнит тест

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Before;
import org.junit.Test;

public class ArrayReverserTest {
private Integer[] seed;

@Before
public void doBeforeEachTestCase() {
    this.seed = new Integer[]{1,2,3,4,5,6,7,8};
}

@Test
public void wholeArrayReverse() {
    ArrayReverser.<Integer>reverse(seed);
    assertThat(seed[0], is(8));
}

 @Test
 public void partialArrayReverse() {
    ArrayReverser.<Integer>reverse(seed, 1, 5);
    assertThat(seed[1], is(5));
 }
}

0

Вот что я придумала:

// solution 1 - boiler plated 
Integer[] original = {100, 200, 300, 400};
Integer[] reverse = new Integer[original.length];

int lastIdx = original.length -1;
int startIdx = 0;

for (int endIdx = lastIdx; endIdx >= 0; endIdx--, startIdx++)
   reverse[startIdx] = original[endIdx];

System.out.printf("reverse form: %s", Arrays.toString(reverse));

// solution 2 - abstracted 
// convert to list then use Collections static reverse()
List<Integer> l = Arrays.asList(original);
Collections.reverse(l);
System.out.printf("reverse form: %s", l);

0

Есть два способа решения проблемы:

1. Обратный массив в пространстве.

Шаг 1. Поменяйте местами элементы в начале и конце индекса.

Шаг 2. Увеличьте начальный индекс, уменьшите конечный индекс.

Шаг 3. Итерируйте Шаг 1 и Шаг 2, пока начальный индекс <конечный индекс

Для этого сложность времени будет O (n), а сложность пространства будет O (1)

Пример кода для обращения массива в пространстве:

public static int[] reverseAnArrayInSpace(int[] array) {
    int startIndex = 0;
    int endIndex = array.length - 1;
    while(startIndex < endIndex) {
        int temp = array[endIndex];
        array[endIndex] = array[startIndex];
        array[startIndex] = temp;
        startIndex++;
        endIndex--;
    }
    return array;
}

2. Обратный массив, используя вспомогательный массив.

Шаг 1. Создайте новый массив размером, равным данному массиву.

Шаг 2. Вставьте элементы в новый массив, начиная с начального индекса, с данного массива, начиная с конечного индекса.

Для этого сложность времени будет O (n), а сложность пространства будет O (n).

Пример кода для обращения массива со вспомогательным массивом выглядит так:

public static int[] reverseAnArrayWithAuxiliaryArray(int[] array) {
    int[] reversedArray = new int[array.length];
    for(int index = 0; index < array.length; index++) {
        reversedArray[index] = array[array.length - index -1]; 
    }
    return reversedArray;
}

Также мы можем использовать API Коллекций из Java для этого.

API коллекций внутренне использует тот же самый обратный подход в пространстве.

Пример кода для использования Collections API выглядит следующим образом:

public static Integer[] reverseAnArrayWithCollections(Integer[] array) {
    List<Integer> arrayList = Arrays.asList(array);
    Collections.reverse(arrayList);
    return arrayList.toArray(array);
}

0
static int[] reverseArray(int[] a) {
     int ret[] = new int[a.length];
     for(int i=0, j=a.length-1; i<a.length && j>=0; i++, j--)
         ret[i] = a[j];
     return ret;
}

0
 public static int[] reverse(int[] array) {

    int j = array.length-1;
    // swap the values at the left and right indices //////
        for(int i=0; i<=j; i++)
        {
             int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
           j--;
        }

         return array;
    }

      public static void main(String []args){
        int[] data = {1,2,3,4,5,6,7,8,9};
        reverse(data);

    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.