Sắp xếp số trong một mảng mà không thay đổi vị trí số chẵn bằng Java-8


8

Tôi đang học luồng Java 8. Hãy cho tôi biết, làm thế nào tôi có thể viết một sortArrayphương pháp gọn hơn?

import org.junit.Test;    
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertArrayEquals;

public class TestStream {

    /*
     * Sort numbers in an array without changing even numbers position
     */

    @Test
    public void test_1() {
        int[] nonSorted = new int[]{3, 4, 5, 2, 1, 6, 9, 8, 7, 0};
        int[] expected = new int[]{1, 4, 3, 2, 5, 6, 7, 8, 9, 0};

        Integer[] arr = sortArray(nonSorted);
        int[] sorted = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            sorted[i] = arr[i];
        }

        assertArrayEquals(expected, sorted);
    }

    private Integer[] sortArray(int[] array) {
        Map<Integer, Integer> even = extractEven(array);
        Integer[] withoutEvens = removeEven(array);
        int length = even.size() + withoutEvens.length;
        Integer[] result = new Integer[length];
        Arrays.sort(withoutEvens);
        for (int i = 0; i < withoutEvens.length; i++) {
            result[i] = withoutEvens[i];
        }
        even.forEach((k, v) -> {
            System.arraycopy(result, k, result, k + 1, length - k - 1);
            result[k] = v;
        });

        return result;
    }


    private Map<Integer, Integer> extractEven(int[] array) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < array.length; i++) {
            if (array[i] % 2 == 0) {
                map.put(i, array[i]);
            }
        }

        return map;
    }

    private Integer[] removeEven(int[] array) {
        ArrayList<Integer> list = new ArrayList<Integer>();

        for (int i = 0; i < array.length; i++) {
            if (array[i] % 2 != 0) {
                list.add(array[i]);
            }
        }

        Integer[] a = new Integer[list.size()];
        return list.toArray(a);
    }
}

Câu trả lời:


8

Người ta có thể nghĩ ra một giải pháp như: Đầu tiên chúng tôi trích xuất các số nguyên lẻ từ nonSorted[]và đưa chúng vào một cách stacksắp xếp.

Tại sao chúng ta nên sử dụng stackmột cách sắp xếp ??

Mảng cuối cùng cần được sắp xếp theo Integerscơ sở lẻ , ngăn xếp tuân theo chính sách FIFO (First in Last Out).

Bây giờ chúng tôi lấy một Instreamvà chạy nó từ 0đến nonSorted.length-1và kiểm tra bản gốc nonSortedcho số lẻ Integer; ngay khi chúng tôi tìm thấy một cái, chúng tôi thay thế nó bằng phần tử đầu tiên của ngăn xếp và pop()phần tử từ stack.

Lưu ý: Người ta cần chơi xung quanh ngăn xếp vì không phải lúc nào bạn cũng cần các phần tử được sắp xếp trong ngăn xếp, nhưng trong trường hợp của OP thì điều này xảy ra.

int[] nonSorted = new int[]{3, 4, 5, 2, 1, 6, 9, 8, 7, 0};

LinkedList<Integer> stack = Arrays.stream(nonSorted)
            .sorted().filter(s -> s % 2 != 0).boxed()
            .collect(Collectors.toCollection(LinkedList::new));

int[] expected = IntStream.rangeClosed(0, nonSorted.length - 1)
       .map(s -> nonSorted[s] % 2 != 0 ? stack.pop():nonSorted[s]) 
       .toArray();

2
Có vẻ tốt hơn nhiều so với tôi có thể đến. +1
Naman

1
Ồ thật là kinh ngạc! stack rất thú vị, tôi nghĩ vậy
Dmitry Shelemeh

2

Tôi thực sự thích ý tưởng sử dụng sắp xếp Stack , nhưng nó không dễ dàng song song và khiến tôi tò mò làm thế nào để giải quyết nó.

Ý tưởng của tôi là sắp xếp các chỉ số của các phần tử không đồng đều và tùy thuộc vào vị trí của chỉ mục mà chúng ta có thể phân biệt trong quá trình tạo mảng kết quả nếu một số chẵn hay không.

public int[] sortUnevenElements(int[] nonSorted) {
    int[] unevenIndices = IntStream.range(0, nonSorted.length).filter(i -> nonSorted[i] % 2 != 0).toArray();
    int[] sortedUnevenIndices = Arrays.stream(unevenIndices, 0, unevenIndices.length).boxed()
          .sorted(Comparator.comparingInt(i -> nonSorted[i])).mapToInt(Integer::intValue).toArray();
    return IntStream.range(0, nonSorted.length).map(i -> {
        int idx = Arrays.binarySearch(unevenIndices, i);
        return idx >= 0 ? nonSorted[sortedUnevenIndices[idx]] : nonSorted[i];
    }).toArray();
}

1

Tôi tin rằng ý của bạn là Java-8 đang sử dụng Streams và các API khác được giới thiệu kể từ phiên bản đó. Bạn đã có một mã hoạt động rất tốt theo ý kiến ​​của tôi mặc dù. Cách tôi có thể nghĩ về việc phá vỡ vấn đề như sau -

  1. Tìm các số lẻ và chẵn và ánh xạ của chúng tới các chỉ mục hiện tại. Như vậy, ngay cả các giá trị với chỉ mục của họ sẽ vẫn cố định.

  2. Theo các số lẻ và chỉ mục của chúng, sắp xếp lại các giá trị sắp xếp chúng một cách tự nhiên.

  3. Khi tất cả điều này được thực hiện, hợp nhất các bản đồ chẵn lẻ này dựa trên các chỉ mục.

  4. Lấy các giá trị từ kết quả hợp nhất này.

Nhìn chung việc thực hiện này sẽ trông giống như -

private Integer[] sortArrayStream(Integer[] array) {
    Map<Boolean, Map<Integer, Integer>> evenOdds = IntStream.range(0, array.length)
            .boxed()
            .collect(Collectors.partitioningBy(i -> array[i] % 2 == 0,
                    Collectors.toMap(o -> o, i -> array[i]))); //1

    Map<Integer, Integer> oddSorted = remapWithSorting(evenOdds.get(Boolean.FALSE)); // 2

    Map<Integer, Integer> overall = new HashMap<>(evenOdds.get(Boolean.TRUE));
    overall.putAll(oddSorted); // part of 3

    return overall.entrySet().stream()
            .sorted(Map.Entry.comparingByKey()) // remaining of 3
            .map(Map.Entry::getValue) // 4
            .toArray(Integer[]::new); 
}


private Map<Integer, Integer> remapWithSorting(Map<Integer, Integer> initialIndexMapping) {
    List<Integer> oddIndexes = new ArrayList<>(initialIndexMapping.keySet());
    List<Integer> sortedOdds = initialIndexMapping.values().stream()
            .sorted().collect(Collectors.toList());
    return IntStream.range(0, sortedOdds.size())
            .boxed()
            .collect(Collectors.toMap(oddIndexes::get, sortedOdds::get));
}

0

Đây là một thử nghiệm sắp xếp chèn với các luồng. Các nonSortedmảng được truyền phát và thu thập đến a new int[]. Nếu giá trị từ nonSortedmảng là chẵn thì nó chỉ được sao chép, nếu không, đó là số lẻ, một loại sắp xếp chèn được chạy chỉ cho các giá trị lẻ đã có trong kết quả.

int[] sort = IntStream.range(0, nonSorted.length)
            .collect(() -> new int[nonSorted.length], (ints, i) -> {
                ints[i] = nonSorted[i];
                if (nonSorted[i] % 2 != 0) {
                    AtomicInteger current = new AtomicInteger(i);
                    IntStream.iterate(i - 1, 
                                     (v) -> current.get() > 0 && v >= 0,
                                     (v) -> --v)
                            .forEach(ind -> {
                                if (ints[ind] % 2 != 0) {
                                    if (ints[ind] > nonSorted[i]) {
                                        ints[current.get()] = ints[ind];
                                        ints[ind] = nonSorted[i];
                                        current.set(ind);
                                    } else {
                                        current.set(-1);
                                    }
                                }
                            });
                }
            }, (a1, a2) -> {
            });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.