1. 直接插入排序
void insertSort(vector<int>& nums) {
// 直接插入排序
// 时间复杂度 O(n * n) 空间复杂度 O(1) 稳定
// 查找时可以通过二分法进行查找,这样可以减少查找次数,但移动次数无法减少
int n = nums.size();
if (n <= 1) return;
for (int i = 1; i < n; ++i) {
if (nums[i] < nums[i - 1]) {
int tmp = nums[i];
int j = -1;
for (j = i - 1; j >= 0 && nums[j] > tmp; --j) {
nums[j + 1] = nums[j];
}
nums[j + 1] = tmp;
}
}
}
2. 希尔排序
void shellSort(vector<int>& nums) {
// 希尔排序
// 时间复杂度 O(n * n) 空间复杂度 O(1) 不稳定
int n = nums.size();
if (n <= 1) return;
int d = 0, i = 0, j = 0, tmp = 0;
for (d = n / 2; d >= 1; d /= 2) {
for (i = d; i < n; ++i) { // 每个元素都进行相应子表的直接插入排序
if (nums[i] < nums[i - d]) {
tmp = nums[i];
for (j = i - d; j >= 0 && nums[j] > tmp; j -= d) {
nums[j + d] = nums[j];
}
nums[j + d] = tmp;
}
}
}
}
3. 冒泡排序
void bubbleSort(vector<int>& nums) {
// 冒泡排序
// 时间复杂度 O(n * n) 空间复杂度 O(1) 稳定
int n = nums.size();
if (n <= 1) return;
bool exchange = 0; // 未发生交换
for (int i = 0; i < n - 1; ++i) { // 需要比较 n - 1 轮
for (int j = 0; j < n - 1 - i; ++j) {
if (nums[j] > nums[j + 1]) {
std::swap(nums[j], nums[j + 1]);
exchange = 1;
}
}
if (exchange == 0) return; // 某一轮中未发生交换说明排序已经完成
}
}
4. 快速排序
void quickSort(vector<int>& nums, int low, int high) {
// 快速排序
// 时间复杂度 O(n * logn) 空间复杂度 O(n) 不稳定
auto partition = [&](int left, int right) -> int {
int pivot = nums[left];
while (left < right) {
while (left < right && nums[right] >= pivot) {
--right;
}
nums[left] = nums[right];
while (left < right && nums[left] <= pivot) {
++left;
}
nums[right] = nums[left];
}
nums[left] = pivot;
return left;
};
if (low < high) {
int pivotpos = partition(low, high);
quickSort(nums, low, pivotpos - 1);
quickSort(nums, pivotpos + 1, high);
}
}
5. 简单选择排序
void selectSort(vector<int>& nums) {
// 简单选择排序
// 时间复杂度 O(n * n) 空间复杂度 O(1) 不稳定
int n = nums.size();
if (n <= 1) return;
for (int i = 0; i < n; ++i) {
int min = i;
for (int j = i + 1; j < n; ++j) {
if (nums[j] < nums[min]) {
min = j;
}
}
if (min != i) {
std::swap(nums[i], nums[min]);
}
}
}
6. 堆排序
6.1 递归调整堆
void heapAdjust(vector<int>& nums, int k, int n) {
if (k >= n) return;
int left = 2 * k + 1;
int right = 2 * k + 2;
int max = k;
if (left < n && nums[left] > nums[max]) {
max = left;
}
if (right < n && nums[right] > nums[max]) {
max = right;
}
if (max != k) {
std::swap(nums[k], nums[max]);
heapAdjust(nums, max, n);
}
}
void buildMaxHeap(vector<int>& nums) {
int n = nums.size();
for (int i = (n - 2) / 2; i >= 0; --i) {
heapAdjust(nums, i, n);
}
}
void heapSort(vector<int>& nums) {
// 堆排序
// 时间复杂度 O(n * logn) 空间复杂度 O(1) 不稳定
int n = nums.size();
buildMaxHeap(nums); // 建立大根堆 -> 时间复杂度为 O(n)
for (int i = n - 1; i > 0; --i) { // n - 1 轮调整堆
std::swap(nums[i], nums[0]);
heapAdjust(nums, 0, i); // 只需改变树的结点数,就可以保持已经排序好的结点不被打乱
}
}
6.2 迭代调整堆
void heapSort(vector<int>& nums) {
// 堆排序
// 时间复杂度 O(n * logn) 空间复杂度 O(1) 不稳定
int sz = nums.size();
auto heapAdjust = [&](int k, int n) {
// 调整以编号是 k 的结点为根的子树,使之成为堆
int tmp = nums[k];
for (int i = 2 * k; i < n; i *= 2) {
if (i < n - 1 && nums[i] < nums[i + 1]) {
++i;
}
if (tmp >= nums[i]) {
break;
}
else {
nums[k] = nums[i];
k = i;
}
}
nums[k] = tmp;
};
auto buildMaxHeap = [&]() {
for (int i = (sz - 2) / 2; i >= 0; --i) {
heapAdjust(i, sz);
}
};
buildMaxHeap(); // 建立大根堆 -> 时间复杂度为 O(n)
for (int i = sz - 1; i > 0; --i) { // sz - 1 轮调整堆
std::swap(nums[i], nums[0]);
heapAdjust(0, i);
}
}
7. 归并排序
void mergeSort(vector<int>& nums, int low, int mid, int high) {
// 归并排序,nums[low] ~ nums[mid] 升序,nums[mid + 1] ~ nums[high] 升序
vector<int> tmp = nums;
int i, j, k;
for (i = low, j = mid + 1, k = low; i <= mid && j <= high; ++k) {
if (tmp[i] <= tmp[j]) {
nums[k] = tmp[i++];
}
else {
nums[k] = tmp[j++];
}
}
while (i <= mid) nums[k++] = tmp[i++];
while (j <= high) nums[k++] = tmp[j++];
}
8. 测试
void print(vector<int>& nums) {
for (int& x : nums) {
cout << x << " ";
}
cout << endl;
}
int main() {
vector<int> nums{ 2,7,4,9,0,1,8,3,5,6 };
//insertSort(nums);
//shellSort(nums);
//bubbleSort(nums);
//quickSort(nums, 0, nums.size() - 1);
//selectSort(nums);
//heapSort(nums);
vector<int> mergeNums{ 0,2,4,6,8,1,3,5,7,9 };
mergeSort(mergeNums, 0, 4, 9);
//print(nums);
print(mergeNums);
return 0;
}