// O(N^1.3)
void ShellSort(int* a, int n) {
// 1、gap>1 预排序
// 2、gap==1 直接排序
int gap = n;
while (gap > 1) {
// gap=gap/3+1; +1可以保证最后一次一定是1
gap = gap / 2;
for (int i = 0; i < n - gap; i++) {
int end = i;
int tmp = a[end + gap];
while (end >= 0) {
if (a[end] > tmp) {
a[end + gap] = a[end];
end -= gap;
} else {
break;
}
}
a[end + gap] = tmp;
}
}
}
void SelectSort(int* a, int n) {
int begin = 0, end = n - 1;
while (begin < end) {
int maxi = begin, mini = begin;
for (int i = begin; i <= end; i++) {
if (a[i] > a[maxi]) {
maxi = i;
}
if (a[i] < a[mini]) {
mini = i;
}
}
Swap(&a[begin], &a[mini]);
// 如果maxi和begin重叠,修正一下即可
if (begin == maxi) {
maxi = mini;
}
Swap(&a[end], &a[maxi]);
++begin;
--end;
}
}
// 1、排序 hore
int PartSort(int* a, int left, int right) {
int mid=GetMidIndex(a, left, right);
Swap(&a[left],&a[mid]);
int keyi = left;
while (left < right) {
//右边找小
while (left < right && a[right] >= a[keyi]) {
--right;
}
//左边找大
while (left < right && a[left] <= a[keyi]) {
++left;
}
Swap(&a[left], &a[right]);
}
Swap(&a[keyi], &a[left]);
return left;
}
2.挖坑法
cpp复制代码
// 2、排序 挖坑法
//[left,right]
int PartSort2(int* a, int left, int right) {
int mid=GetMidIndex(a, left, right);
Swap(&a[left],&a[mid]);
int key = a[left];
int hole = left;
while (left < right) {
// 右边找小
while (left < right && a[right] >= key) {
--right;
}
a[hole] = a[right];
hole = right;
// 左边找大
while (left < right && a[left] <= key) {
++left;
}
a[hole] = a[left];
hole = left;
}
a[hole] = key;
return hole;
}
3.前后指针法
cpp复制代码
// 3、排序 前后指针法
int PartSort3(int* a, int left, int right) {
int mid=GetMidIndex(a, left, right);
Swap(&a[left],&a[mid]);
int keyi = left;
int prev = left;
int cur = left + 1;
while (cur <= right) {
if (a[cur] < a[keyi] && ++prev != cur) {
Swap(&a[cur], &a[prev]);
}
++cur;
}
Swap(&a[prev], &a[keyi]);
keyi = prev;
return keyi;
}
3)快速排序优化
三数取中法选key
递归到小的子区间时,可以考虑使用插入排序
cpp复制代码
int GetMidIndex(int* a, int left, int right) {
int mid = (left + right) / 2;
if (a[left] < a[mid]) {
if (a[mid] < a[right]) {
return mid;
} else if (a[left] < a[right]) {
return right;
} else {
return left;
}
} else {
if (a[mid] > a[right]) {
return mid;
} else if (a[left] > a[right]) {
return right;
} else {
return left;
}
}
}
4)快速排序非递归
cpp复制代码
void QuickSortNonR(int* a, int begin, int end) {
ST st;
STInit(&st);
STPush(&st, end);
STPush(&st, begin);
while (!STEmpty(&st)){
int left = STTop(&st);
STPop(&st);
int right = STTop(&st);
STPop(&st);
int keyi = PartSort3(a, left, right);
if (keyi + 1 < right) {
STPush(&st, right);
STPush(&st, keyi + 1);
}
if (left < keyi - 1) {
STPush(&st,keyi-1);
STPush(&st, left);
}
}
STDestroy(&st);
}
快速排序的特性总结:
快速排序整体的综合性能和使用场景都是比较好的,所以才敢叫快速排序
时间复杂度:O(N*logN)
空间复杂度:O(logN)
稳定性:不稳定
4、归并排序
基本思想:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有 序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
cpp复制代码
//时间复杂度:O(logN* n)
//空间复杂度:O(N)
void _MergeSort(int* a, int begin, int end, int* tmp) {
if (begin == end)
return;
int mid = (begin + end) / 2;
//[begin, mid] [mid+1, end]
_MergeSort(a, begin, mid, tmp);
_MergeSort(a, mid + 1, end, tmp);
int begin1 = begin, end1 = mid;
int begin2 = mid+1, end2 = end;
int i = begin;
while (begin1<=end1&&begin2<=end2) {
if (a[begin1] < a[begin2]) {
tmp[i++] = a[begin1++];
} else {
tmp[i++] = a[begin2++];
}
}
while (begin1 <= end1) {
tmp[i++] = a[begin1++];
}
while (begin2 <= end2) {
tmp[i++] = a[begin2++];
}
memcpy(a+begin, tmp+begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n) {
int* tmp = (int*)malloc(sizeof(int) * n);
_MergeSort(a, 0, n - 1, tmp);
free(tmp);
}