为何以最左元素为基准时,快速排序不能从左侧开始分区?
Hoare分区法选最左元素为基准时,为何不能从左侧开始分区?
我正在使用Hoare分区法实现快速排序,代码如下:
private static int partition(int[] arr, int startIndex, int endIndex) { int pivot = arr[startIndex]; int i = startIndex; int j = endIndex; while (i != j) { while (i < j && arr[i] <= pivot) { i++; } while (i < j && arr[j] > pivot) { j--; } if (i < j) { swap(arr, i, j); } } swap(arr, startIndex, i); return i; }
我选择最左侧元素作为基准,从左索引开始分区时发现该实现无法正常工作,但从右侧开始分区则可正常运行。我想了解为何以最左元素为基准时,不能从左侧索引开始分区?
核心原因:相遇点元素的性质不符合分区要求
当基准选在数组最左侧时,必须先从右侧(j)开始遍历,否则会导致最后i、j相遇的位置元素大于基准,交换后破坏分区逻辑,具体拆解如下:
先左后右的遍历逻辑缺陷
你的代码中先移动i:只要arr[i] <= pivot就i++,直到找到第一个大于pivot的元素或i=j。
举个反例:数组[3,4,2],基准是最左的3。- 初始i=0,j=2。i先移动:
arr[0]<=3→i=1;arr[1]=4>3,停止左遍历。 - 再移动j:
arr[2]=2>3不成立,j保持2。此时i=1<j=2,交换arr[1]和arr[2],数组变为[3,2,4]。 - 继续循环:i=1,j=2。i再次移动:
arr[1]=2<=3→i=2,此时i=j,退出循环。 - 交换基准位置(0)和相遇点(2),数组变为
[4,2,3]。此时基准3的左侧出现了大于它的4,分区完全失效。
- 初始i=0,j=2。i先移动:
先右后左的合理性
如果先从j开始遍历:只要arr[j]>pivot就j--,直到找到第一个<=pivot的元素或i=j。
最后i、j相遇的位置,元素一定是<=pivot的——因为要么是j停在这个位置,要么是i移动到j的位置(此时j已经找到符合条件的元素)。
把基准和这个位置交换后,基准左侧的元素都会<=它,右侧都会>它,符合Hoare分区的规则。本质逻辑
Hoare分区的核心是让基准最终处于正确位置:左边元素<=基准,右边元素>基准。当基准在最左时,我们需要保证最后交换到基准位置的元素是<=它的,而先从右侧遍历才能确保这一点。
内容的提问来源于stack exchange,提问作者hawarden_
相关产品推荐
相关产品推荐

