合并排序算法思想:
先将无序序列利用二分法划分为子序列,直至每个子序列只有一个元素(单个元素就是有序),然后再对有序子序列两两进行合并排序。
合并方法是循环地将两个有序子序列当前的首元素进行比较,较小的元素取出,置入合并序列(这就是合并排序O(n)的辅助空间花销的来源,建立了一个新的空数组来接收排好序的子序列)的左边空置位,直至所有元素置入合并序列
怎么划分就怎么合并!!!!
(截图自B站up主:请叫我AXin 的视频)
解释:
(0+8)/ 2 = 4 所以下标为4及左边的元素作为一个子数组,下标大于4的元素作为另一个子数组
同理,(0+4)/ 2 = 2 所以 下标为 0 1 2 的元素作为一个子数组,下标为3 4 的作为另一个子数组
(0+2)/ 2 = 1 所以 下标为 0 1 的元素作为一个子数组,下标为2的元素作为另一个子数组,因为这个子数组只有一个元素,所以他就是有序数组,等待合并就行。
(0+1)/ 2 = 0 所以下标为0 的元素作为一个子数组,下标为1 的又作为一个子数组,也划分完毕了。
右边的元素划分也同理。
都划分完毕后,就开始合并,怎么划分就怎么合并。
小的数就放前面,例如子数组2 5 9 和子数组 7 12:
一开始两个指针分别指向2,7。因为2<7,所以2拎出来,指到5,5<7,拎出来,指针继续走指到9,9>7,所以7拎出来,现在合并序列为 2 5 7,第一个子数组没数了,加入12,就排好了
#include <iostream>
using namespace std;
void Merge(int arr[], int left, int mid,int right)
{
int* B = new int[right - left + 1]; //开辟一个辅助空间接收排好序的元素
int i = left; //将两个子数组的首元素下标分别赋值给i和j
int j = mid + 1; //mid+1是右边子数组的首元素下标
int k = 0; //作为数组B的下标
while (i <= mid && j <= right)
{
if (arr[i] <= arr[j]) //较小者拎出来
{
B[k++] = arr[i++]; //注意是后缀自增,先赋值再自增
}
else //这个就是右边的子数组的当前首元素较小的情况
{
B[k++] = arr[j++];
}
} //当任意一个子数组走完了,不管另一个走没走完,这个循环都结束了
while (i <= mid) //i还没到左边子数组的最右边,即还没走完,因为退出了循环,j所在的子数组肯定走完了,所以直接把i所在数组元素逐个添加就行
{
B[k++] = arr[i++];
}
while (j <= right) //同理,这是右边子数组还没走完的情况
{
B[k++] = arr[j++];
}
for (int i = left, k = 0; i <= right; i++)
{
//因为B数组待会要释放掉,所以把B数组赋值给arr
arr[i] = B[k++];
}
delete[]B; //释放B数组空间
}
void MergeSort(int arr[], int left, int right) //用来分解数组的
{
if (left < right) //left!=right说明子数组还不止一个元素,需要继续递归调用
{
int mid = (left + right) / 2;
MergeSort(arr, left, mid);
MergeSort(arr, mid + 1, right);
Merge(arr, left, mid, right);
}
}
int main()
{
int arr[5] = { 5,1,8,3,9 };
MergeSort(arr, 0, 4); //数组作为形参时,传递的是地址。在函数中修改数组就相当于修改了原数组。
for (int i = 0; i < 5; i++)
{
cout << arr[i] << ' ';
}
return 0;
}
输出: 1 3 5 8 9