-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Expand file tree
/
Copy pathquick_sort.c
More file actions
137 lines (123 loc) · 4.19 KB
/
Copy pathquick_sort.c
File metadata and controls
137 lines (123 loc) · 4.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* File: quick_sort.c
* Created Time: 2023-01-18
* Author: Reanon (793584285@qq.com)
*/
#include "../utils/common.h"
/* 元素交换 */
void swap(int nums[], int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
/* 哨兵划分 */
int partition(int nums[], int left, int right) {
// 以 nums[left] 为基准数
int i = left, j = right;
while (i < j) {
while (i < j && nums[j] >= nums[left]) {
j--; // 从右向左找首个小于基准数的元素
}
while (i < j && nums[i] <= nums[left]) {
i++; // 从左向右找首个大于基准数的元素
}
// 交换这两个元素
swap(nums, i, j);
}
// 将基准数交换至两子数组的分界线
swap(nums, i, left);
// 返回基准数的索引
return i;
}
/* 快速排序 */
void quickSort(int nums[], int left, int right) {
// 子数组长度为 1 时终止递归
if (left >= right) {
return;
}
// 哨兵划分
int pivot = partition(nums, left, right);
// 递归左子数组、右子数组
quickSort(nums, left, pivot - 1);
quickSort(nums, pivot + 1, right);
}
// 以下为中位数优化的快速排序
/* 选取三个候选元素的中位数 */
int medianThree(int nums[], int left, int mid, int right) {
int l = nums[left], m = nums[mid], r = nums[right];
if ((l <= m && m <= r) || (r <= m && m <= l))
return mid; // m 在 l 和 r 之间
if ((m <= l && l <= r) || (r <= l && l <= m))
return left; // l 在 m 和 r 之间
return right;
}
/* 哨兵划分(三数取中值) */
int partitionMedian(int nums[], int left, int right) {
// 选取三个候选元素的中位数
int med = medianThree(nums, left, (left + right) / 2, right);
// 将中位数交换至数组最左端
swap(nums, left, med);
// 以 nums[left] 为基准数
int i = left, j = right;
while (i < j) {
while (i < j && nums[j] >= nums[left])
j--; // 从右向左找首个小于基准数的元素
while (i < j && nums[i] <= nums[left])
i++; // 从左向右找首个大于基准数的元素
swap(nums, i, j); // 交换这两个元素
}
swap(nums, i, left); // 将基准数交换至两子数组的分界线
return i; // 返回基准数的索引
}
/* 快速排序(三数取中值) */
void quickSortMedian(int nums[], int left, int right) {
// 子数组长度为 1 时终止递归
if (left >= right)
return;
// 哨兵划分
int pivot = partitionMedian(nums, left, right);
// 递归左子数组、右子数组
quickSortMedian(nums, left, pivot - 1);
quickSortMedian(nums, pivot + 1, right);
}
// 以下为递归深度优化的快速排序
/* 快速排序(递归深度优化) */
void quickSortTailCall(int nums[], int left, int right) {
// 子数组长度为 1 时终止
while (left < right) {
// 哨兵划分操作
int pivot = partition(nums, left, right);
// 对两个子数组中较短的那个执行快速排序
if (pivot - left < right - pivot) {
// 递归排序左子数组
quickSortTailCall(nums, left, pivot - 1);
// 剩余未排序区间为 [pivot + 1, right]
left = pivot + 1;
} else {
// 递归排序右子数组
quickSortTailCall(nums, pivot + 1, right);
// 剩余未排序区间为 [left, pivot - 1]
right = pivot - 1;
}
}
}
/* Driver Code */
int main() {
/* 快速排序 */
int nums[] = {2, 4, 1, 0, 3, 5};
int size = sizeof(nums) / sizeof(int);
quickSort(nums, 0, size - 1);
printf("快速排序完成后 nums = ");
printArray(nums, size);
/* 快速排序(中位基准数优化) */
int nums1[] = {2, 4, 1, 0, 3, 5};
quickSortMedian(nums1, 0, size - 1);
printf("快速排序(中位基准数优化)完成后 nums = ");
printArray(nums1, size);
/* 快速排序(递归深度优化) */
int nums2[] = {2, 4, 1, 0, 3, 5};
quickSortTailCall(nums2, 0, size - 1);
printf("快速排序(递归深度优化)完成后 nums = ");
printArray(nums1, size);
return 0;
}