目录
编辑
排序的概念
常见排序算法
编辑
1.冒泡排序
🍹图解
🥳代码实现
🤔时间复杂度
2.插入排序
🍹图解
🌴深度剖析
🍎代码思路
🥳代码实现
🤔时间复杂度
3.希尔排序
🌴深度剖析
🍎代码思路
🍋思考:关于gap的取值问题
🥳代码实现
🤔时间复杂度
4.堆排序
⛱️请看我的另一篇文章:详解堆排序
5.选择排序
🍹图解
🌴深度剖析
🥳代码实现
🤔时间复杂度
6.快速排序
🍹图解1:霍尔法
🌴深度剖析
🍎代码思路
🍎优化1:改变选key策略,采用三数选中法
🍎优化2:小区间优化,采用其它排序方法,减少递归次数
🍋思考:如何保证相遇位置比key小?
🥳代码实现
🍹图解2:前后指针法
🌴深度剖析
🍎代码思路
🍎优化:避免自己和自己交换
🥳代码实现
🍹非递归实现
🍎代码思路
🥳代码实现
7.归并排序
🍹图解
🌴深度剖析
🍹递归版
🍎代码思路
🥳代码实现
🍹非递归版
🍎代码思路
🍋思考:上面的思路只能解决数组大小为的数组,其余数组则会存在越界问题,如何解决?
🥳代码实现
🤔时间复杂度
排序的概念
排序 :所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。稳定性 :假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中, r[i]=r[j] ,且 r[i] 在 r[j] 之前,而在排序后的序列中, r[i] 仍在 r[j] 之前,则称这种排序算法是稳定的;否则称为不稳定的。内部排序 :数据元素全部放在内存中的排序。外部排序 :数据元素太多不能同时放在内存中,根据排序过程的要求不断地在内外存之间移动数据的排序。
常见排序算法
下文将会细细介绍上图中七种排序,观看前,可以点一个免费的赞与收藏支持作者~希望本篇博客能帮助到你!
1.冒泡排序
相邻两个数进行比较,大的数向后移,每次循环都能冒出一个大的数到数组最后,直至最后全部冒出。
🍹图解
🥳代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void bubble_sort(int arr[],int sz)
{
int flag = 1;//优化
int i = 0;
for (i = 0; i < sz - 1; i++) {
int j = 0;
for (j = 0; j < sz - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
flag = 0;
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
if (flag == 1) {
break;
}
}
}
int main() {
int n = 0;
int arr[] = {2,6,9,3,6,9,1};
int sz = sizeof(arr) / sizeof(arr[0]);
bubble_sort(arr, sz);
for (n = 0; n < sz - 1; n++) {
printf("%d", arr[n]);
}
return 0;
}
🤔时间复杂度
O(N^2)
2.插入排序
🍹图解
🌴深度剖析
🍎代码思路
上图为基本的插入排序,可对其进行优化:依次遍历找出最大值和最小值索引。
代码思路:1.设变量mini,maxi分别为最小值和最大值索引
设begin,end分别无序部分的首尾索引。
2.遍历无序部分,找出最小值和最大值的索引mini,maxi
3.将a[begin]和a[mini]进行交换,将a[end]和a[maxi]进行交换
注意:两次交换的中间需要进行依次判断,判断maxi是否仍然等于begin,因为经过第一个交换后原begin位置的值已经交换到mini位置去了,如果判断成立,maxi也应该跟随原begin的值的移动移动到mini位置。
4.此时begin、end处已经属于有序部分,begin++,end--,,更新无序部分的范围。
5.对剩余无序部分重复上述步骤,直到begin==end。
🥳代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void selectsort(int* a, int n) {
int begin = 0;
int end = n - 1;
while (begin < end) {
int mini = begin;
int maxi = begin;
//找最大值最小值的索引
for (int i = begin + 1; i <= end; i++) {
if (a[i] < a[mini]) {
mini = i;
}
if (a[i] > a[maxi]) {
maxi = i;
}
}
//进行交换
swap(&a[mini], &a[begin]);
if (maxi == begin)//begin此时被mini换走了
maxi = mini;
swap(&a[maxi], &a[end]);
begin++;
end--;
}
}
int main() {
int a1[8] = { 9,1,2,5,7,4,6,3};
selectsort(a1,8);
//int a2[5] = { 3,2,5,6,7 };
//selectsort(a2, 5);
for (int i = 0; i < 8; i++) {
printf("%d ", a1[i]);
}
return 0;
}
🤔时间复杂度
O(N^2)
3.希尔排序
🌴深度剖析
🍎代码思路
希尔排序是在插入排序的基础上进行优化的。
1.预排序:将数组分为gap组,进行预排序(让数组接近有序)
2.插入排序(此时,数组近乎有序,使用插入排序效率极高)
即蓝色的为一组,红色的为一组,绿色为一组,对每组进行插入排序
以下是预排序的代码:
//预排序过程,假设gap=3
//第一种写法:依次对三组进行预排序
for(int j=0;j<gap;j++){ //依次对三组进行预排序
for (int i = gap; i < n; i+=gap) { //对一组进行预排序的过程,由于一组内部元素之间相距gap,所以应该是i+=gap
int end = i;
int tmp = a[end];
while (end >= gap) {
if (tmp < a[end - gap]) {
a[end] = a[end - gap];
a[end - gap] = tmp;
end -= gap;
}
else {
break;
}
}
}
//第二种写法:同时进行三组的预排序(但效率相较上一种写法其实没有改变)
for (int i = gap; i < n; i++) {//先对蓝组排1下,再对红组排1下,再对绿组排1下,如此循环
int end = i;
int tmp = a[end];
while (end >= gap) {
if (tmp < a[end - gap]) {
a[end] = a[end - gap];
a[end - gap] = tmp;
end -= gap;
}
else {
break;
}
}
🍋思考:关于gap的取值问题
gap越大:大的数字越快跳到后面,小的数字越快跳到前面,结果越不接近有序。
gap越小:跳得越慢,但结果越接近有序(gap==1时,相当于插入排序)
解决方案:走多组gap,gap>1时就是预排序
gap==1时就是插入排序
gap我们通常设置为gap=gap/3+1
这里+1是为了保证gap>=1。
🥳代码实现
//1.预排序,分成gap组进行
//2.插入排序
void ShellSort(int* a, int n) {
int gap = n;
while (gap>1) {
gap = gap / 3 + 1;//保证gap>=1
for (int i = gap; i < n; i++) {
int end = i;
int tmp = a[end];
while (end >= gap) {
if (tmp < a[end - gap]) {
a[end] = a[end - gap];
a[end - gap] = tmp;
end -= gap;
}
else {
break;
}
}
}
}
}
🤔时间复杂度
4.堆排序
⛱️
请看我的另一篇文章:详解堆排序
5.选择排序
🍹图解
🌴深度剖析
基本思路:遍历一遍,选择最小的插到最左边
优化思路:遍历一遍,选出最小的最大的分别插到最左最右
一个小坑:将最大值放到最后后,可能破坏了原本的
🥳代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void selectsort(int* a, int n) {
int begin = 0;
int end = n-1 ;
while (begin < end) {
int mini = a[begin];
int maxi = a[end];
for (int i = begin; i <= end; i++) {
if (a[i] < mini) {
mini = a[i];
swap(&a[i], &a[begin]);
}
if(a[i]>maxi) {
maxi = a[i];
swap(&a[i], &a[end]);
}
//验证
if (a[i] <= mini) {
mini = a[i];
swap(&a[i], &a[begin]);
}
}
begin++;
end--;
}
}
int main() {
int a1[8] = { 9,1,2,5,7,4,6,3};
selectsort(a1,8);
//int a2[5] = { 3,2,5,6,7 };
//selectsort(a2, 5);
for (int i = 0; i < 8; i++) {
printf("%d ", a1[i]);
}
return 0;
}
🤔时间复杂度
O(N^2)
6.快速排序
🍹图解1:霍尔法
🌴深度剖析
🍎代码思路
我们先考虑单趟:
end,begin相遇前:end向前走找比key小的值,begin向后走找比key大的值,都找到后两者进行交换
end,begin相遇时:循环停止,交换begin和key
单趟过后的结果:
key所在位置一定是正确的位置,[left,key-1]中的值一定小于key,[key+1,right]中的值一定大于key
//单趟(一定先走end,再走begin)
int begin = left;
int end = right;
int key = left;
while (begin < end) {
while (a[end] >= a[key] && begin < end) {
end--;
}
while(a[begin] <= a[key]&&begin<end) {
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
key = begin;
此时整个数组可以划分为三个部分:[left,key-1],key, [key+1,right]
递归:接着就用递归思想对[left,key-1],[key+1,right]中的值进行排序
递归结束条件:数组不存在或者只有1个元素
🍎优化1:改变选key策略,采用三数选中法
当数组有序排列时,且数据量较大时,基础版快排可能出现栈溢出问题。
解决办法:改变选key的策略,采用三数选中的方法,使key不要老是为最小值,而尽量趋于中值。
即确定出三个索引,如left,right, (right-left)/2,选出三个索引对应的值为中值的索引。
//优化1:改变选key的策略,采用三数选中法
int FindMid(int* a, int left, int right) {
int mid = (left + right) / 2;
if (a[left] < a[right]) {
if (a[left] < a[mid]) {
if (a[mid] < a[right]) {//a[left]<a[mid]<a[right]
return mid;
}
else {//a[left]<a[right]<a[mid]
return right;
}
}
else {//a[mid]<a[left]<a[right]
return left;
}
}
else {//a[left] > a[right]
if (a[mid] > a[right]) {
if (a[mid] > a[left]) {//a[mid] > a[left]> a[right]
return left;
}
else {
return mid;
}
}
else {//a[left] > a[right]>a[mid]
return right;
}
}
}
🍎优化2:小区间优化,采用其它排序方法,减少递归次数
冒泡排序、选择排序效率太一般,希尔排序更适合处理数据量更大的数据,此时的数据已经较为接近有序,此处采用插入排序。
//优化:小数区间,采取选择排序
if (left + 5 >= right) {
InsertSort(a+left, right - left + 1);
return;
}
🍋思考:如何保证相遇位置比key小?
左边做key,右边先走,可以保证相遇位置比key小。
相遇场景分析:
begin遇end:end先走,停下来,一定是因为遇到了比key小的值。
begin再走,begin没有找到大的遇到end就停下了。
end遇begin:end走,end没有找到小的遇到begin就停下了。
而begin的位置此时还是上一轮交换的位置,而上一轮交换,把比key小的值换到了begin的位置。
🥳代码实现
1.基础版(递归)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//递归版
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void QuickSort(int* a, int left, int right) {
//先考虑单趟
//end找比key小,begin找比key大,都找到后交换
//end,begin相遇时停止,交换begin和key
//单趟过后的结果:key所在位置一定是正确的位置,a[left,key-1]一定小于key,a[key+1,right]一定大于key
//接着就用递归思想处理:a[left,key-1],a[key+1,right]
//递归结束条件:数组不存在或者只有1个元素
if (left >= right) {
return;
}
int begin = left;
int end = right;
int key = left;
while (begin < end) {
while (a[end] >= a[key] && begin < end) {
end--;
}
while(a[begin] <= a[key]&&begin<end) {
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
key = begin;//此时key需要改变
QuickSort(a, left, key-1);
QuickSort(a, key + 1, right);
}
int main() {
int a[10]={ 6, 1, 2, 7, 9, 3, 4, 5, 10,8 };
QuickSort(a, 0, 9);
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
return 0;
}
2.优化版(递归)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//递归版
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
//优化1:改变选key的策略,采用三数选中法
int FindMid(int* a, int left, int right) {
int mid = (left + right) / 2;
if (a[left] < a[right]) {
if (a[left] < a[mid]) {
if (a[mid] < a[right]) {//a[left]<a[mid]<a[right]
return mid;
}
else {//a[left]<a[right]<a[mid]
return right;
}
}
else {//a[mid]<a[left]<a[right]
return left;
}
}
else {//a[left] > a[right]
if (a[mid] > a[right]) {
if (a[mid] > a[left]) {//a[mid] > a[left]> a[right]
return left;
}
else {
return mid;
}
}
else {//a[left] > a[right]>a[mid]
return right;
}
}
}
void InsertSort(int* a, int n) {
for (int i = 1; i < n ; i++) {
int end = i;
int tmp = a[end];
while (end > 0) {
if (tmp < a[end - 1]) {
a[end] = a[end - 1];
a[end - 1] = tmp;
end--;
}
else {
break;
}
}
}
}
void QuickSort(int* a, int left, int right){
//先考虑单趟
//end找比key小,begin找比key大,都找到后交换
//end,begin相遇时停止,交换begin和key
//单趟过后的结果:key所在位置一定是正确的位置,a[left,key-1]一定小于key,a[key+1,right]一定大于key
//接着就用递归思想处理:a[left,key-1],a[key+1,right]
//递归结束条件:数组不存在或者只有1个元素
/*if (left >= right) {
return;
}*/
//优化:小数区间,采取选择排序
if (left + 5 >= right) {
InsertSort(a+left, right - left + 1);
return;
}
int begin = left;
int end = right;
//优化:改变选key的策略,采用三数选中法
int key = FindMid(a+left, left, right);
Swap(&a[begin], &a[key]);
key = begin;
//int key = begin;
while (begin < end) {
while (a[end] >= a[key] && begin < end) {
end--;
}
while(a[begin] <= a[key]&&begin<end) {
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
key = begin;//此时key需要改变
QuickSort(a, left, key-1);
QuickSort(a, key + 1, right);
}
int main(){
int a[10]={ 6, 1, 2, 7, 9, 3, 4, 5, 10,8 };
QuickSort(a, 0, 9);
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
return 0;
}
🍹图解2:前后指针法
🌴深度剖析
🍎代码思路
仍然从单趟开始分析:
1.
2.判断cur指针指向的数据是否小于key:
小于——prev后移一位,交换cur和prev指向的内容,cur指针后移一位
大于——cur后移一位,效果:使得prev和cur之间的值全是大于key的值
3.当cur越界,将prev指向的内容与key进行呼唤
效果:key左边的数据都比key小,key右边的数据都比key大
由于快慢指针法单趟后的效果和霍尔法其实是一致的,后续步骤就和霍尔法的步骤一模一样。
🍎优化:避免自己和自己交换
if (a[cur] < a[key] && ++prev != cur) {//优化:当++prev与cur重叠时,就不进行交换
Swap(&a[cur], &a[prev]);
}
🥳代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
//优化1:改变选key的策略,采用三数选中法
int FindMid(int* a, int left, int right) {
int mid = (left + right) / 2;
if (a[left] < a[right]) {
if (a[left] < a[mid]) {
if (a[mid] < a[right]) {//a[left]<a[mid]<a[right]
return mid;
}
else {//a[left]<a[right]<a[mid]
return right;
}
}
else {//a[mid]<a[left]<a[right]
return left;
}
}
else {//a[left] > a[right]
if (a[mid] > a[right]) {
if (a[mid] > a[left]) {//a[mid] > a[left]> a[right]
return left;
}
else {
return mid;
}
}
else {//a[left] > a[right]>a[mid]
return right;
}
}
}
void InsertSort(int* a, int n) {
for (int i = 1; i < n; i++) {
int end = i;
int tmp = a[end];
while (end > 0) {
if (tmp < a[end - 1]) {
a[end] = a[end - 1];
a[end - 1] = tmp;
end--;
}
else {
break;
}
}
}
}
void QuickSort2(int* a, int left, int right) {
if (left + 5 >= right) {
InsertSort(a + left, right - left + 1);
return;
}
//优化:改变选key的策略,采用三数选中法
int key = FindMid(a + left, left, right);
Swap(&a[left], &a[key]);
key = left;
int prev = left;
int cur = left + 1;
while (cur <= right) {
if (a[cur] < a[key] && ++prev != cur) {//优化:当++prev与cur重叠时,就不进行交换
Swap(&a[cur], &a[prev]);
}
cur++;
}
Swap(&a[key], &a[prev]);
key = prev;//此时key需要改变
QuickSort2(a, left, key - 1);
QuickSort2(a, key + 1, right);
}
int main(){
int a[10] = { 6, 1, 2, 7, 9, 3, 4, 5, 10,8 };
QuickSort2(a, 0, 9);
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
return 0;
}
🍹非递归实现
🍎代码思路
利用栈来模拟递归的过程,假设每次key值都刚好二分。
1.初始化一个栈,将right和left压入栈中
1.对数组进行单趟快速排序,得到[left,key-1],key,[key+1,right]
2.设begin1=left,end1=key-1
设begin2=key+1,end2=right
3.若begin2<end2,将end2,begin2压入栈中
若begin1<end1,将end1,begin1压入栈中
4.取并删除栈顶元素两次,得到begin1,end1,对[begin1,end1]数组进行单趟快速排序
5.重复步骤2,3,4,栈为空时循环结束
.
🥳代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "stack.h"
void Swap(int* a, int* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
void QuickSort(int* a, int left, int right) {
Stack st;
StackInit(&st);
StackPush(&st, right);
StackPush(&st, left);
while (!StackEmpty(&st)) {
left = StackTop(&st);
StackPop(&st);
right = StackTop(&st);
StackPop(&st);
int begin = left;
int end = right;
int key = begin;
while (begin < end) {
while (a[end] >= a[key] && begin < end) {
end--;
}
while (a[begin] <= a[key] && begin < end) {
begin++;
}
Swap(&a[begin], &a[end]);
}
Swap(&a[begin], &a[key]);
key = begin;//此时key需要改变
int begin1 = left;
int end1 = key - 1;
int begin2 = key + 1;
int end2 = right;
if (begin2 < end2) {
StackPush(&st, end2);
StackPush(&st, begin2);
}
if (begin1 <end1) {
StackPush(&st, end1);
StackPush(&st, begin1);
}
}
StackDestroy(&st);
return;
}
int main() {
int a[10] = { 6, 1, 2, 7, 9, 3, 4, 5, 10,8 };
QuickSort(a, 0, 9);
for (int i = 0; i < 10; i++) {
printf("%d ", a[i]);
}
return 0;
}
7.归并排序
🍹图解
🌴深度剖析
基本思想:归并排序( MERGE-SORT )是建立在归并操作上的一种有效的排序算法 , 该算法是采用分治法 。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
🍹递归版
🍎代码思路
假设数组可以被拆分成两个子数组:
比较begin1和begin2位置的值,
取小尾插到tmp,
被取指针向前移动
未被取指针,不动
但问题是:数组往往不能直接被拆成两个有序数组
因此,考虑继续细分数组直到有序(比如只有1个数时必定有序)
然后将有序子数组一层层的合并回去,每次合并完将结果拷贝回原数组。
这个过程有点类似后序遍历。
🥳代码实现
void MergeSort1(int* a, int n) {
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL) {
perror("tmp malloc fail!");
return;
}
if (n <= 1) {//当数组被拆分成单个数,或无法继续拆分,返回
return;
}
int mid = (n+1)/ 2;//假设数组3个数,mid==2,
MergeSort1(a, mid);//[0,mid-1]有序
MergeSort1(a+mid, n-mid);//[mid,n-1]有序
//合并两个有序数组
int begin1 = 0;
int end1 = mid - 1;
int begin2 = mid;
int end2 = n - 1;
int tmp1 = 0;
while (begin1 <=end1 && begin2 <= end2) {
if (a[begin1] < a[begin2]) {//begin1的数比begin2小,尾插begin1
tmp[tmp1] = a[begin1];
begin1++;
tmp1++;
}
else {
tmp[tmp1] = a[begin2];
begin2++;
tmp1++;
}
}
//循环结束,说明有一方指针已经走完
//将另一方未走完指针走完
while (begin1 <=end1) {
tmp[tmp1] = a[begin1];
begin1++;
tmp1++;
}
while (begin2 <=end2) {
tmp[tmp1] = a[begin2];
begin2++;
tmp1++;
}
//此时的tmp数组为有序数组
//拷贝回原数组
memcpy(a, tmp, sizeof(int) * n);
}
🍹非递归版
🍎代码思路
1.首先设一个变量gap代表每组需要归并的个数。
2.划分两个大小为gap的子数组[begin1,end1],[begin2,end2],这两个数组应当是有序的,对其进行归并,归并完后,继续向后划分两个大小为gap的子数组,继续归并,直到整个数组被遍历完。
3.遍历完一次数组意味着以gap*2为大小的子数组已经有序,因此gap*=2,以新gap数,继续完成新一轮对数组的归并遍历。直到gap>=2,结束。
🍋思考:上面的思路只能解决数组大小为的数组,其余数组则会存在越界问题,如何解决?
这是一个数据个数为10的数组:
打印每轮的合并情况,可发现,有些位置发生了越界:
将图示越界的位置抽象出来,即为:
解决方案:
判断begin2是否存在,若不存在,则结束归并,若存在则修正end2,使其不越界。
🥳代码实现
void MergeSort2(int* a, int n) {
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL) {
perror("tmp malloc fail!");
return;
}
if (n <= 1) {//当数组被拆分成单个数,或无法继续拆分,返回
return;
}
//后序遍历
//合并两个有序数组
int gap = 1;//每组需要归并的个数
while(gap<n){//层序遍历
for(int i=0;i<n;i+=2*gap){
int begin1 = i;
int end1 = i+gap-1;
int begin2 = i+gap;
int end2 = i+2*gap-1;
int j = i;
if (begin2 >= n) {
break;
}
if (end2 >= n) {
end2 = n - 1;
}
while (begin1 <= end1 && begin2 <= end2) {
if (a[begin1] < a[begin2]) {//begin1的数比begin2小,尾插begin1
tmp[j++] = a[begin1];
begin1++;
}
else {
tmp[j++] = a[begin2];
begin2++;
}
}
//循环结束,说明有一方指针已经走完
//将另一方未走完指针走完
while (begin1 <= end1) {
tmp[j++] = a[begin1];
begin1++;
}
while (begin2 <= end2) {
tmp[j++] = a[begin2];
begin2++;
}
//此时的tmp数组为有序数组
//拷贝回原数组
memcpy(a+i, tmp+i, sizeof(int) * (end2-i+1));//易错点:(end2-begin1+1)是错的,因为begin1这个时候已经不再是子数组起点位置
}
gap *= 2;
}
}
int main() {
int a1[8] = { 10,6,7,1,3,9,4,2 };
int a2[16] = { 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1 };
int a3[12] = { 12,11,10,9,8,7,6,5,4,3,2,1 };
MergeSort2(a1, 8);
for (int i = 0; i < 8; i++) {
printf("%d ", a1[i]);
}
printf("\n");
MergeSort2(a2, 16);
for (int i = 0; i < 16; i++) {
printf("%d ", a2[i]);
}
MergeSort2(a3, 12);
printf("\n");
for (int i = 0; i < 12; i++) {
printf("%d ", a3[i]);
}
}
🤔时间复杂度
O(N*logN)