wulaxiaohei 2020-01-07
归并排序(Merging Sort)就是将两个或两个以上的有序表合并成一个有序表的过程。将两个有序表合并成一个有序表的过程称为2-路归并,2-路归并最为简单和常用。下面以2-路归并为例,介绍归并排序算法
假设初始序列含有n个记录,则可看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n/2]个长度为2或1的有序子序列;再两两归并,……,如此重复,直至得到一个长度为n的有序序列为止。
2-路归并排序的过程如图所示
2-路归并排序中的核心操作是,将待排序序列中前后相邻的两个有序序列归并为一个有序序列。
原理如下(假设序列共有n个元素):
1、将原始序列从中间分为左、右两个子序列,此时序列数为2
2、将左序列和右序列再分别从中间分为左、右两个子序列,此时序列数为4
3、重复以上步骤,直到每个子序列都只有一个元素,可认为每一个子序列都是有序的
4、最后依次进行归并操作,直到序列数变为1
代码实现
package com.hxy.sort; import java.util.Arrays; public class MergeSort1{ public static void main(String[] args) { int[] arr= {2,5,7,4,9,3,4,}; System.out.println("未排序前的顺序"); System.out.println(Arrays.toString(arr)); mergeSort(arr,new int[arr.length],0,arr.length-1); System.out.println("排序之后的顺序"); System.out.println(Arrays.toString(arr)); } public static void merge(int[] arr,int[] temp, int low , int mid, int high){ int i = low, j = mid+1; int k = 0; while(i<=mid&&j<=high){ if(arr[i]<=arr[j]){ temp[k]=arr[i]; k++; i++; }else{ temp[k]=arr[j]; k++; j++; } } //如果左边有剩余而右边已经添加完 直接把左边剩余的按着顺序添加到临时数组temp中 while (i<=mid){ temp[k]=arr[i]; k++; i++; } //如果右边有剩余而左边已经添加完 直接把右边剩余的按着顺序添加到临时数组temp中 while (j<=high){ temp[k]=arr[j]; k++; j++; } //将临时序列中有序的序列赋给原序列 for(int t = 0; t<k;t++){ arr[low+t]= temp[t]; } } public static void mergeSort(int[] arr, int[] temp ,int low ,int high){ if(low<high){ //将序列分为左右两部分 int mid = (low+high)/2; //将左边的序列进行归并排序 mergeSort(arr,temp,low,mid); //将右边的序列进行归并排序 mergeSort(arr,temp,mid+1,high); //将两段有序的序列合为一段有序的序列 merge(arr,temp,low,mid,high); } } }
原理如下(假设序列共有n个元素):
1、将序列每相邻两个数进行归并操作,形成ceil(n/2)个序列,排序后每个序列包含两/一个元素
2、将序列每相邻的两个有序子序列进行归并操作,形成ceil(n/4)个序列,每个序列包含四/三个元素
3、重复步骤2,直到所有元素排序完毕,即序列数为1个
void Merge(int*a,int low,int mid,int high) { inti=low,j=mid+1,k=0; int *temp=(int*)malloc((high-low+1)*sizeof(int)); while(i<=mid&&j<=high) a[i]<=a[j]?(temp[k++]=a[i++]):(temp[k++]=a[j++]); while(i<=mid) temp[k++]=a[i++]; while(j<=high) temp[k++]=a[j++]; memcpy(a+low,temp,(high-low+1)*sizeof(int)); free(temp); } void MergeSort(int*a,int n) { int length; for(length=1; length<n; length*=2) { int i; for(i=0; i+2*length-1<=n-1; i+=2*length) Merge(a,i,i+length-1,i+2*length-1); if(i+length<=n-1) Merge(a,i,i+length-1,n-1); } }
递归和迭代都是循环的一种。简单地说,递归是重复调用函数自身实现循环。迭代是函数内某段代码实现循环,而迭代与普通循环的区别是:循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。
递归循环中,遇到满足终止条件的情况时逐层返回来结束。迭代则使用计数器结束循环。当然很多情况都是多种循环混合采用,这要根据具体需求。
递归与迭代都是基于控制结构:迭代用重复结构,而递归用选择结构。 递归与迭代都涉及重复:迭代显式使用重复结构,而递归通过重复函数调用实现重复。 递归与迭代都涉及终止测试:迭代在循环条件失败时终止,递归在遇到基本情况时终止。 使用计数器控制重复的迭代和递归都逐渐到达终止点:迭代一直修改计数器,直到计数器值使循环条件失败;递归不断产生最初问题的简化副本,直到达到基本情况。迭代和递归过程都可以无限进行:如果循环条件测试永远不变成false,则迭代发生无限循环;如果递归永远无法回推到基本情况,则发生无穷递归。 递归函数是通过调用函数自身来完成任务,而且在每次调用自身时减少任务量。而迭代是循环的一种形式,这种循环不是由用户输入而控制,每次迭代步骤都必须将剩余的任务减少;.
①时间复杂度
当有n个记录时,需进行log2n趟归并排序,每一趟归并,其关键字比较 次数不超过n,元素移动次数都是n,因此归并排序的时间复杂度为O(nlog2n)
②
用顺序表实现归并排序时,需要和待排序记录个数相等的辅助存储空间,所以空间复杂度为O(n)
(1) 是稳定排序
(2) 可用于链式结构,且不需要附加存储空间,但递归实现时仍需要开辟相应的递归工作栈
排序是将一串数据按照其某个或者某些关键字的大小进行递增或递减排列的操作我,通常指的排序是升序,排序方式是原地排序。即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并