具有排列数组的通用合并排序
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 数组进行排序。
排序后,您可以打印索引(将具有您输入的原始索引)
【讨论】:
以上是关于具有排列数组的通用合并排序的主要内容,如果未能解决你的问题,请参考以下文章