空间复杂度O(n)
时间复杂度O(nlogn):一趟归并遍历n个数据,由完全二叉树的深度可知,需要进行log2n次
代码实现(非递归,稳定):
//gap--两两归并---两个归并段----每个归并段元素最大数量gap
void Merge(int* arr, int len, int gap,int* tmp) {
int left1 = 0;
int right1 = left1 + gap-1;
int left2 = right1 + 1;
int right2 = left2 + gap - 1 <= len - 1 ? left2 + gap - 1 : len - 1;
int i = 0;//i遍历tmp
//足够两个归并段
while (left2 < len) {
//一组归并段
while (left1 <= right1 && left2 <= right2) {
//谁小谁下来 ++
if (arr[left1] <= arr[left2]) {
tmp[i++] = arr[left1++];
}
else {
tmp[i++] = arr[left2++];
}
}
if (left1 > right1) {//拷贝第二个归并段到tmp
for (int j = left2; j <= right2; j++) {
tmp[i++] = arr[j];
}
}
else {//拷贝第一个归并段到tmp
for (int j = left1; j <= right1; j++) {
tmp[i++] = arr[j];
}
}
left1 = right2 + 1;
right1 = left1 + gap - 1;
left2 = right1 + 1;
right2 = left2 + gap - 1 <= len - 1 ? left2 + gap - 1 : len - 1;
}
//不足两个归并段 Left1~Right1有数据
for (int j = left1; j < len ; j++) {
tmp[i++] = arr[j];
}
//将tmp拷贝给arr
memcpy(arr, tmp, sizeof(int)*len);//string.h
}
void MergeSort(int* arr, int len) {
int* tmp = (int*)malloc(sizeof(int) * len);
assert(tmp != NULL);
for (int i = 1; i < len; i *=2) {
Merge(arr, len, i,tmp);
}
free(tmp);
tmp = NULL;
}
//分割函数
int Partition(int* arr,int left, int right) {
assert(arr != NULL);
//选取基准
int tmp = arr[left];
while (left < right) {
//从右向左找,<= 基准小 向前丢
while (left<right && arr[right] > tmp) {
right--;
}
arr[left] = arr[right];
//从左向右找,>基准大 向后丢
while (left<right && arr[left] <= tmp) {
left++;
}
arr[right] = arr[left];
}
arr[left] = tmp;
return left;
}
void Quick(int* arr, int left, int right) {
assert(arr != NULL);
int index = Partition(arr, left, right);
if (index - left >= 2) {
Quick(arr, left, index-1);
}
if (right - index >= 2) {
Quick(arr, index+1, right);
}
}
void QuickSort(int* arr, int len) {
assert(arr != NULL);
if (len <= 1)return;
Quick(arr, 0, len - 1);
}
如果数据量过小,可以直接插入排序。因为n小,n^2也不会太大;
void QuickSort(int* arr, int len) {
assert(arr != NULL);
if (len <= 1)return;
if (len <= 1000) {
InsertSort(arr, len);
}
Quick(arr, 0, len - 1);
}
三数取中法,取最左端值、最右端值、中间值,三者中不大不小的作为基准值;
void Three_Num_Mid(int* arr, int left, int right) {
int mid = (left + right) / 2;
//将左边和中间位置de较大值放在中间
if (arr[left] > arr[mid]) {
int tmp = arr[left];
arr[left] = arr[mid];
arr[mid] = tmp;
}
//将三个数中的最大值放在最右边
if (arr[mid] > arr[right]) {
int tmp = arr[mid];
arr[mid] = arr[right];
arr[right] = tmp;
}
//不大不小的值,在左边或者中间,如果在中间,则放到最左边
if (arr[left] < arr[mid]) {
int tmp = arr[left];
arr[left] = arr[mid];
arr[mid] = tmp;
}
}
void Quick(int* arr, int left, int right) {
assert(arr != NULL);
Three_Num_Mid(arr, left, right);
int index = Partition(arr, left, right);
if (index - left >= 2) {
Quick(arr, left, index-1);
}
if (right - index >= 2) {
Quick(arr, index+1, right);
}
}
void QuickSort(int* arr, int len) {
assert(arr != NULL);
if (len <= 1)return;
Quick(arr, 0, len - 1);
}
随机数法,通过使用随机数,将数据打乱;
递归时,如果子序列数据量过小,也可以直接调用直接插入排序。