Як повернути масив 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
Я бачу, що я зробив не так. Повинна бути дійсною.для довжини / 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частину на зовнішню сторону петлі for.
Джин Квон

7
@ Джин я б не став. Це лише обтяжує значення, і я сподіваюся, що оптимізуючий компілятор все-таки зробить це для вас. Незалежно від того, що немає сенсу мікрооптимізувати, поки ви не отримаєте чітких доказів з профілювання, що це необхідно / корисно.
Nicu Stiurca

9
@JinKwon Це було б так, як робити validData.length >> 1 . Це рівноцінно і швидше, але це бентежить багатьох програмістів і будь-який хороший компілятор автоматично це зробить.
Джастін

2
Ви повинні зробити цей розрахунок лише один раз validData.length - i - 1і зберегти його до змінної.

Чи може хто-небудь запропонувати змінити з тимчасовою змінною !!
sg28

303

З Commons.Lang ви можете просто користуватися

ArrayUtils.reverse(int[] array)

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


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

2
@ laurent-g, щоб бути справедливим: повернути масив таким чином є більш ефективним у пам’яті, тому, ймовірно, вони зробили це так.
Sirmyself

4
Моя думка була не копія чи не копія. У моєму повідомленні зазначено, що "(передано)" повернути (після його перегляду), щоб воно могло бути передано у виразі, не потребуючи окремого твердження.
Лоран G

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і в цьому випадку) і ставляться до списку. Розумієте, Integers - це об'єкти. @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
@Andrea Насправді це не так. Список, повернутий Arrays.asList()не посилається на початковий масив, а також на масив, що повертається. Ось одна з проблем цього методу: він використовує потрійну пам'ять і робить потрійну роботу як місцевий алгоритм.
Брайан Маккотчон

4
Цей метод сам по собі може працювати, але він просто не може передати int[]аргумент цього методу ( "несумісні типи: int [] не може бути перетворений в Object []" ).
MC імператор

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

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

Вартість - це лише створення одного об'єкта List, і додаткові бібліотеки не потрібні.

Аналогічне рішення було подано у відповіді Таріка та їхніх коментаторів, але я думаю, що ця відповідь була б більш стислою та легшою для аналізу.


15
Для масивів об’єктів це хороше рішення. Але це не працює для масивів примітивів. E. g. передача int[]до asList(...)"не" поверне a List<Integer>, але a List<int[]>, що містить один елемент. AFAICS не існує простого вбудованого способу перетворення int[]в Integer[].
Мартін Іржа

4
Ця робота не працює з примітивними масивами ... колекції dosnt повертають значення, тому тепер у вас є марний масив як список в пам'яті
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;
    }
}

Я також думаю, що це зручніше робити це за певний час.

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 (дані, зліва, справа).
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 і встановити кожен елемент. Але я згоден з вами, що це геніальне рішення.
Патрік Паркер

Дійсно, про це варто пам’ятати. Я не думаю, що це було б великою справою в більшості кодів, з якими я особисто працюю - наші "гарячі" області чітко визначені, решта - "клей-код" сортів. В той же час я певен, що зменшення пам’яті також створює додаткову «приховану» вартість, яку профілі не відносять до фактичної функції.
Люк Ушервуд

@LukeUsherwood він все-таки повертає список в коробках замість
простого

2
@AnthonyJClink Не впевнений, на що йдеться "він", але утиліта JDK Collections.reverse- це недійсний метод. Це функціонує на місці внутрішнього класу Guava, який завершує int[](Так як він ніколи не зберігає список ящиків Integer, я б не назвав клас "списком у коробці", а "Переглядом списку масиву"). Але так, він працює через інтерфейс, що передає Integerоб'єкти, так що це створило б багато тимчасових збитків та боксу, як згадувалося. Спробуйте IntStreamабо бібліотеку примітивної колекції, де важлива продуктивність. (Колекції Trove, Koloboke, Eclipse, ...)
Лука Ушервуд

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
Надалі повідомте запитувача конкретно, що вони зробили неправильно та що ви зробили правильно.
Kartik Chugh

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

Перетворення масиву примітивів невідомої довжини в масив може бути дуже поганою ідеєю, особливо якщо це зроблено без усвідомлення цього. Java не є 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
Можливо, ви мали на увазі своп як псевдокод для вбудованої заміни, а не виклику методу, але якщо ні, це не спрацює. Java проходить за посиланням, тому неможливо написати метод swap для змінних.
Дін Повей

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

1
Дін, масив validData є об'єктом, переданим посиланням, тому метод swap () буде працювати бездоганно.
Gaël Oberson

3

Якщо ви працюєте з більш примітивними даними (наприклад, char, байт, 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
Занадто мило, щоб насправді використовувати у виробничому коді, але при цьому весело. Для максимальної милості використовуйте операцію% = так: array [i]% = array [len - i - 1] тощо.
Melinda Green

Схожий, але трохи коротший:for (int m = x.length, i = --m / 2; ++i <= m;) { x[i] ^= x[m - i]; x[i] ^= x[m - i] ^= x[i]; }
Томас Мюллер

2

Найефективніше просто повторити масив назад.

Я не впевнений, чи вирішує рішення Аарона цей виклик. Collections.reverse(list);Хтось знає?


Ітерація назад через масив вимагає нового масиву. Мені подобається рішення, розміщене вище, що робить вбудовану реверсування без створення нового масиву.
mmcdole

1
@Simucal навіщо створювати новий масив? Просто повторіть її назад.
Трежказ

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}; для (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. Використовуючи для циклу та поміняйте місцями елементи до середини з часовою складністю 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, щоб уникнути змінної temp, який повинен виглядати ваш код

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 Collections від 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.