归并排序是一种基于分治法的一种排序方法。它将要排序的序列分成两个长度相等的子序列,为每一个子序列进行排序,然后再将子序列合并成一个有序的序列。
实现:
////////////////////////////////////////////////////////////
//归并排序
//时间复杂度:O(N * logN)
//空间复杂度:O(N)
//稳定性:稳定排序
////////////////////////////////////////////////////////////
//第一个区间:[beg, mid)
//第二个区间:[mid, end)
void _MergeArray(int array[], int64_t beg, int64_t mid, int64_t end, int* tmp){
int64_t cur1 = beg;
int64_t cur2 = mid;
int64_t tmp_index = beg;
while(cur1 < mid && cur2 < end){
if(array[cur1] < array[cur2]){
tmp[tmp_index++] = array[cur1++];
}else{
tmp[tmp_index++] = array[cur2++];
}
}
if(cur1 < mid){
while(cur1 < mid){
tmp[tmp_index++] = array[cur1++];
}
}else{
while(cur2 < end){
tmp[tmp_index++] = array[cur2++];
}
}
while(cur1 < mid){
tmp[tmp_index++] = array[cur1++];
}
while(cur2 < end){
tmp[tmp_index++] = array[cur2++];
}
memcpy(array + beg, tmp + beg, sizeof(int) * (end - beg));
}
void _MergeSort(int array[], int64_t beg, int64_t end, int* tmp){
if(end - beg <= 1){
return;
}
int64_t mid = beg + (end - beg) / 2;
_MergeSort(array, beg, mid, tmp);
_MergeSort(array, mid, end, tmp);
//先保证左右区间均为有序区间后,才能进行合并
_MergeArray(array, beg, mid, end, tmp);
}
void MergeSort(int array[], int64_t size){
int* tmp = (int*)malloc(sizeof(int) * size);
//[0, size)
_MergeSort(array, 0, size, tmp);
free(tmp);
}
//归并排序的非递归版本
void MergeSortByLoop(int array[], int64_t size){
if(size <= 1){
return;
}
int* tmp = (int*)malloc(sizeof(int) * size);
int64_t gap = 1;
for(; gap < size; gap *= 2){
int64_t i = 0;
for(; i < size; i += gap * 2){
//每次循环其实就是在处理两个相邻的区间
int64_t beg = i;
int64_t mid = i + gap;
int64_t end = i + 2 * gap;
if(mid > size){
mid = size;
}
if(end > size){
end = size;
}
//[beg, mid),[mid, end)
_MergeArray(array, beg, mid, end, tmp);
}
}
free(tmp);
}
优化:
当划分的子区间的元素小于13个元素左右时,再使用归并的话会效率不会很高,相当于多增加了二叉树的后面几层的结点。这时候我们改用直接插入排序来进行优化。
void _MergeArray(int array[], int64_t beg, int64_t mid, int64_t end, int* tmp){
int64_t cur1 = beg;
int64_t cur2 = mid;
int64_t tmp_index = beg;
while(cur1 < mid && cur2 < end){
if(array[cur1] < array[cur2]){
tmp[tmp_index++] = array[cur1++];
}else{
tmp[tmp_index++] = array[cur2++];
}
}
if(cur1 < mid){
while(cur1 < mid){
tmp[tmp_index++] = array[cur1++];
}
}else{
while(cur2 < end){
tmp[tmp_index++] = array[cur2++];
}
}
while(cur1 < mid){
tmp[tmp_index++] = array[cur1++];
}
while(cur2 < end){
tmp[tmp_index++] = array[cur2++];
}
memcpy(array + beg, tmp + beg, sizeof(int) * (end - beg));
}
void _MergeSort(int array[], int64_t beg, int64_t end, int* tmp){
if(end - beg <= 1){
return;
}
int64_t mid = beg + (end - beg) / 2;
if(begin < mid){
if(mid - begin > 13){
_MergeSort(array, beg, mid, tmp);
}
else{
InsertSort(array + beg, end - beg + 1);
}
}
if(mid + 1 < end){
if(end - mid - 1 > 13){
_MergeSort(array, mid, end, tmp);
}
else{
InsertSort(array + mid + 1, end - mid);
}
}
//先保证左右区间均为有序区间后,才能进行合并
_MergeArray(array, beg, mid, end, tmp);
}
void MergeSort(int array[], int64_t size){
int* tmp = (int*)malloc(sizeof(int) * size);
//[0, size)
_MergeSort(array, 0, size, tmp);
free(tmp);
}