//归并排序--递归算法的运用 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> /* 归并排序步骤: 第一步;将一组数据分成2部分,然后递归的继续将这2部分数据划分成4部分,直接每个部分只剩下一个元素 第二步:对相邻2组之间的数据进行归并 */ //打印数组 void Print(int * arr, int num){ if (arr == NULL) { printf("传入参数不可以为空! "); return; } int i = 0; for (int i = 0; i < num; i++) { printf("%5d", *(arr + i)); } printf(" "); } //归并排序--两组之间合并 /* src:第一个小数组的地址 srct:第二个小数组的地址 dec:归并后结果的数组地址 len1:第一个数组的长度 len2:第二个数组的长度 */ static void Merge(int * dec, int *src, int *srct, int len1, int len2) { int i = 0, m = 0, n = 0; while (m < len1&&n < len2) { //比较必须两组都有值,所以需要"m<len1 && n<len2"条件 if (src[m]<srct[n]) { dec[i++] = src[m++]; } else { dec[i++] = srct[n++]; } } //若还剩几个尾部元素 依次插入 while (m < len1) { dec[i++] = src[m++]; } while (n < len2) { dec[i++] = srct[n++]; } } //递归分组算法 /* @arr:既做输入,又做输出 */ static void MSort(int *arr, int len) { //当数组元素为1,,说明只剩下一个元素 if (len==1) { return; } //两个分组的长度 int len1 = 0,len2=0; //根据数组长度的奇偶性,确定被拆分数组的长度 int flag = len % 2 == 0 ? 0 : 1; if (flag==0) { len1 = len2 = len/2; } else { len1 = len / 2; len2 = len / 2+1; } //分配拆分数组的内存空间 int *temparr1 = (int *)malloc(sizeof(int)*len1); if (temparr1==NULL) { printf("malloc() failed "); return; } memset(temparr1, 0, sizeof(int)*len1); int *temparr2 = (int *)malloc(sizeof(int)*len2); if (temparr2 == NULL) { printf("malloc() failed "); return; } memset(temparr2, 0, sizeof(int)*len2); //数据拆分 int i = 0,m=0,n=0; for (i = 0; i < len; i++) { if (i<len1) { temparr1[m++] = arr[i]; } else { temparr2[n++] = arr[i]; } } //递归分组 MSort(temparr1, len1); MSort(temparr2, len2); //组合数据 Merge(arr, temparr1, temparr2, len1, len2); //释放内存 free(temparr1); free(temparr2); } void Test(){ int i = 0; int arr[10] = { 0 }; //定义时间类型变量 time_t ts; //生成随机数种子 srand((unsigned int)time(&ts)); for (i = 0; i < 10; i++) { arr[i] = (int)(rand() % 100); } //打印数组 printf(" 原始数据---- "); Print(arr, 10); MSort(arr, 10); Print(arr, 10); } void main(){ Test(); system("pause"); }
//排序--归并排序法 #include<stdio.h> #include<stdlib.h> #include<string.h> #include<time.h> /* 归并排序步骤: 第一步;将一组数据分成2部分,然后递归的继续将这2部分数据划分成4部分,直接每个部分只剩下一个数组 第二步:对相邻2组之间的数据进行归并 */ //打印数组 void Print(int * arr, int num){ if (arr == NULL) { printf("传入参数不可以为空! "); return; } int i = 0; for (int i = 0; i < num; i++) { printf("%5d", *(arr + i)); } printf(" "); } //归并排序--两组之间合并 /* src:第一个小数组的地址 srct:第二个小数组的地址 dec:归并后结果的数组地址 len1:第一个数组的长度 len2:第二个数组的长度 */ void Merge(int * src, int *srct, int *dec, int len1, int len2){ int i = 0, j = 0,k=0; //注意 这里使用的是“&&” 因为只需要一个数组插入完成 另一个数组依次插入返回数组后面即可 while (i <len1 && j <len2){ if (src[i]<srct[j]) { dec[k++] = src[i++]; } else{ dec[k++] = srct[j++]; } } //若还剩几个尾部元素 依次插入 while (i < len1){ dec[k++] = src[i++]; } //若还剩几个尾部元素 依次插入 while (j < len2){ dec[k++] = srct[j++]; } } //归并排序--分组 void MSort(int * src,int *dec,int low,int high){ if (low == high) { //说明只有一个元素 不用排序了 直接把原始数据 放置到新数组中 dec[0] = src[low]; return; } //将原始数组元素一分为二 //注意 将数组分割成2部分 中间元素的下标是 (high+low) / 2 不是 (high-low) / 2 //假设 下标是3,和下标5 中间的下标应该是4 int mid = (high+low) / 2; //第一组的长度 int m = mid - low + 1; //第二组的长度 int n = high - (mid + 1) + 1; /* 开辟两个数组空间 分别存放被分开的2组元素 */ int * space = (int *)malloc(sizeof(int)*m); if (space==NULL) { printf("开辟内存空间失败! "); return; } //初始化 memset(space, 0, sizeof(int)*m); int * spacet = (int *)malloc(sizeof(int)*n); if (spacet == NULL) { printf("开辟内存空间失败! "); return; } //初始化 memset(spacet, 0, sizeof(int)*n); //递归调用 直至将数组元素变成1个为止 MSort(src, space,low, mid); MSort(src, spacet, mid + 1, high); //归并排序 dec是由上一层函数分配的内存 Merge(space, spacet, dec, m, n); free(space); free(spacet); } void Test(){ int i = 0; int arr[10] = { 0 }; int relt[10] = { 0 }; //定义时间类型变量 time_t ts; //生成随机数种子 srand((unsigned int)time(&ts)); for (i = 0; i < 10; i++) { arr[i] = (int)(rand() % 100); } //打印数组 printf(" 原始数据---- "); Print(arr, 10); //归并法排序 printf("归并法排序之后的数据 "); /* 这里作为返回的数组,为什么可以传本身呢? 因为归并的数据都是放在临时创建的内存空间里,并没有破坏原来的数据 最后一次归并 是将临时内存空间里的数据覆盖了原来的内存空间 0是数组的最小下标 9是数组的最大下标 */ MSort(arr, arr, 0, 9); Print(arr, 10); } void main(){ Test(); system("pause"); }