Hi,
Wouldn't it better to use boolean flag instead of int index?
--
Dmytro Sheyko
PS
--- DualPivotQuicksortWithoutSentinel.java Fri May 07 10:40:14 2010
+++ DualPivotQuicksortWithoutSentinelA.java Fri May 07 11:54:51 2010
@@ -39,7 +39,7 @@
* @version 2010.04.30 m765.827.12i:5\7
* @since 1.7
*/
-final class DualPivotQuicksortWithoutSentinel {
+final class DualPivotQuicksortWithoutSentinelA {
/**
* Prevents instantiation.
@@ -78,7 +78,7 @@
* @param a the array to be sorted
*/
public static void sort(int[] a) {
- dualPivotQuicksort(a, 0, a.length - 1, 0);
+ dualPivotQuicksort(a, 0, a.length - 1, true);
}
/**
@@ -96,7 +96,7 @@
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- dualPivotQuicksort(a, fromIndex, toIndex - 1, fromIndex);
+ dualPivotQuicksort(a, fromIndex, toIndex - 1, true);
}
/**
@@ -108,12 +108,12 @@
* @param right the index of the last element, inclusive, to be sorted
* @param fromIndex the first index of the original range to be sorted
*/
- private static void dualPivotQuicksort(int[] a, int left, int
right, int fromIndex) {
+ private static void dualPivotQuicksort(int[] a, int left, int
right, boolean leftmost) {
int length = right - left + 1;
// Use insertion sort on tiny arrays
if (length < INSERTION_SORT_THRESHOLD) {
- if (left > fromIndex) {
+ if (!leftmost) {
/*
* TODO
*/
@@ -129,11 +129,11 @@
* For case, when left == fromIndex, traditional (without
* sentinel) insertion sort, optimized for server VM,
is used.
*/
- for (int i = fromIndex, j = i; i < right; j = ++i) {
+ for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
- if (j-- == fromIndex) {
+ if (j-- == left) {
break;
}
}
@@ -237,8 +237,8 @@
a[right] = a[great + 1]; a[great + 1] = pivot2;
// Sort left and right parts recursively, excluding known
pivots
- dualPivotQuicksort(a, left, less - 2, fromIndex);
- dualPivotQuicksort(a, great + 2, right, fromIndex);
+ dualPivotQuicksort(a, left, less - 2, leftmost);
+ dualPivotQuicksort(a, great + 2, right, false);
/*
* If center part is too large (comprises > 5/7 of the array),
@@ -295,7 +295,7 @@
}
// Sort center part recursively
- dualPivotQuicksort(a, less, great, fromIndex);
+ dualPivotQuicksort(a, less, great, false);
} else { // Pivots are equal
/*
@@ -350,8 +350,8 @@
}
// Sort left and right parts recursively
- dualPivotQuicksort(a, left, less - 1, fromIndex);
- dualPivotQuicksort(a, great + 1, right, fromIndex);
+ dualPivotQuicksort(a, left, less - 1, leftmost);
+ dualPivotQuicksort(a, great + 1, right, false);
}
}
> From: iaroslav...@mail.ru
> To: j...@google.com; dmytro_she...@hotmail.com
> CC: core-libs-dev@openjdk.java.net; iaroslav...@mail.ru
> Subject: Re[2]: New portion of improvements for Dual-Pivot Quicksort
> Date: Fri, 7 May 2010 00:46:59 +0400
>
> Hello Josh, Dmytro,
>
> I've modified the DQP and now it doesn't touch elements outside of
> the range and doesn't set a sentinel at all. Elements from the left
> part are used as a sentinel (as it was suggested by Dmytro) and index
> fromIndex is used as left boundary (suggestion from Josh). The index
> fromIndex is the initial left boundary and passed down through the
> recursions. No any tricks with changing outside of the range and
> negative infinity.
>
> The fragment of code is (full version see in attachment):
>
> * ...
> * @param fromIndex the first index of the original range to be sorted
> */
> private static void dualPivotQuicksort(int[] a, int left, int right,
int fromIndex) {
> int length = right - left + 1;
>
> // Use insertion sort on tiny arrays
> if (length < INSERTION_SORT_THRESHOLD) {
> if (left > fromIndex) {
> /*
> * TODO
> */
> for (int j, i = left + 1; i <= right; i++) {
> int ai = a[i];
> for (j = i - 1; /* j >= left && */ ai < a[j]; j--) {
> a[j + 1] = a[j];
> }
> a[j + 1] = ai;
> }
> } else {
> /*
> * For case, when left == fromIndex, traditional (without
> * sentinel) insertion sort, optimized for server VM, is used.
> */
> for (int i = fromIndex, j = i; i < right; j = ++i) {
> int ai = a[i + 1];
> while (ai < a[j]) {
> a[j + 1] = a[j];
> if (j-- == fromIndex) {
> break;
> }
> }
> a[j + 1] = ai;
> }
> }
> return;
> }
> ...
>
> This variant is little bit faster (~0.5%) on client VM and slower (~2%)
> on server VM than original variant. I think that it is not too bad.
> What do you think?
>
> And one question: the method declaration
>
> private static void dualPivotQuicksort(int[] a, int left, int right,
int fromIndex) {
>
> now is too long, how should I format it? What is the guideline?
>
> Thank you,
> Vladimir
>
> Wed, 5 May 2010 18:21:18 -0400 письмо от Joshua Bloch <j...@google.com>:
>
> > Vladimir,
> >
> > On Wed, May 5, 2010 at 12:57 AM, Joshua Bloch <j...@google.com> wrote:
> >
> > The sentinel technique that you use in lines 118 - 136 is
questionable: you are modifying a portion of the array outside the
specified range of the call, which arguably violates the contract of the
call, and could be observed in a multithreaded program. It's not beyond
the realm of reason that it could break existing clients. I will discuss
it with Doug Lea and let you know what he says.
> >
> > I talked to Doug, and he agrees that it's not acceptable to modify
any location outside the array range that the caller has asked you to
sort. This doesn't entirely kill the optimization; it's still OK to use
on subranges that don't include the first element of the range that you
were asked to sort. In other words, this test
> >
> > 120 if (left > 0) {
> >
> > Should be replaced by:
> >
> > 120 if (left > fromIndex + 1) {
> >
> > and you have to pass original fromIndex down to the recursive calls
(in fact, you could pass fromIndex +1 to avoid the cost of the addition
in each test). It's not clear whether the cost of passing this index
down through the recursive calls will eliminate the gains of the
optimization, but it's worth performing the experiment.
> >
> > Sorry,
> > Josh