具有排列数组的通用合并排序

Posted

技术标签:

【中文标题】具有排列数组的通用合并排序【英文标题】:Generic MergeSort with Permutation Array 【发布时间】:2020-12-02 13:28:56 【问题描述】:

我有通用数组的 MergeSort 代码。唯一的问题是,我希望输出与索引而不是实际的 int、float 或其他。你们对如何做到这一点有任何想法吗? 这是我到目前为止的代码:

class MergeSortGeneric<T extends Comparable<? super T>> 
public static void main(String[] args)
    
    // example using Strings
    String[] arrayOfStrings = "Andree", "Leana", "Faviola", "Loyce", "Quincy", 
 "Milo", "Jamila", "Toccara", "Nelda", "Blair", "Ernestine", "Chara", "Kareen", "Monty", "Rene", 
"Cami", "Winifred", "Tara", "Demetrice", "Azucena";
    MergeSortGeneric<String> stringSorter   = new MergeSortGeneric<>();
    stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);
    System.out.println(java.util.Arrays.toString(arrayOfStrings));

    // example using Doubles
    Double[] arrayOfDoubles = 0.35, 0.02, 0.36, 0.82, 0.27, 0.49, 0.41, 0.17, 0.30, 
0.89, 0.37, 0.66, 0.82, 0.17, 0.20, 0.96, 0.18, 0.25, 0.37, 0.52;
    MergeSortGeneric<Double> doubleSorter   = new MergeSortGeneric<>();
    doubleSorter.mergeSort(arrayOfDoubles, 0, arrayOfDoubles.length - 1);
    System.out.println(java.util.Arrays.toString(arrayOfDoubles));
    

    // main function that sorts array[start..end] using merge()
    void mergeSort(T[] array, int start, int end)
    
    // base case
    if (start < end)
    
       // find the middle point
       int middle = (start + end) / 2;

       mergeSort(array, start, middle); // sort first half
       mergeSort(array, middle + 1, end);  // sort second half

      // merge the sorted halves
      merge(array, start, middle, end);
    
    

    // merges two subarrays of array[].
    void merge(T[] array, int start, int middle, int end)
    
    T[] leftArray  = (T[]) new Comparable[middle - start + 1];
    T[] rightArray = (T[]) new Comparable[end - middle];

    // fill in left array
    for (int i = 0; i < leftArray.length; ++i)
    leftArray[i] = array[start + i];

    // fill in right array
    for (int i = 0; i < rightArray.length; ++i)
    rightArray[i] = array[middle + 1 + i];

    /* Merge the temp arrays */

    // initial indexes of first and second subarrays
    int leftIndex = 0, rightIndex = 0;

    // the index we will start at when adding the subarrays back into the main array
    int currentIndex = start;

    // compare each index of the subarrays adding the lowest value to the currentIndex
    while (leftIndex < leftArray.length && rightIndex < rightArray.length)
    
    if (leftArray[leftIndex].compareTo(rightArray[rightIndex]) <= 0)
    
    array[currentIndex] = leftArray[leftIndex];
    leftIndex++;
    
    else
    
    array[currentIndex] = rightArray[rightIndex];
    rightIndex++;
    
    currentIndex++;
    

    // copy remaining elements of leftArray[] if any
    while (leftIndex < leftArray.length) array[currentIndex++] = leftArray[leftIndex++];

    // copy remaining elements of rightArray[] if any
    while (rightIndex < rightArray.length) array[currentIndex++] = rightArray[rightIndex++];
    

谢谢你们的任何提示。顺便说一句,这就是任务: 实现合并排序算法。该算法对 java.util.list 进行排序 的任何元素。因此该类必须是通用的。对于排序,它得到一个 匹配比较器。

var data = Arrays.asList(23, 42, 11, 1, 12);
var mergeSort = new MergeSort<Integer>();
mergeSort.setup(data, (i1, i2) -> i1 - i2);

但是,输入列表中的元素位置没有改变。相反, 指定排列数组的排序。该数组具有与 输入数据列表有元素。每个 τ 元素指定排序后对应输入元素的索引。同样在内部,您只使用排列数组而不使用 输入元素的更多列表。

【问题讨论】:

【参考方案1】:

不修改合并算法的最简单方法就是:

    创建要排序的数组的副本; 对数组进行排序; 比较副本和排序后的数组,找出索引。

例如:

String[] arrayOfStrings = ...;
List<String> copyArrayOfStrings = Arrays.stream(arrayOfStrings).collect(Collectors.toList());

...
stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);
...

List<Integer> index = Arrays.stream(arrayOfStrings).map(copyArrayOfStrings::indexOf).collect(Collectors.toList());
System.out.println(java.util.Arrays.toString(index.toArray()));

如果出于某种奇怪的原因你只能使用数组和基本运算符,上述逻辑仍然适用:

副本:

 String[] copyArrayOfStrings = new String[arrayOfStrings.length];
    for(int i  = 0; i < arrayOfStrings.length; i++)
       copyArrayOfStrings[i] = arrayOfStrings[i];
     

排序:

    stringSorter.mergeSort(arrayOfStrings, 0, arrayOfStrings.length - 1);

获取索引:

    Integer[] index = new Integer[copyArrayOfStrings.length];
    int index_pos = 0;
    for(String s : arrayOfStrings) 
        for (int i = 0; i < copyArrayOfStrings.length; i++) 
            if(copyArrayOfStrings[i].equals(s))
                index[index_pos++] = i;
                break;
            
        
    

    System.out.println(java.util.Arrays.toString(index));  

【讨论】:

【参考方案2】:

如果索引是整数类型而不是本机整数,则可以使用 lambda 比较。只有索引数组需要是整数类型,值数组可以是原始类型。

package x;
import java.util.Arrays;
public class x 
    public static void main(String[] args) 
        int[] A = 3, 1, 2, 0;
        Integer[] I = 0, 1, 2, 3;
        Arrays.sort(I, (i, j) -> A[i]-A[j]);
        for (Integer i : I) 
            System.out.println(A[i]);
        
    

【讨论】:

【参考方案3】:

你可以像下面这样创建一个类(注意它是伪代码)

import java.util.Arrays;

public class SomeClass 

    public static void main(String[] args) 
        double[] doubleArray = new double[] 2.3, 3.4, 1.2, 0.3, 4.3;
        ObjectWithIndex[] objectWithIndexAr = new ObjectWithIndex[doubleArray.length];
        for (int i = 0; i < doubleArray.length; i++) 
            objectWithIndexAr[i] = new ObjectWithIndex(i, doubleArray[i]);
        

        Arrays.sort(objectWithIndexAr);

        for ( ObjectWithIndex obj : objectWithIndexAr) 
            System.out.println("index: " + obj.index + " value: " + obj.actualObject);
        
    


class ObjectWithIndex implements Comparable<ObjectWithIndex> 
    int index;
    Comparable actualObject;

    public ObjectWithIndex(int index, Comparable object) 
        this.index = index;
        this.actualObject = object;
    

    @Override
    public int compareTo(ObjectWithIndex o) 
        return this.actualObject.compareTo(o.actualObject);
    

您可以使用输入的 Double、Integer 数组(无论实现 Comparable)创建此对象的数组,并对新的 ObjectWithIndex 数组进行排序。

排序后,您可以打印索引(将具有您输入的原始索引)

【讨论】:

以上是关于具有排列数组的通用合并排序的主要内容,如果未能解决你的问题,请参考以下文章

合并 K 个排序数组/向量的复杂性

自底向上的合并排序算法

lintcode_64.合并排序数组 II

排序算法 -归并排序

剑指 Offer II 078. 合并排序链表

归并排序