关于快速选择排序程序第一趟划分流程分析
关于快速选择排序程序第一趟划分流程分析
问题1:{28,16,32,12,60,2,5,72}选择28作为基准第一趟划分分析
下面详细分析数组 {28, 16, 32, 12, 60, 2, 5, 72}
以 28
作为基准进行第一趟划分的过程。
初始状态
[28, 16, 32, 12, 60, 2, 5, 72]
- 选择第一个元素
28
作为基准元素。 - 初始化指针:
left
指针从low + 1
即索引1
开始,初始指向元素16
。right
指针从high
即索引7
开始,初始指向元素72
。
指针移动与元素交换步骤
第一轮移动与交换
left
指针移动:left
指向16
,因为16 < 28
,left
指针继续向右移动,指向32
。此时32 > 28
,left
指针停止移动。right
指针移动:right
指向72
,因为72 > 28
,right
指针继续向左移动,指向5
。此时5 < 28
,right
指针停止移动。- 元素交换:此时
left
指向32
,right
指向5
,交换这两个元素,数组变为[28, 16, 5, 12, 60, 2, 32, 72]
。
第二轮移动与交换
left
指针移动:left
继续右移,指向12
,因为12 < 28
,继续右移指向60
,60 > 28
,left
指针停止移动。right
指针移动:right
继续左移,指向2
,因为2 < 28
,right
指针停止移动。- 元素交换:此时
left
指向60
,right
指向2
,交换这两个元素,数组变为[28, 16, 5, 12, 2, 60, 32, 72]
。
指针相遇
left
指针移动:left
继续右移。right
指针移动:right
继续左移。当left > right
时,指针相遇,此时right
指向的元素是2
,left
指向的元素是60
,分区过程结束。
放置基准元素
将基准元素 28
与 right
指针所指的元素 2
交换位置,数组变为 [2, 16, 5, 12, 28, 60, 32, 72]
。
结果分析
经过第一趟划分后,基准元素 28
已经处于其最终排序的位置,左边的子数组 [2, 16, 5, 12]
中的所有元素都小于 28
,右边的子数组 [60, 32, 72]
中的所有元素都大于 28
。接下来就可以递归地对左右子数组分别进行快速排序,以完成整个数组的排序。
下面是用代码模拟上述第一趟划分过程的示例:
#include <stdio.h>
// 分区函数,用于将数组以基准元素为界分为两部分
int partition(int arr[], int low, int high) {
int pivot = arr[low]; // 选择第一个元素作为基准
int left = low + 1;
int right = high;
int temp;
while (1) {
// 左指针右移,直到找到大于基准的元素
while (left <= right && arr[left] <= pivot) {
left++;
}
// 右指针左移,直到找到小于基准的元素
while (left <= right && arr[right] >= pivot) {
right--;
}
if (left > right) {
break;
}
// 交换左右指针所指的元素
temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
// 将基准元素放到正确的位置
temp = arr[low];
arr[low] = arr[right];
arr[right] = temp;
return right;
}
int main() {
int arr[] = {28, 16, 32, 12, 60, 2, 5, 72};
int n = sizeof(arr) / sizeof(arr[0]);
int pivot_index = partition(arr, 0, n - 1);
printf("第一趟划分后的数组: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n基准元素的最终位置索引: %d\n", pivot_index);
return 0;
}
问题2:{28,16,32,12,60,2,5,18}选择18作为基准第一趟划分分析
下面详细分析这个过程:
初始状态
- 待排序数组:
[28, 16, 32, 12, 60, 2, 5, 18]
- 基准元素
pivot
:选择数组的最后一个元素 18。 - 初始化一个索引
i
为-1
,用于标记小于基准元素的元素的边界。
分区过程
遍历数组元素
从数组的第一个元素开始,依次与基准元素 18 进行比较,并根据比较结果进行相应操作。
- 处理元素 28:
- 因为
28 > 18
,不进行索引i
的更新和元素交换操作。此时i
仍为-1
。
- 因为
- 处理元素 16:
- 由于
16 < 18
,将i
加 1,此时i
变为0
。 - 交换
arr[i]
(即arr[0]
,值为 28)和arr[j]
(即arr[1]
,值为 16),数组变为[16, 28, 32, 12, 60, 2, 5, 18]
。
- 由于
- 处理元素 32:
- 因为
32 > 18
,不进行索引i
的更新和元素交换操作。此时i
仍为0
。
- 因为
- 处理元素 12:
- 由于
12 < 18
,将i
加 1,此时i
变为1
。 - 交换
arr[i]
(即arr[1]
,值为 28)和arr[j]
(即arr[3]
,值为 12),数组变为[16, 12, 32, 28, 60, 2, 5, 18]
。
- 由于
- 处理元素 60:
- 因为
60 > 18
,不进行索引i
的更新和元素交换操作。此时i
仍为1
。
- 因为
- 处理元素 2:
- 由于
2 < 18
,将i
加 1,此时i
变为2
。 - 交换
arr[i]
(即arr[2]
,值为 32)和arr[j]
(即arr[5]
,值为 2),数组变为[16, 12, 2, 28, 60, 32, 5, 18]
。
- 由于
- 处理元素 5:
- 由于
5 < 18
,将i
加 1,此时i
变为3
。 - 交换
arr[i]
(即arr[3]
,值为 28)和arr[j]
(即arr[6]
,值为 5),数组变为[16, 12, 2, 5, 60, 32, 28, 18]
。
- 由于
放置基准元素
遍历完除基准元素外的所有元素后,i
为 3
。将基准元素 18 与 arr[i + 1]
(即 arr[4]
,值为 60)交换位置,数组变为 [16, 12, 2, 5, 18, 32, 28, 60]
。
划分结果
经过第一趟划分后,数组变为 [16, 12, 2, 5, 18, 32, 28, 60]
。基准元素 18 已经处于其最终排序的正确位置,左边子数组 [16, 12, 2, 5]
中的所有元素都小于 18,右边子数组 [32, 28, 60]
中的所有元素都大于 18。后续可以递归地对左右子数组分别进行快速排序,以完成整个数组的排序。
下面是用代码模拟上述第一趟划分过程的示例:
#include <stdio.h>
// 分区函数,用于将数组以基准元素为界分为两部分
int partition(int arr[], int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = (low - 1); // 初始化小于基准元素的元素的索引
for (int j = low; j <= high - 1; j++) {
// 如果当前元素小于基准元素
if (arr[j] < pivot) {
i++;
// 交换 arr[i] 和 arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 将基准元素放到正确的位置
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return (i + 1);
}
int main() {
int arr[] = {28, 16, 32, 12, 60, 2, 5, 18};
int n = sizeof(arr) / sizeof(arr[0]);
int pivot_index = partition(arr, 0, n - 1);
printf("第一趟划分后的数组: ");
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n基准元素的最终位置索引: %d\n", pivot_index);
return 0;
}