归并排序
归并排序(Merge Sort)是建立在归并操作上的一种有效、稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
归并操作的工作原理如下:
第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置;
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾。
例如: 使用归并排序算法将数组 { 9,5,2,7,12,4,3,1,11 } 进行升序排序。
代码如下:
#include<stdio.h>
#include<assert.h>
#include<stdlib.h> //分配内存
//分治 递归
//辅助函数:打印数组
void printf_arr(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%d", arr[i]);
}
putchar('\n');
}
//合并函数
void merge(int arr[], int tempArr[], int left, int mid, int right)
{
//标记左半区第一个未排序的元素
int l_pos = left;
//标记右半区第一个未排序的元素
int r_pos = mid + 1;
//临时数组元素的下标
int pos = left;
//合并
while (l_pos <= mid && r_pos <= right)
{
if (arr[l_pos] < arr[r_pos]) //左半区第一个剩余元素更小
tempArr[pos++] = arr[l_pos++];
else //右半区第一个剩余元素更小
tempArr[pos++] = arr[l_pos++];
}
//合并左半区剩余的的元素
while (l_pos <= mid)
tempArr[pos++] = arr[l_pos++];
//合并右半区剩余的的元素
while (r_pos <= right)
{
arr[left] = tempArr[left];
left++;
}
//把临时数组中合并后的元素复制回原来的数组
while (left <= right)
{
arr[left] = tempArr[left];
left++;
}
}
//归并排序
void msort(int arr[], int tempArr[], int left, int right)
{
//如果只有一个元素 不需要继续划分
if (left < right)
{
//找中间点
int mid = (left + right) / 2;
//递归划分左半区域
msort(arr, tempArr, left, mid);
//递归划分右半区域
msort(arr, tempArr, mid + 1, right);
//合并已经排序的部分
merge(arr, tempArr, left, mid, right);
}
}
//归并排序入口
void merge_sort(int arr[], int n)
{
//分配一个辅助的数组
int* tempArr = (int*)malloc(n * sizeof(int));
if (tempArr) //分配成功
{
msort(arr, tempArr, 0, n - 1); //msort 划分和归并
free(tempArr);
}
else
{
printf("fail");
}
}
int main(int argc,char const* argv[])
{
int arr[] = { 9,5,2,7,12,4,3,1,11 };
int n = 9;
printf_arr(arr, n);
merge_sort(arr, n);
printf_arr(arr, n);
return 0;
}
归并排序介绍
将两个的有序数列合并成一个有序数列,我们称之为"归并"。
归并排序(Merge Sort)就是利用归并思想对数列进行排序。根据具体的实现,归并排序包括"从上往下"和"从下往上"2种方式。
归并排序的时间复杂度和稳定性
归并排序时间复杂度
归并排序的时间复杂度是O(N*lgN)。
假设被排序的数列中有N个数。遍历一趟的时间复杂度是O(N),需要遍历多少次呢?
归并排序的形式就是一棵二叉树,它需要遍历的次数就是二叉树的深度,而根据完全二叉树的可以得出它的时间复杂度是O(N*lgN)。
归并排序稳定性
归并排序是稳定的算法,它满足稳定算法的定义。
算法稳定性 -- 假设在数列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。则这个排序算法是稳定的!