标签:new 完成 com lse 一段 递归循环 初始 util bsp
归并排序(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) 可用于链式结构,且不需要附加存储空间,但递归实现时仍需要开辟相应的递归工作栈
标签:new 完成 com lse 一段 递归循环 初始 util bsp
原文地址:https://www.cnblogs.com/huxiaoyang/p/12058011.html