算法复杂度
时间复杂度:O(nlogn)
空间复杂度:T(n)
算法策略
分而治之
基本逻辑
将相邻的数两两排序,排序好的2个数合并作为一组。
然后再把相邻的两组数两两排序,排序好的两组数合并为新的一组。
直到最后只剩一组,排序完成。
图解
代码实现
void merge_sort(int arr[], int len) {
devide_arr_merge(arr, 0, (len - 1));
for (int i = 0; i < 9; i++) {
std::cout << arr[i] << " ";
}
std::cout << std::endl;
}
void devide_arr_merge(int arr[], int start, int end) {
//如果传入数组为空,或者数组内只有1个元素,则返回
if (arr == NULL || start >= end) {
return;
}
//取中间值
int middle = (start + end) / 2;
//分解数组
devide_arr_merge(arr, start, middle);
devide_arr_merge(arr, middle + 1, end);
//分解到1时,两个devide直接返回
//此时this的start和end为相邻整数,middle == start
//调用merge将这两个数排序,回到上一层
//此时,上一层的2个devide执行完毕,上一层的start到middle是有序的,middle+1到end是有序的
//继续merge,直到所有递归调用完毕,数组变得有序
//合并排序
merge(arr, start, middle, end);
}
void merge(int arr[], int start, int middle, int end) {
int* temp = new int[end - start + 1];//排序好的数组临时放在这里
int left = start;
int right = middle + 1;
for (int i = 0; i < (end - start + 1); i++) {
if (left > middle) {
//如果左边的数据已经用完了,此时右边剩下的数都是有序的,且都比已排数更大
for (int j = right; j <= end; j++) {
temp[i] = arr[j];
i++;
}
break;
}
else if (right > end) {
//左边没用完,但右边用完了,同理
for (int j = left; j <= middle; j++) {
temp[i] = arr[j];
i++;
}
break;
}
else if (arr[left] > arr[right]) {
//左右都还有数,正常排序
temp[i] = arr[right];
right++;
}
else {
temp[i] = arr[left];
left++;
}
}
//排序完毕,将临时数组中的数填回原数组对应的位置
//因为传参传数组属于引用类型,在函数内部可以直接操作数组本身
for (int i = 0; i < (end - start + 1); i++) {
arr[start + i] = temp[i];
}
//最后别忘了释放临时数组
delete[] temp;
}
ps. 代码自己写的,但是写完发现VS出了点问题,网速过慢修复需要好久,又没有单独安装cmake。所以,基本逻辑没啥问题,但是好久没写C++了,细节上不太敢确定,不保证代码能直接跑。