归并排序

 归并排序(Merge Sort)是建立在归并操作上的一种有效、稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

  归并操作的工作原理如下:
    第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;
    第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置;
    第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置。
    重复步骤3直到某一指针超出序列尾,将另一序列剩下的所有元素直接复制到合并序列尾。

例如: 使用归并排序算法将数组 { 9,5,2,7,12,4,3,1,11 } 进行升序排序。

 

 

归并排序算法 java 归并排序算法c语言_归并排序算法 java

 代码如下:

#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]前面。则这个排序算法是稳定的!