我观看了这种快速排序算法的精彩可视化:http://www.youtube.com/watch?v=Z5nSXTnD1I4
我觉得我真的理解快速排序背后的原则,并且在一些在线指南的帮助下,着手创建我自己的快速排序。
这就是我想出的:
public void quickSort(int[] a, int left, int right) {
int index = partition(a, left, right);
if (left < index - 1)
quickSort(a, left, index);
if (index < right)
quickSort(a, index + 1, right);
}
private int partition (int[] a, int left, int right) {
int i = left - 1;
int j = right + 1;
int pivot = a[0];
while (i < j) {
i++;
while (a[i] < pivot)
i++;
j--;
while (a[j] > pivot)
j--;
if (i < j)
swap (a, i, j);
}
return i;
}
private void swap (int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
左和右的值如下:
left = 0
right = array size - 1
不幸的是输出不正确。问题似乎在于我对枢轴的处理。在我观察的可视化中,教师物理地移除了枢轴并使指针指向任何东西。他继续学习教程,当他到达我和j(我称之为左右)两者都指向同一个空位时,他插入了枢轴并继续进行。
由于我在物理上保持枢轴,我发现很难对其进行适当的分类。
在此代码中,我正在使用输入:
4 8 1 6 3 7 2 5
我得到了输出:
1 3 2 6 8 7 4 5
一旦在算法的最开始对“4”值(即枢轴)进行排序,我就不会使用它,这会抛弃一切。另外,我认为quickSort方法有问题。
有人可以给我一些指示吗?感谢。
编辑:此处的两次修改已被删除,因为它们包含不必要且不正确的信息。其中一人将支点改为:(左+右)/ 2.由于以下答案中解释的原因,这当然是错误的。
答案 0 :(得分:4)
我不得不摆脱分区,因为你需要i
和j
。它应该是这样的:
public void quickSort(int[] a, int left, int right) {
int i = left; // Was -1
int j = right; // Was +1
int pivot = a[left + (right - left) / 2]; // Pivot is the value of the middle index, not the index itself
while (i <= j) { // Changed terminating condition
// i++; Not needed
while (a[i] < pivot) {
i++;
}
// j++; Not needed
while (a[j] > pivot) {
j--;
}
if (i <= j) { // Changed terminating condition
swap(a, i, j);
i++; // You need to progress the indexes after the swap
j--;
}
}
System.out.println(Arrays.toString(a));
if (left < j) { // Changed condition
quickSort(a, left, j);
}
if (i < right) {
quickSort(a, i, right); // was i + 1
}
}
输出:
[4, 5, 1, 2, 3, 7, 6, 8]
[1, 5, 4, 2, 3, 7, 6, 8]
[1, 3, 2, 4, 5, 7, 6, 8]
[1, 2, 3, 4, 5, 7, 6, 8]
[1, 2, 3, 4, 5, 7, 6, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8]
答案 1 :(得分:2)
int partition(final int[] a, final int left, final int right) {
// set the last element as pivot
final int pivot = a[right];
int i = left - 1, j = left;
for (; j < right; j++)
if (a[j] < pivot) {
i++;
swap(a, i, j);
}
// swap a[i+1] and pivot
swap(a, i + 1, right);
return i + 1;
}
并在您的quickSort方法中:
if (left < index)
quickSort(a, left, index-1);
if (index < right)
quickSort(a, index + 1, right);
希望有所帮助
答案 2 :(得分:2)
int pivot = a[0];
应该是
int pivot = a[left];
即将swap (a, i, j);
更改为swap (a, i--, j++);
和everything appears to work fine。
为何上述变化:
枢轴应该是范围中的第一个元素,而不是第一个元素。
也不应该在这个中间,就像这里:
int pivot = a[(left + right) / 2];
您想要枢轴的哪个元素无关紧要,最简单的方法是始终将所选元素与第一个元素交换,并继续正常运行。可能还有其他的做事方式,但那些可能会更复杂。
所以你可以说:
swap(left, (left + right) / 2);
int pivot = a[left];
与上面的内容非常相似(不完全相同),只是更容易处理。
答案 3 :(得分:1)
我认为partition
方法应该返回j
而不是i
。
代码中的另一个问题是停止条件:
而不是两个单独的条件我将它改为一个条件:
if (left < right) {
do partition & recursive calls
}
完整代码:
public void quickSort(int[] a, int left, int right) {
if (left < right) {
int index = partition(a, left, right);
quickSort(a, left, index);
quickSort(a, index + 1, right);
}
}
private int partition (int[] a, int left, int right) {
int i = left - 1;
int j = right + 1;
int pivot = a[(left+right)/2];
while (i < j) {
i++;
while (a[i] < pivot)
i++;
j--;
while (a[j] > pivot)
j--;
if (i < j)
swap (a, i, j);
}
return j;
}
private void swap (int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}