我尝试编写一个实现 QuickSort
的 Insertion Sort
方法,以便用更小的数组来加速它。
我对InsertionSort
和QuickSort
的方法对数组进行了很好的排序,但是当我开始混合它们时,我会得到一些列表,其中与完全排序的列表相比,某些数字位置被切换。
首先是Quicksort
:
public class qSort implements IntSorter {
public enum Order {
RANDOM, FIRST, LAST, MYPIVOT
}
private final Order order;
private Random random;
public qSort(Order order) {
this.order = order;
random = new Random();
}
public int[] sort(int[] v) {
return qsort(v, 0, v.length - 1);
}
// Sorts the elements of the subvector v[first..last].
protected int[] qsort(int[] v, int first, int last) {
if(first >= last) // Less than two elements
return v;
int p = 0;
// Choose a pivot element.
if(order == Order.FIRST)
p = v[first];
else if(order == Order.LAST)
p = v[last];
else if(order == Order.MYPIVOT) {
//The median of the first, middle and last element will be
//chosen as the median
if((v[first] >= v[(last - first)/2 +first] && v[first] <= v[last])
|| (v[first] <= v[(last - first)/2 +first] && v[first] >= v[last])) {
p = v[first];
}
else if((v[last] >= v[(last - first)/2 +first] && v[last] <= v[first])
|| (v[last] <= v[(last - first)/2 +first] && v[last] >= v[first])) {
p = v[last];
}
else if((v[(last - first)/2 +first] >= v[last] && v[(last - first)/2 +first] <= v[first])
|| (v[(last - first)/2 +first] <= v[last] && v[(last - first)/2 + first]>= v[first])) {
p = v[last/2];
}
}
else if(order == Order.RANDOM) {
int r = random.nextInt(last - first) + first;
p = v[r];
}
int[] lowHigh = partition(v, first, last, p);
qsort(v, first, lowHigh[0]-1);
qsort(v, lowHigh[1]+1, last);
return v;
}
/**
* Reorders the elements of the subarray v[first..last] so that
* all elements in v[first..low-1] are less than pivot,
* all elements in v[low..high] are equal to pivot,
* all elements in v[high+1..last] are greater than pivot.
*
* Precondition: first < last.
*/
protected int[] partition(int[] v, int first, int last, int pivot) {
int low = first;
int mid = first;
int high = last;
while (mid <= high) {
int a = v[mid];
if (a < pivot) {
v[mid] = v[low];
v[low] = a;
low++;
mid++;
}
else if (a == pivot) {
mid++;
}
else { // a > pivot
v[mid] = v[high];
v[high] = a;
high--;
}
}
int[]returnArray = new int[2];
returnArray[0] = low;
returnArray[1] = high;
return returnArray;
}
请注意,这两个实现InSorter
,一个接口,以便以后更容易测试它们。它只包含sort方法。
接下来是混合Quicksort
和Insertionsort
的方法,名为MixSort:
public class mixSort extends qSort {
private InsertionSort isort;
//Enum inheritet from qSort allows orders RANDOM, FIRST, LAST
private Order order;
//Arraysize for when to change to insertionsort
private int k;
private Random random;
public mixSort(int k, Order order)
{
isort = new InsertionSort();
this.order = order;
this.k = k;
random = new Random();
}
/**
* Sorts the array in ascending order through Quicksort implementing Insertionsort
* @param v array to be sorted
* @param first beginning of array
* @param last last index of array
* @return sorted array
*/
@Override
public int[] qsort(int[] v, int first, int last)
{
if (first >= last - 1) // Less than two elements
return v;
int p = 0;
// Choose a pivot element.
if(order == Order.FIRST)
p = v[first];
else if(order == Order.LAST)
p = v[last];
else if(order == Order.MYPIVOT)
{
//The median of the first, middle and last element will be
//chosen as the median
if((v[first] >= v[(last - first)/2 +first] && v[first] <= v[last])
|| (v[first] <= v[(last - first)/2 + first] && v[first] >= v[last]))
{
p = v[first];
}
else if((v[last] >= v[(last - first)/2 +first] && v[last] <= v[first])
|| (v[last] <= v[(last - first)/2 + first] && v[last] >= v[first]))
{
p = v[last];
}
else if((v[(last - first)/2 + first] >= v[last] && v[(last - first)/2 + first]<= v[first])
|| (v[(last - first)/2 + first] <= v[last] && v[(last - first)/2 +first] >= v[first]))
{
p = v[last/2];
}
}
else if(order == Order.RANDOM)
{
int r = random.nextInt(last - first) + first;
p = v[r];
}
if(last - first <= k)
{
this.isort(v, first, last);
}
else
{
// Partition the elements so that every number of
// v[first..mid] <= p and every number of v[mid+1..last] > p.
int[] lowHigh = partition(v, first, last, p);
this.qsort(v, first, lowHigh[0]-1);
this.qsort(v, lowHigh[1]+1, last);
}
return v;
}
/**
* A method that utilizes Insertion sort to sort given array of ints.
*
* @param a the array to be sorted
* @param first the starting index of the array
* @param last the last index to be sorted in the array
* @return the sorted array produced by sort()
*/
public int[] isort(int[] a, int first, int last)
{
if(a.length <= 1) //Array contains less then 2 elements
return a;
int save = 0;
for (int i = first + 1; i < last; i++)
{
save = a[i];
int j = 0;
for (j = i -1; j >= first && save < a[j]; j--)
{
a[j + 1] = a[j];
}
a[j + 1] = save;
}
return a;
}
请注意,mixSort扩展了Quicksort。
我无法弄清楚为什么我自己的MixSort不起作用,尽管我在排序列表中看到的错误暗示了Pivotpoint的问题。虽然由于该代码与Quicksort共享,但由于Quicksort运行没有失败,所以不会出现这样的问题。
一个数组在排序后的样子如下:
正确排序的数组位于左侧,而使用MixSort排序的同一数组位于右侧。我不知道如何表示数组,所以这个列表必须要做。请注意,数字22已在稍后的列表中插入。
事先谢谢。
答案 0 :(得分:0)
正如您所想,我没有阅读您的所有代码,但看到类似
的内容v[first] >= v[last/2]
您的枢轴选择中的在我眼中看起来非常腥。最后一个应该是一个范围的结束,你想看看你的排序中的元素v[first..last]
(此时无耻地使用伪红宝石,但我想你明白了)。如果您获得first=100
和last=150
,则会查看元素v[75]
,该元素不属于此时要排序的元素。
没有完全检查你的代码(并没有一个例子以及它是如何出错的(提示,提示......))很难确认这是真正的问题,但你可能会尝试一下。 / p>
答案 1 :(得分:0)
代码中有两个错误,一个是如何在不同的排序算法之间传递参数,另一个是野生-1
从第一个开始: Quicksort
方法使用
public int[] sort(int[] v) {
return qsort(v, 0, v.length - 1);
}
要开始排序, Insertionsort
部分将使用
public int[] sort(int[] v) {
return isort(v, 0, v.length);
}
因为-1是在方法的代码中处理的。这意味着当参数传递时,它应该以+1传递。否则将始终有1个未排序的元素,这是我们在示例中看到的。另一个错误是:
if (first >= last - 1) // Less than two elements
return v;
其中-1如果少于2个元素但不是2个或更少,则退出排序。如果这两个元素尚未排序,则会在列表中创建两个未排序元素的随机故障。