繁体   English   中英

更改我的quickSort算法Java中的数据透视

[英]change pivot in my quickSort algorithm java

我使用数组中的第一个元素作为枢轴实现了一个有效的quickSort算法,如下所示:

public int[] quickSort( int[] a, int start, int end){

    int l = start;
    int r = end;

    int pivotIndex = start; //<---- first element in the array as pivot! 

    // must be at least two elements
    if ( end - start >= 1){

        // set pivot
        int pivot = a[pivotIndex];


        while ( r > l ){
            // scan from the left
            while ( a[l] <= pivot && l <= end && r > l  ){
                l++;
            }
            while ( a[r] > pivot && r >= start && r >= l){
                r--;
            }
            if ( r > l ){
                this.swap(a, l, r);
            }
        }
        this.swap(a, pivotIndex, r);

        System.out.println("calling quickSort on " + start + " and " + (r-1));                 
        quickSort(a, pivotIndex, r - 1); // quicksort the left partition
        System.out.println("calling quickSort on " + (r+1) + " and " + end);
        quickSort(a, r + 1, end);   // quicksort the right partition

    } else {
        return a;
    }

    return a;
}    

这样做很好,但是如果我将pivotIndex更改为可以说int pivotIndex = end; 我得到这个结果:

run:
2, 8, 7, 1, 3, 5, 6, 4, 
2, 8, 7, 1, 3, 5, 6, 4, 
swapping l:8 and r:4
2, 4, 7, 1, 3, 5, 6, 8, 
swapping l:7 and r:3
2, 4, 3, 1, 7, 5, 6, 8, 
swapping l:8 and r:1
calling quickSort on 0 and 2
calling quickSort on 4 and 7
2, 4, 3, 8, 7, 5, 6, 1, 
swapping l:7 and r:1
2, 4, 3, 8, 1, 5, 6, 7, 
swapping l:7 and r:1
calling quickSort on 4 and 3
calling quickSort on 5 and 7
2, 4, 3, 8, 7, 5, 6, 1, 
swapping l:5 and r:1
2, 4, 3, 8, 7, 1, 6, 5, 
swapping l:5 and r:1
calling quickSort on 5 and 4
calling quickSort on 6 and 7
2, 4, 3, 8, 7, 5, 6, 1, 
swapping l:6 and r:1
2, 4, 3, 8, 7, 5, 1, 6, 
swapping l:6 and r:1
calling quickSort on 6 and 5
calling quickSort on 7 and 7
2, 4, 3, 8, 7, 5, 6, 1, 
BUILD SUCCESSFUL (total time: 1 second)

我如何使算法与pivotIndex一起用作a.length的任何索引0 to a.length

您可以在开始排序之前简单地将所选的枢轴与数组中的第一个元素交换,这样它将完全像以前一样工作。

int l = start;
int r = end;

this.swap(a, choosePivot(), start); 
int pivotIndex = start; 

如果选择从旋转任意元素开始,则必须更改分区循环的行为。 请参见下面的代码:

/* Selecting the pivot to be a random-ish element
   and pivotIndex to be beginning, since we don't know
   where it will be until we loop through the list */
int pivot = a[someInt];
int pivotIndex = begin-1;
//have to keep track of where the pivot actually is in the list
int currentPivotIndex = someInt;

for(int i = begin; i <= end; i++) {
    if(a[i] <= pivot) {
        //for each element less than the pivot
        //the pivotIndex moves by one
        pivotIndex++;
        //place the element to the left of the pivot
        this.swap(a, pivotIndex, i);
        //update currentPivotIndex if needed
        if(a[pivotIndex] == pivot) {
            currentPivotIndex = pivotIndex;
        }
    }
}
//put the pivot in its place
this.swap(a, pivotIndex, currentPivotIndex);

这是一些奇怪的行为,很可能是由您的枢轴元素参与分区引起的。

输出的第一行表示swapping l:8 and r:4但它应该已经swapping l:8 and r:3 因为4是枢轴元素,它既不属于左侧的分区,也不属于右侧的分区。 它是分区中间的元素。 分区期间必须将其隔离。

要解决此问题,请在选择枢轴后将其移到末尾。 即,第一件事,用数组的最后一个元素替换ivot。 因此,您可以将其与分区过程隔离。 然后,以l = start and r = end - 1开始while循环,因为end当前是枢轴。 不要管它。 完成分区后,将枢轴还原到两个分区的中间。 中间将是lr相遇的地方。

我相信按照上述方法可以解决您的问题。 让我知道是否可以。

没有直接关系,但是您对枢轴元素的选择会对快速排序的性能产生巨大影响。 使用其当前版本,可能会遇到最坏情况( O(n^2) )。 最简单的是,您可以随机选择它,这很可能带来O(nlogn)复杂性。

暂无
暂无

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

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