歸併排序的根本原理是將一個序列先分成一個一個小序列,分別完成排序,然後再將小序列兩兩合併,直到全部合併完成即排序結束。代碼中也是使用這個思路,先將序列分成(n+1)/2個小序列,再慢慢合併,直到全部合併完成。
/* 合併序列,只用於合併相鄰序列 */
void merge_arr(int *nums,int arr1_start,int arr2_start,int end)
{
int len = end+1-arr1_start;
int *p_arr = (int*)malloc(len*sizeof(int));
int arr1_idx = arr1_start;
int arr2_idx = arr2_start;
for(int i = 0;i < len;)
{
if(arr1_idx >= arr2_start)
{
p_arr[i++] = nums[arr2_idx++];
}
else if(arr2_idx > end)
{
p_arr[i++] = nums[arr1_idx++];
}
else
{
if(nums[arr1_idx] < nums[arr2_idx])
{
p_arr[i++] = nums[arr1_idx++];
}
else
{
p_arr[i++] = nums[arr2_idx++];
}
}
}
memcpy(nums+arr1_start,p_arr,len*sizeof(int));
free(p_arr);
}
/*
* 歸併排序(merge sort)
* 1.將已有序的子序列合併,直到再無無序序列
* 實現原理:先將數列n分爲n/2個序列,並使每個序列有序
* 再將有序序列兩兩合併,直到全部合併完成排序結束
* 這裏都是將相鄰序列合併,方便合併序列的執行
*/
void merge_sort(int *nums, int len)
{
int step = 1; // 初始合併的步長爲2,後續依次乘2,直到長度大於數列長度結束
int idx = 0;
while(step < len)
{
// 將已劃分的小序列排序
for(int i = 0;i < len;i+=step*2)
{
idx = i;
int arr2_start = idx+step;
int end = idx+step+step-1;
if(arr2_start > len)
{
break;
}
else if(end >= len)
{
merge_arr(nums,idx,arr2_start,len-1);
}
else
{
merge_arr(nums,idx,arr2_start,end);
}
}
step *= 2;
}
}