朋友们,现在我出一个非常简单的问题,给你一个数组,把它进行处理,变成左边小,中间相等,右边大的一个数组,如何解决呢,这里涉及到一个基本方法叫分组,今天咱们不解决这个问题,只了解下,分组算法的基本思想。
代码很简洁,如下:
public static int partition(int[] arr, int L, int R) {
if (L > R) {
return -1;
}
if (L == R) {
return L;
}
int lessEqual = L - 1;
int index = L;
while (index < R) {
if (arr[index] <= arr[R]) {
swap(arr, index, ++lessEqual);
}
index++;
}
swap(arr, ++lessEqual, R);
return lessEqual;
}
分区操作的目标是将一个数组分成两部分,一部分包含所有小于或等于某个元素的值,另一部分包含所有大于该元素的值。这个元素一般称为“分区元素”或“基准元素”。
以下是代码的详细解释:
public static int partition(int[] arr, int L, int R) {
if (L > R) {
return -1;
}
if (L == R) {
return L;
}
int lessEqual = L - 1; // 初始化小于等于分区元素的区域的边界
int index = L; // 初始化当前遍历的元素的索引,从左边界开始
// 从左到右遍历数组,将小于等于分区元素的元素放在 lessEqual 区域
while (index < R) {
if (arr[index] <= arr[R]) {
swap(arr, index, ++lessEqual); // 如果当前元素小于等于分区元素,将其与 lessEqual 区域的下一个元素交换位置
}
index++;
}
// 最后将分区元素与 lessEqual 区域的下一个元素交换位置,使分区元素位于正确的位置
swap(arr, ++lessEqual, R);
return lessEqual; // 返回分区元素的最终位置
}
示例:
让我们通过一个示例来演示这个分区操作。假设有一个数组 arr
,内容如下:
arr = [7, 3, 9, 4, 6, 2, 8]
我们调用 partition(arr, 0, 6)
来分区这个数组,其中 L = 0
是左边界,R = 6
是右边界。这个示例的初始状态如下:
lessEqual
初始化为 L - 1 = -1
,表示小于等于分区元素的区域为空。index
初始化为 L = 0
,从数组的左边开始遍历分区操作的过程如下:
index = 0
,此时 arr[index] = 7
,因为 7 <= 8
(分区元素是最右边的元素),所以将 7
与 arr[lessEqual + 1]
交换,lessEqual
变为 0
。 结果:arr = [7, 3, 9, 4, 6, 2, 8]
index = 1
,此时 arr[index] = 3
,因为 3 <= 8
,所以将 3
与 arr[lessEqual + 1]
交换,lessEqual
变为 1
。 结果:arr = [7, 3, 9, 4, 6, 2, 8]
index = 2
,此时 arr[index] = 9
,因为 9 > 8
,不需要交换,index
继续向右移动。 结果:arr = [7, 3, 9, 4, 6, 2, 8]
依此类推,直到 index
移动到 6
。
最后,将分区元素 8
与 arr[lessEqual + 1]
交换,即 8
移动到了正确的位置。 结果:arr = [7, 3, 4, 6, 2, 8, 9]
分区操作结束,lessEqual
的值表示分区元素 8
的最终位置。在这个示例中,lessEqual
的值为 5
,即分区元素 8
最终位于索引 5
的位置。
这就完成了一次分区操作,将数组分为两部分:左边是小于等于 8
的元素,右边是大于 8
的元素。
上面主要是讲了荷兰国旗问题的一个小分支,这属于核心算法,具体如何实现整体的,大家可以自行查阅,其实这个算法可以自己去算一算,如果用一句话总结的话就是:给一个数组,最右侧的R是默认要划分的边界值,lessEqual记录小于等于R的最右侧边界索引,最后把R放到lessEqual的未知,再返回lessEqual的index。