Java 快速排序算法未正确分配枢轴
我观看了一个快速排序算法的奇妙可视化: 我觉得自己真正理解了快速排序背后的原则,并在一些在线指南的帮助下,着手创建自己的快速排序。Java 快速排序算法未正确分配枢轴,java,sorting,quicksort,Java,Sorting,Quicksort,我观看了一个快速排序算法的奇妙可视化: 我觉得自己真正理解了快速排序背后的原则,并在一些在线指南的帮助下,着手创建自己的快速排序。 这就是我想到的: 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 &
这就是我想到的:
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;
}
不幸的是,输出不正确。问题似乎在于我对枢轴的处理。在我观看的可视化过程中,讲师实际移除了枢轴,让指针指向任何东西。他继续进行教程,当他到达i和j(我称之为左和右)都指向同一个空白点时,他插入枢轴并继续进行
由于我在物理上保持枢轴在适当的位置,我发现很难对其进行正确排序
在这段代码中,我使用的是输入:
4 8 1 6 3 7 2 5
我得到输出:
1 3 2 6 8 7 4 5
一旦在算法开始时对“4”值(即枢轴)进行排序,我就再也不会使用它,这会使一切都变得混乱。此外,我认为快速排序方法有问题
有人能给我一些建议吗?谢谢
编辑:此处的两个编辑已被删除,因为它们包含不必要和不正确的信息。其中一个将轴更改为:(左+右)/2。这当然是错误的,原因如下所述。我认为
分区
方法应该返回j
,而不是I
代码中的另一个问题是停止条件:
我将其更改为单个条件,而不是两个单独的条件:
if (left < right) {
do partition & recursive calls
}
if(左<右){
执行分区和递归调用
}
完整代码:
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;
}
public void快速排序(int[]a,int left,int right){
if(左<右){
int index=分区(a,左,右);
快速排序(a,左,索引);
快速排序(a,索引+1,右);
}
}
私有int分区(int[]a,int左,int右){
int i=左-1;
int j=右+1;
int pivot=a[(左+右)/2];
而(ipivot)
j--;
if(i
我必须去掉分区,因为您需要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
}
}
很明显,你已经得到了公认的答案。但是,我要提到的是,分区逻辑可以更容易地实现,只有一个for(或while)循环,没有嵌套循环:
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;
}
int分区(final int[]a,final int left,final int right){
//将最后一个元素设置为轴
最终整数轴=a[右];
int i=左-1,j=左;
对于(;j
在您的快速排序方法中:
if (left < index)
quickSort(a, left, index-1);
if (index < right)
quickSort(a, index + 1, right);
if(左<索引)
快速排序(a,左,索引-1);
如果(索引<右)
快速排序(a,索引+1,右);
希望能有帮助
int pivot = a[0];
应该是
int pivot = a[left];
通过改变swap(a,i,j)代码>到交换(a,i--,j++)代码>和
上述变化的原因:
轴应该是范围中的第一个元素,而不是第一个元素
也不应该在中间,就像这里:
int pivot = a[(left + right) / 2];
无论您希望轴心是哪个元素,最简单的方法是始终将所选元素与第一个元素交换,然后继续正常操作。也许还有其他的方法,但这些方法可能更复杂
所以你可以说:
swap(left, (left + right) / 2);
int pivot = a[left];
这与上面的非常相似(不完全相同),只是更容易处理。因为太本地化而关闭。@djechlin:我认为它针对的是一个特定的编程算法,如常见问题解答所示。如果我错了,你能推荐哪个堆栈交换来询问这个问题吗?@djechlin他在问一个显示代码的编码问题。这怎么可能太本地化了???@djechlin:我想指出的是,在常见问题解答中,它说:“你应该根据你所面临的实际问题,只提出实际的、可回答的问题。”我不知道在哪里“。如前所述,如果您知道我应该在另一个Stack Exchange站点发布此内容,请推荐。@djechlin您弄错了。问一个关于堆栈溢出的实际编码问题是完全可以的。我想也许你在想程序员。在任何情况下,请随时询问Meta以澄清。它可能需要这样做,但不幸的是,这会返回StackOverflow错误-可能是由于其他地方的错误。您应该将该更改应用于原始代码。您在edit2中的更改是错误的。您必须在循环之前更改i&j,因为它们被初始化为刚好超出您正在分区的数组范围的值。我已将我的个人副本更改回edit2之前,并将返回int更改为j-但是,它仍然会生成StackOverflow错误您有调试器吗?StackOverflow意味着partition方法不会对输入进行分区(即其中一个分区为空),这会导致无限递归。是的,我现在在Eclipse调试器上完成每个步骤(使用您的编辑)。只是不知道如何停止错误!工作完美。先生,你绝对是个传奇人物。我将研究你的代码和我的代码之间的差异,并尝试从中学习。没问题。如果你需要任何澄清,请在这里发表评论。嗨,你能进一步解释一下这句话吗?int pivot=a[left+(right-left)/2]@这意味着我们选择“<代码>枢轴< /代码>的值:位于<>代码>左和<代码>右< /代码>之间的元素。这都有帮助。我将研究这一点,并尝试从中学习。感谢you@AndrewMartin
int pivot = a[(left + right) / 2];
swap(left, (left + right) / 2);
int pivot = a[left];