Как изменить массив 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.