在Java中使用插入排序实现的非工作QuickSort?

时间:2014-03-06 14:15:24

标签: java sorting quicksort insertion-sort

我尝试编写一个实现 QuickSort Insertion Sort 方法,以便用更小的数组来加速它。

我对InsertionSortQuickSort的方法对数组进行了很好的排序,但是当我开始混合它们时,我会得到一些列表,其中与完全排序的列表相比,某些数字位置被切换。

首先是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方法。

接下来是混合QuicksortInsertionsort的方法,名为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运行没有失败,所以不会出现这样的问题。

一个数组在排序后的样子如下:

  • 19 19
  • 21 21
  • 22 23
  • 23 24
  • 24 24
  • 24 25
  • 25 22
  • 30 30

正确排序的数组位于左侧,而使用MixSort排序的同一数组位于右侧。我不知道如何表示数组,所以这个列表必须要做。请注意,数字22已在稍后的列表中插入。

事先谢谢。

2 个答案:

答案 0 :(得分:0)

正如您所想,我没有阅读您的所有代码,但看到类似

的内容
v[first] >= v[last/2]
您的枢轴选择中的

在我眼中看起来非常腥。最后一个应该是一个范围的结束,你想看看你的排序中的元素v[first..last](此时无耻地使用伪红宝石,但我想你明白了)。如果您获得first=100last=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个或更少,则退出排序。如果这两个元素尚未排序,则会在列表中创建两个未排序元素的随机故障。