目录
归并排序
一、简介:
二、思路
三、代码
归并排序
一、简介:
归并,也叫合并,合二为一嘛,归并排序实际上相当于二叉树递归,先左右拆分,最后给数组拆分为每个数据为独立个体,再执行合并操作。
时间复杂度:O()-----口令:快(快速排序)以归(归并排序)队(堆排序)
空间复杂度:O(n)因为需要临时数组几个数据,临时数组大小就是几个。口令--饿鬼(归并)炸鸡(基数排序)块
稳定性:稳定,因为归并的时候,优先归并前面那个范围的,相对位置不贵发生改变,
口令--稳稳的幸福,鸡(基数排序)毛(冒泡排序)插(直接插入和折半插入排序)龟(归并排序)壳
排序趟数:对N个元素进行K路归并,排序排序趟数t等于t=向上取整。
移动次数:N个元素,进行k路归并,移动元素个数为:N*
二、思路
归并排序主要分为两步:第一步,给数组左右拆分;第二步两两合并
第一步,给数组左右拆分:
- 给数组传进两个标记,表示数组范围,分别为low和high
- 当low<high时,计算mid中间标记,这样就给一个数组分为两个数组了mid为中间点
- 然后进入递归,左边递归数组范围时low和mid右边递归范围时mid+1和high。
- 就这样层层递归,递归到最后,每个数据都成叶子结点了,再执行归并操作,但一个元素时肯定有序,所以返回倒数第二层,执行归并操作,依次往上返。
- 步骤如图所示,但是,原理是图中从最下层开始递归,然后递归到最后,都递归成叶子结点了,返回倒数第二层开始第一次归并操作,开始两两合并,选大小。
第二步两两合并:
- 叶子结点时,归并操作没用,因为只有一个元素,肯定有序,因此往倒数第二层返回,执行倒数第二层的归并操作。
- 归并时,我们是传了三个坐标,low,mid和high。
- 先创建个临时数组,给原数组的数值复制进去,用来对比最大或最小值,
- 再定义一个实际坐标,指向实际数组中要存放的位置,
- 就这个要存放的位置,来个循环,每次循环的时候,进行low到mid这个范围和mid+1到high这个范围进行比对,然后二选一存放值。
- 如果最后两两没法对比了,再给剩下的都放进实际数组即可
三、代码
#include <stdio.h>
#include <malloc.h>
void PrintSort(int *a,int len)
{
int i=0;
for(i=0;i<len;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
void Merge(int *a,int low,int mid,int high)
{
int *b=(int*)malloc((high+1)*sizeof(int));
int i;
for(i=low;i<=high;i++)
{
b[i]=a[i];//临时数组,存进去值,用来取值比较。
}
//k为a数组实际指向的箭头
int k=low;
//用p,q两个箭头分别指向b数组中两个紧挨着的有序数组,然后判断谁打谁小,随后给a[k]重新赋值
int p,q;
//两数组对比,然后选出一个,赋值到a中,随后k++,a数组换下一个坐标接着重复 步骤
for(p=low,q=mid+1,k=low;p<=mid&&q<=high;k++)
{
//在临时数组b中进行对比选择,最后赋值到实际数组a中
if(b[p]<=b[q])
{
a[k]=b[p];
p++;
}
else
{
a[k]=b[q];
q++;
}
}
//如果对比完,还有一个数组没有对比完,接着往后赋值即可。
while(p<=mid)
{
a[k]=b[p];
k++;
p++;
}
while(q<=high)
{
a[k]=b[q];
k++;
q++;
}
}
void MergeSort(int *a,int low,int high)
{
//归并排序是个递归过程,先从整体表,慢慢拆分
//拆分成每个数据是个整体时,再执行归并操作
//两个合并成一个,依次往回返回
if(low<high)
{
int mid =(low+high)/2;
MergeSort(a,low,mid);
MergeSort(a,mid+1,high);
Merge(a,low,mid,high);
}
}
int main()
{
int a[7]={49,38,65,97,76,13,27};
MergeSort(a,0,6);
PrintSort(a,7);
return 0;
}