C++ 归并排序 个人笔记
一.归并排序的基本思想
一个数组分成先以中间为界,把其均分为 A 和 B 两个数组(如果是奇数个,允许两组数相差一个),这二组数据必须是有序的,我们可以依次从两组中取最前面的那个最小元素依次有序放到临时的数组中,然后再把临时数组中有序的数据拷贝到原数组中,快速完成排序(归并法)
但是一个待排序的数组从中间分成二组数据,不可能二组数据都是有序的,我可以用分治的手法,把数组分到只有二个数据然后进行归并法
二. 归并排序的代码实现
建议从main()函数开始看代码
源代码
#include <iostream>
using namespace std;
/*
****************************
* 函数前提: 将一组数据分成二组 这两组的数据都是从小到大有序的
(如果是奇数个,允许两组数据相差一个)
* 函数作用: 利用一个临时数组将一个数组排序一个数组中一个区间的数据排序
*
* 函数参数: arr - 需要排序的数组的首地址;
* left - 左边组开始的数组下标
* middie - 右边组开始的数组下标
* 也是左边组结束数组下标的下一个下标
* right - 右边组结束的数组下标
* 这个区间最后一个数组下标
* tmp - 临时保存已排好序的数组
*
* 函数返回值: 无
***************************
*/
void mergerAdd(int* arr, int left, int middie, int right,int* tmp) {
if (!arr || !tmp) return;
int size = left; //临时数组的下标
int i = left; //i指向左边组开始的数组下标,
int j = middie;//j指向右边组开始的数组下标,
while (i < middie && j <= right) {
//因为这两组是有序的
//比如 左边组 1 3 5
//右边数据 2,4,6
//从第一个元素比较 1比2小 1进入临时数组
//i++ 下标指向 3
//循环直到一组数据完成遍历循环结束
if (arr[i] > arr[j]) {
tmp[size++] = arr[j];
j++;
}
else {
tmp[size++] = arr[i];
i++;
}
}
//左边的数据没有完成遍历
while (i < middie) {
//肯定是最大的数 依次进入临时数组
tmp[size++] = arr[i];
i++;
}
//右边的数据没有完成遍历
while (j <= right) {
tmp[size++] = arr[j];
j++;
}
//当前tmp数组是一个有序数组
/*
**************************************
*函数作用: 内存拷贝
*函数参数: 第一个参数是需要拷贝到的目的地(地址)
* 第二个参数是待拷贝的地址
* 第三个参数是需要拷贝的字节数
*
*******************************
*/
//为什么第一个参数是arr+ left?
//比如传入的是参数是: arr数组:7,2,4,1,3,7, left = 1,middie = 2,right = 4
//下标为0 的数据不变 从下标为1到下标为4这个区间的数据
//分为二组开始合并成一个有序数组保存在tmp 临时数组中
//如果从arr的首地址开始进行数据拷贝会导致在这个区间以外的数据发生被覆盖
memcpy(arr + left, tmp + left, sizeof(int) * (right - left + 1));
}
/*
***********************************
*函数作用: 归并排序
*
*函数参数: arr - 需要排序的数组
* left - 从这个位置开始排序的数组下标
* right - 结束的数组下标 left 到 right 是需要排序的区间
* tmp - 临时保存已排好序的数组
*
* 函数返回值 : 无
*/
void mergerSort(int* arr, int left, int right, int* temp) {
int middie = -1;
//这个条件使得这个指定区间能一分为二
//分到这区间只有2个数据
if (left < right) {
//middie取left和right相对中间的下标
middie = (right - left) / 2 + left;
//middie 左边的数据进行排序(包括middie)
mergerSort(arr, left, middie, temp);
//middie+1 右边的数据进行排序
mergerSort(arr, middie + 1, right, temp);
//这个区间只有2个数据后分成二组 这二组都是有序的
//一组一个数据进行合并
//这个区间成为一个有序数组
mergerAdd(arr, left, middie+1, right,temp);
}
}
int main(void) {
int test[] = { 1,14,11,10,23,15,21,13,25};
int len = sizeof(test) / sizeof(test[0]);
int* tmp = new int[len];
//int middie = len / 2;
mergerSort(test, 0, len-1,tmp);
for (int i = 0; i < len; i++) {
printf("%d\t", test[i]);
}
delete[] tmp;
return 0;
}
代码测试
三.归并排序的递归过程
红线-左边数组分治也就是归并排序中第一次调用的函数
蓝线-右边数组分治也就是归并排序中第二次调用的函数
因为数组的个数越多,调用函数的次数越多,调用过程是重复的,我选了4个数来进行归并排序