简体   繁体   English

具有重复值的QuickSort

[英]QuickSort with duplicates values

I have implemented the following code, but it does not seem to work for the case that my array has duplicate values. 我已经实现了以下代码,但是对于我的数组具有重复值的情况,它似乎不起作用。

 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);
}

I found a slightly different implementation that works pretty well in this case, but I don't understand why. 我发现有一个稍微不同的实现,在这种情况下效果很好,但是我不明白为什么。 Any help would be appreciated. 任何帮助,将不胜感激。

    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);
    }

1.Pick up one element as the pivot 1,选择一个元素作为枢轴

2.Move all elements less than the pivot to the left, and all elements greater than the pivot to the right 2.将所有小于枢轴的元素移至左侧,将所有大于枢轴的元素移至右侧

3.Apply the above steps on both parts 3.将以上步骤同时应用于两个部分

The following method implements quick sort. 以下方法实现了快速排序。 It defines a recursive method to sort subarrays, and also defines a method to partition an array into two parts. 它定义了对子数组进行排序的递归方法,还定义了将数组划分为两部分的方法。

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
      }

The partitioning process involves picking up the pivot and move elements around the pivot. 分区过程包括拾取枢轴并围绕枢轴移动元素。 A simple procedure is as below: 一个简单的过程如下:

1,Allocate a new temporary array holding the partitioned result 1,分配一个新的保存分区结果的临时数组

2.Pick up the first element as the pivot 2.拾取第一个元素作为枢轴

3.Scan the array from the second element, compare each element with the pivot, and put it to the left end of the temporary array if it is less than or equal to the pivot, otherwise put it to the right end. 3.从第二个元素扫描数组,将每个元素与支点进行比较,如果它小于或等于支点,则将其放在临时数组的左端,否则将其放在右端。

4.Finally copy back the result from the temporary array to the original array 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;
  }

The method above requires extra storage (linear space) holding the intermediate result. 上面的方法需要额外的存储(线性空间)来保存中间结果。 The following is an in-place version of the partitioning which does not require addtional storage: 以下是该分区的就地版本,不需要附加存储:

1.Pick up the first element in the array as the pivot 1.拾取数组中的第一个元素作为枢轴

2.Scan the array from both ends toward the middle 2.从两端向中间扫描阵列

3.Whenever finding two elements on the wrong side, swap them 3,每当发现错误的两个元素时,将它们交换

4.When the scans from both ends meet in the middle, swap the pivot with this middle element 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.If the pivot chosen at each time is the median element, then the partitioning is even, and the level of partitioning is O(log n) 1,如果每次选择的枢轴是中位数元素,则划分为偶数,划分级别为O(log n)

2.If the pivot chosen at each time is either the smallest or the largest element (bad luck every time), then one part has no element and the other part holds all elements except the pivot itself. 2.如果每次选择的枢轴都是最小或最大元素(每次运气不好),则一个部分没有元素,而另一部分则包含除枢轴本身以外的所有元素。 This will generate n levels of partitioning, which is essentially similar to selection sort. 这将生成n个分区级别,这基本上类似于选择排序。

3.If the pivot chosen randomly each time, then on average, the partitioning will be even, and the level of partitioning is close to O(log n). 3.如果每次随机选择枢轴,则平均而言,分区将是均匀的,并且分区级别接近O(log n)。

Hopes this may bring you right idea about Quick Sort take some time to read all I provided comments in snippets too. 希望这可以为您带来有关“快速排序”的正确想法,还需要一些时间来阅读我在摘要中提供的所有注释。

Here is your code: 这是您的代码:

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

Here is what is different in their code: 这是他们的代码的不同之处:

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

Notice they use the pre-increment/decrement operators ++i and --j. 请注意,它们使用了预增/减运算符++ i和--j。 So, the first check in the while will in advance of the check increment or decrement. 因此,while中的第一个检查将在检查增加或减少之前进行。

which is equivalent to having: 这等效于:

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

Point is, you need to increment i and decrement j BEFORE your first comparisons. 关键是,您需要在第一次比较之前将i递增和j递减。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM