具有重复值的QuickSort

时间:2016-02-13 23:05:58

标签: java quicksort

我已经实现了以下代码,但它似乎不适用于我的数组具有重复值的情况。

 private int partition(Integer[] arr,int left, int right)
 {
    int i = left;
    int j = right;
    int pivot = arr[left];

    while(true) 
    {
        while(arr[i] <pivot) i++;
        while(arr[j] > pivot) j--;

        if(i < j)
        {
            print(arr);
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        else return j; 
    }
}


public void quickSort(Integer[] arr, int left,int right)
{
    print(arr);
    if(left >= right) return;

    int index = partition(arr,left,right);

    quickSort(arr,left,index-1);
    quickSort(arr,index+1,right);
}

在这种情况下,我发现了一个稍微不同的实现,但我不明白为什么。任何帮助将不胜感激。

    private int partition(Integer[] arr, int left, int right)
    {
    int i = left-1;
    int j = right+1;
    int pivot = arr[left];


    while(true) 
    {

        while(arr[++i] < pivot) ;
        while(arr[--j] > pivot) ;

        if(i < j)
        {
            print(arr);
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        else return j; 
     }
     }

    public void quickSort(Integer[] arr, int left,int right)
    {
    print(arr);
    if(left >= right) return;

    int index = partition(arr,left,right);

    quickSort(arr,left,index);
    quickSort(arr,index+1,right);
    }

2 个答案:

答案 0 :(得分:1)

1.拾取一个元素作为支点

2.将小于枢轴的所有元素移动到左侧,并将所有元素移动到大于右侧的枢轴

3.在两个部分上应用上述步骤

以下方法实现快速排序。它定义了一个递归方法来对子数组进行排序,还定义了一个将数组分成两部分的方法。

public static void quickSort(int[] data, int first, int last)
      {
        if (first >= last)return;
        int pivot = partition(data, first, last);
        quickSort(data, first, pivot - 1); // sort the left part
        quickSort(data, pivot + 1, last); // sort the right part
      }

分区过程涉及拾取枢轴并围绕枢轴移动元素。一个简单的程序如下:

1,分配一个包含分区结果的新临时数组

2.拾取第一个元素作为支点

3.从第二个元素扫描数组,将每个元素与pivot进行比较,如果它小于或等于pivot,则将其放在临时数组的左端,否则将其放在右端。

4.最后将结果从临时数组复制回原始数组

public static int partition(int[] data, int first, int last)
 {
int[] temp = new int[last - first + 1];
int pivot = data[first];
int i = 0, j = last - first, k;

for (k = first + 1; k <= last; k++)
{
    if (data[k] <= pivot)
        temp[i++] = data[k];
    else
        temp[j--] = data[k];
}
temp[i] = data[first];

// Copy data back into original array
for (k = first; k <= last; k++)
    data[k] = temp[k - first];
return first + i;
  }

上述方法需要额外的存储空间(线性空间)来保存中间结果。以下是分区的就地版本,不需要额外存储:

1.拾取数组中的第一个元素作为数据透视

2.从两端向中间扫描阵列

3.无论何时找到错误的两个元素,交换它们

4.当两端的扫描在中间相遇时,将枢轴与此中间元素交换

public static int partition(int[] data, int first, int last)
 {
int pivot = data[first];
int left = first, right = last;

while (left < right)
{
    // Find an element bigger than the pivot from the left
    while (data[left] <= pivot && left < right)
        left++;
    // Find an element smaller than the pivot from the right
    while (data[right] > pivot)
        right--;
    // Swap the two elements found
    if (left < right)
        swap(data, left, right);
}

// move the pivot element to the middle
swap (data, first, right);
return right; }

1.如果每次选择的轴都是中间元素,那么分区是均匀的,分区的级别是O(log n)

2.如果每次选择的枢轴是最小或最大元素(每次运气不好),则一部分没有元素,另一部分包含除枢轴本身之外的所有元素。这将生成n级分区,这与选择排序基本类似。

3.如果每次随机选择一个轴,那么平均来说,分区将是均匀的,并且分区的水平接近于O(log n)。

希望这可能会让你对Quick Sort有一个正确的想法,花点时间阅读我在片段中提供的所有评论。

答案 1 :(得分:0)

这是你的代码:

    while(arr[i] <pivot) i++;
    while(arr[j] > pivot) j--;

以下是他们的代码中的不同之处:

    while(arr[++i] < pivot) ;
    while(arr[--j] > pivot) ;

注意他们使用预增量/减量运算符++ i和--j。 因此,在检查增量或减量之前,第一次检查将会进行。

相当于:

do{ i++; }while(arr[i] < pivot);
do{ j--; }while(arr[j] > pivot);

点是,你需要在第一次比较之前增加i并减少j。