归并排序算法
- 格式:docx
- 大小:16.92 KB
- 文档页数:2
各种排序算法的作用和意义在计算机科学和数据处理领域,排序是一个基本而重要的问题。
排序算法是解决排序问题的一种方法,通过对数据进行重新排列,使其按照特定的顺序排列。
不同的排序算法有着不同的作用和意义,下面将介绍几种常见的排序算法及其作用和意义。
1. 冒泡排序算法冒泡排序是一种简单直观的排序算法,通过不断比较相邻的元素并交换位置,将最大的元素逐渐“冒泡”到最后。
冒泡排序的作用是将一个无序的序列转化为一个有序的序列,适用于数据量较小且基本有序的情况。
冒泡排序的意义在于其简单易懂的思想和实现方式,对于初学者来说是一个很好的入门算法。
2. 插入排序算法插入排序是一种简单直观的排序算法,通过构建有序序列,对于未排序的数据,在已排序序列中从后向前扫描,找到相应位置并插入。
插入排序的作用是将一个无序的序列转化为一个有序的序列,适用于数据量较小且基本有序的情况。
插入排序的意义在于其相对简单的实现和较好的性能,在某些特定情况下比其他排序算法更高效。
3. 选择排序算法选择排序是一种简单直观的排序算法,通过不断选择剩余元素中的最小值,并与未排序部分的第一个元素交换位置,将最小的元素逐渐放到已排序的部分。
选择排序的作用是将一个无序的序列转化为一个有序的序列,适用于数据量较小的情况。
选择排序的意义在于其简单直观的思想和实现方式,对于初学者来说是一个很好的入门算法。
4. 快速排序算法快速排序是一种高效的排序算法,通过选择一个基准元素,将序列分成两部分,一部分元素小于基准,一部分元素大于基准,然后递归地对两部分进行排序。
快速排序的作用是将一个无序的序列转化为一个有序的序列,适用于数据量较大的情况。
快速排序的意义在于其高效的性能和广泛应用,是一种常用的排序算法。
5. 归并排序算法归并排序是一种稳定的排序算法,通过将序列拆分成长度为1的子序列,然后逐步合并子序列,直到合并为一个有序序列。
归并排序的作用是将一个无序的序列转化为一个有序的序列,适用于数据量较大的情况。
归并排序的细节讲解与复杂度分析1.归并排序时间复杂度为O(N*logN),额外的空间复杂度O(N)。
2.递归⾏为:⼀个数组的排序,先将左侧部分排好序,然后将右侧部分排好序,最后整体利⽤外排序的⽅式整体排好。
3.归并排序:将两个(或者两个以上)有序表合并成⼀个新的有序表,即把待排序的序列分成若⼲个⼦序列,在把有序的⼦序列合并为整体有序的序列。
算法思路:归并排序的中⼼思想是将两个已经排好的序列,合并成⼀个排序的序列4.递归排序举例 (1)对于数组:[5,3,6,2,0,1] 序列可以分为:[5,3,6]和[2,0,1] (2)对上⾯的序列分别进⾏排序,结果为: [3,5,6]和[0,1,2] 然后将上⾯的两个序列合并为⼀个排好序的序列 合并的⽅法是:设置两个指针,分别指着两个序列的开始位置,如下所⽰ [3,5,6] [0,1,2] /|\ /|\ (3)开始的时候两个指针分别指向3和0,这时我们找到⼀个空数组,将3和0中较⼩的值复制进这个数组中,并作为第⼀个元素。
新数组: [0,,,,,,] (4)后⾯数组的指针后移⼀位,如下所⽰ [3,5,6] [0,1,2] /|\ /|\ 将1和3进⾏⽐较,1⼩于3,于是将1插⼊新数组:[0,1,.......] (5)后⾯数组的指针后移⼀位,如下所⽰ [3,5,6] [0,1,2] /|\ /|\ 将2和3进⾏⽐较,2⼩于3,于是将2插⼊新数组:[0,1,2,.......] (6)将剩余的左边已经有序的数组直接复制进⼊新数组中去,可以得到新数组:[0,1,2,3,5,6] (7)有master公式(递归公式):T(n)=2T(n/2)+O(N) 可以得出时间复杂度为:O(N*logN)5.java代码如下:import java.util.Arrays;public class MergeSort1 {public static void main(String[] args) {//先⽣成⼀个随机数组发⽣器int testTime = 500000;int maxSize =100;int maxValue=100;boolean succeed = true;for (int i = 0 ; i <testTime;i++){int[] arr1 = generateRandomArray(maxSize,maxValue);int[] arr2 = copyArray(arr1);mergeSort(arr1);comparator(arr2); //将数组arr2⽤⾃带的默认排序器进⾏排序if(!isEqual(arr1,arr2)){succeed=false;printArray(arr1);printArray(arr2);break;}}System.out.println(succeed?"Nice":"fucking fucked");int[] arr = generateRandomArray(maxSize,maxValue);printArray(arr);printArray(arr);}//testpublic static int[] generateRandomArray(int maxSize,int maxValue){int[] arr = new int[(int)((maxSize+1)*Math.random())]; //⽣成⼀个0到100维之间随机⼤⼩的数组for(int i =0 ; i<arr.length;i++){arr[i]=(int)((maxValue+1)*(Math.random()))-(int)((maxValue)*Math.random()); //⽣成两个0-100之间随机⼤⼩的整数,然后将两个整数相减 }return arr;}//testpublic static int[] copyArray(int[] arr){if(arr==null){return null;}int[] res = new int[arr.length];for(int i = 0 ;i <arr.length;i++){res[i]=arr[i];}return res;}//testpublic static void comparator(int[] arr){Arrays.sort(arr);}//testpublic static void printArray(int[] arr){if(arr==null){return;}for(int i = 0 ; i<arr.length;i++){System.out.print(arr[i]+"");}System.out.println();}//判断是否相等public static boolean isEqual(int[] arr1,int[] arr2){if((arr1==null&&arr2!=null)||(arr1!=null&&arr2==null)){return false;}if((arr1==null) && (arr2==null)){return true;}if(arr1.length!=arr2.length){return false;}for(int i =0 ; i <arr1.length;i++){if(arr1[i]!=arr2[i]){return false;}}return true;}public static void mergeSort(int[] arr){if(arr==null || arr.length<2 ){return;}mergeSort(arr,0,arr.length-1);}public static void mergeSort(int[] arr,int l, int r){if(l==r){return;}int mid = (l+r)/2;mergeSort(arr,l,mid);mergeSort(arr,mid+1,r);merge(arr,l,mid,r);}public static void merge(int[] arr, int l,int mid , int r) {int[] help= new int[r-l+1];int i =0 ;int p1= l ;int p2 = mid+1;while (p1<=mid&&p2<=r){help[i++] =arr[p1]<arr[p2]?arr[p1++]:arr[p2++];}while (p1<=mid){help[i++]=arr[p1++];}help[i++] = arr[p2++];}for(i = 0 ;i<help.length;i++){ arr[l+i]=help[i];}}}。
归并排序算法Matlab实现Matlab⼀段时间不⽤发现有些⽣疏了,就⽤归并排序来练⼿吧.代码没啥说的,百度有很多.写篇博客,主要是记下matlab语法,以后备查.测试代码srcData=[1,3,2,4,6,5,8,7,9];%测试数据dataSrcLength=length(srcData);%数据长度srcData2=diGuiMerge(srcData,1,dataSrcLength)%递归实现srcData1=dieDaiMerge(srcData)%迭代实现合并⾃函数M⽂件%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 说明:负责进⾏数据合并% 参数:% dataSrc 待处理的数据% left1 数据1的开始位置% right1 数据1的结束位置% left2 数据2的开始位置% right2 数据2的结束位置% 返回:合并后的数据 dataSrc%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function dataSrc=mergeSub(dataSrc,left1,right1,left2,right2)dataSrcLength=length(dataSrc);tempData=zeros(1,right2-left1+1);i=left1;j=left2;tempIndex=1;%进⾏数据合并while(1)if dataSrc(i)>=dataSrc(j)tempData(tempIndex)=dataSrc(i);i=i+1;tempIndex=tempIndex+1;elsetempData(tempIndex)=dataSrc(j);j=j+1;tempIndex=tempIndex+1;endif i>right1||i>dataSrcLengthbreak;endif j>right2||j>dataSrcLengthbreak;endend%查看左边数据是否还有剩下while(i<=right1&&i<=dataSrcLength)tempData(tempIndex)=dataSrc(i);i=i+1;tempIndex=tempIndex+1;end%查看右边数据是否还有剩下while(j<=right2&&j<=dataSrcLength)tempData(tempIndex)=dataSrc(j);j=j+1;tempIndex=tempIndex+1;end%把数据放回在原始数据中j=1;for i=left1:right2dataSrc(i)=tempData(j);j=j+1;if j>right2-left1+1break;endif j>dataSrcLengthbreak;endendend递归实现M⽂件%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 说明:归并排序的递归实现% 参数:% dataSrc 待处理的数据% startIndex 数据的开始位置% endIndex 数据的结束位置% 返回:排序后的数据 dataSrc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function srcData=diGuiMerge(srcData,startIndex,endIndex)%待排序的数据只有⼀个,则直接返回if endIndex-startIndex==0return;end%归并排序左半边数据srcData=diGuiMerge(srcData,1,floor((startIndex+endIndex)/2));%归并排序右半边数据srcData=diGuiMerge(srcData,floor((startIndex+endIndex)/2)+1,endIndex);%将两块数据合并srcData=mergeSub(srcData,1,floor((startIndex+endIndex)/2),floor((startIndex+endIndex)/2) +1,endIndex);end迭代实现M⽂件%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 说明:归并排序的迭代实现% 参数:% dataSrc 待处理的数据% 返回:排序后的数据 dataSrc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function srcData=dieDaiMerge(srcData)dataSrcLength=length(srcData);%数据长度lengthStep=1;%初始⼦排序长度while(1)%分步排序srcData=merge2Sub(srcData,lengthStep);if lengthStep*2>dataSrcLengthbreak;endlengthStep=lengthStep*2;endend %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 说明:归并排序的迭代实现的⼦函数% 参数:% dataSrc 待处理的数据% lengthStep 数据块长度% 返回:排序后的数据 dataSrc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%function dataSrc=merge2Sub(dataSrc,lengthStep)dataSrcLength=length(dataSrc);startIndex=1;startIndexEnd=startIndex+lengthStep-1;start2Index=startIndex+lengthStep;start2IndexEnd=start2Index+lengthStep-1;%合并指定长度的数据块while(1)dataSrc=mergeSub(dataSrc,startIndex,startIndexEnd,start2Index,start2IndexEnd);dataSrc=mergeSub(dataSrc,startIndex,startIndexEnd,start2Index,start2IndexEnd);startIndex=start2Index+lengthStep;startIndexEnd=startIndex+lengthStep-1;start2Index=startIndex+lengthStep;start2IndexEnd=start2Index+lengthStep-1;if startIndex>dataSrcLength||start2Index>dataSrcLengthbreak;endendend。
算法—4.归并排序(⾃顶向下)1.基本思想将两个有序的数组归并成⼀个更⼤的有序数组,很快⼈们就根据这个操作发明了⼀种简单的递归排序算法:归并排序。
要将⼀个数组排序,可以先(递归地)将它分成两半分别排序,然后将结果归并起来。
你将会看到,归并排序最吸引⼈的性质是它能够保证将任意长度为N的数组排序所需时间和NlogN成正⽐;它的主要缺点则是它所需的额外空间和N成正⽐。
简单的归并排序如下图所⽰:原地归并的抽象⽅法:实现归并的⼀种直截了当的办法是将两个不同的有序数组归并到第三个数组中,实现的⽅法很简单,创建⼀个适当⼤⼩的数组然后将两个输⼊数组中的元素⼀个个从⼩到⼤放⼊这个数组中。
public void merge(Comparable[] a, int lo, int mid, int hi){int i = lo, j = mid+1;//将a[lo..hi]复制到aux[lo..hi]for (int k = lo; k <= hi; k++) {aux[k] = a[k];}//归并回到a[lo..hi]for (int k = lo; k <= hi; k++) {if(i > mid){a[k] = aux[j++];}else if(j > hi){a[k] = aux[i++];}else if(less(aux[j], aux[i])){a[k] = aux[j++];}else{a[k] = aux[i++];}}}以上⽅法会将⼦数组a[lo..mid]和a[mid+1..hi]归并成⼀个有序的数组并将结果存放在a[lo..hi]中。
在归并时(第⼆个for循环)进⾏了4个条件判断:左半边⽤尽(取右半边的元素)、右半边⽤尽(取左半边的元素)、右半边的当前元素⼩于左半边的当前元素(取右半边的元素)以及右半边的当前元素⼤于等于左半边的当前元素(取左半边的元素)。
2.具体算法/*** ⾃顶向下的归并排序* @author huazhou**/public class Merge extends Model{private Comparable[] aux; //归并所需的辅助数组public void sort(Comparable[] a){System.out.println("Merge");aux = new Comparable[a.length]; //⼀次性分配空间sort(a, 0, a.length - 1);}//将数组a[lo..hi]排序private void sort(Comparable[] a, int lo, int hi){if(hi <= lo){return;}int mid = lo + (hi - lo)/2;sort(a, lo, mid); //将左半边排序sort(a, mid+1, hi); //将右半边排序merge(a, lo, mid, hi); //归并结果}} 此算法基于原地归并的抽象实现了另⼀种递归归并,这也是应⽤⾼效算法设计中分治思想的最典型的⼀个例⼦。
五种常见的排序方法在计算机科学中,排序是一种非常重要的操作,它可以将一组数据按照一定的顺序排列。
排序算法是计算机科学中最基本的算法之一,它的应用范围非常广泛,例如数据库查询、数据压缩、图像处理等。
本文将介绍五种常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序和归并排序。
一、冒泡排序冒泡排序是一种简单的排序算法,它的基本思想是将相邻的元素两两比较,如果前面的元素大于后面的元素,则交换它们的位置,一遍下来可以将最大的元素放在最后面。
重复这个过程,每次都可以确定一个最大的元素,直到所有的元素都排好序为止。
冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1)。
二、选择排序选择排序是一种简单的排序算法,它的基本思想是每次从未排序的元素中选择最小的元素,将它放到已排序的元素的末尾。
重复这个过程,直到所有的元素都排好序为止。
选择排序的时间复杂度为O(n^2),空间复杂度为O(1)。
三、插入排序插入排序是一种简单的排序算法,它的基本思想是将一个元素插入到已排序的元素中,使得插入后的序列仍然有序。
重复这个过程,直到所有的元素都排好序为止。
插入排序的时间复杂度为O(n^2),空间复杂度为O(1)。
四、快速排序快速排序是一种高效的排序算法,它的基本思想是选择一个基准元素,将序列分成两个子序列,其中一个子序列的所有元素都小于基准元素,另一个子序列的所有元素都大于基准元素。
然后递归地对这两个子序列进行排序。
快速排序的时间复杂度为O(nlogn),空间复杂度为O(logn)。
五、归并排序归并排序是一种高效的排序算法,它的基本思想是将序列分成两个子序列,然后递归地对这两个子序列进行排序,最后将这两个有序的子序列合并成一个有序的序列。
归并排序的时间复杂度为O(nlogn),空间复杂度为O(n)。
总结在实际的应用中,选择合适的排序算法非常重要,不同的排序算法有不同的优劣势。
冒泡排序、选择排序和插入排序是三种简单的排序算法,它们的时间复杂度都为O(n^2),在处理小规模的数据时比较适用。
一、实验目的1. 理解归并排序的基本思想和原理。
2. 掌握归并排序的实现方法。
3. 分析归并排序算法的时间复杂度。
4. 学会使用归并排序解决实际问题。
二、实验内容1. 归并排序的基本思想归并排序是一种基于分治策略的排序算法,其基本思想是将待排序的序列分成若干个子序列,分别对每个子序列进行排序,然后将排序好的子序列合并成一个有序序列。
具体步骤如下:(1)将待排序的序列分成两个子序列,分别进行排序;(2)将排序好的两个子序列合并成一个有序序列;(3)递归地对合并后的序列进行步骤(1)和(2)的操作,直到整个序列有序。
2. 归并排序的实现方法归并排序算法主要分为两个步骤:归并和合并。
(1)归并:将序列分为两个子序列,对每个子序列进行归并排序;(2)合并:将排序好的两个子序列合并成一个有序序列。
以下是归并排序的Python代码实现:```pythondef merge_sort(arr):if len(arr) <= 1:return arrmid = len(arr) // 2left = merge_sort(arr[:mid])right = merge_sort(arr[mid:])return merge(left, right)def merge(left, right):merged = []i = j = 0while i < len(left) and j < len(right):if left[i] < right[j]:merged.append(left[i])i += 1else:merged.append(right[j])j += 1merged.extend(left[i:])merged.extend(right[j:])return merged```3. 归并排序的时间复杂度分析归并排序算法的时间复杂度主要由归并操作和递归调用决定。
对于长度为n的序列,归并排序需要进行n-1次归并操作,每次归并操作需要比较n/2次,因此总的比较次数为(n/2) (n-1) = n^2/2。
⼆路归并排序算法将两个按值有序序列合并成⼀个按值有序序列,则称之为⼆路归并排序,下⾯有⾃底向上和⾃顶向下的两种排序算法,⾃顶向下的排序在本⽂末讲述,使⽤递归实现,代码较简洁,经供参考。
1. 归并⼦算法:把位置相邻的两个按值有序序列合并成⼀个按值有序序列。
例如把序列 X[s..u] = {3, 12, 23, 32}和序列 X[u+1..v] = {2, 5, 8, 99} 合并成序列Z[s..v] = {2, 3, 5, 8, 12, 23, 32, 99}, 注意合并前的元素都位于同⼀个有序序列的相邻位置,合并后的有序序列的下标与合并前的序列总的起始下标相同。
算法过程中需要三个整型变量,i ⽤来遍历归并的前⼀个有序序列,其初始位置是s;j ⽤来遍历归并的后⼀个有序序列,其初始值是u+1;q ⽤来指出归并后得到的有序序列的末尾元素的位置,其初始值是s。
当遍历完成其中的⼀个有序序列之后,只需把另⼀个未结束有序序列的剩余元素复制到合并后的有序序列的末尾。
看代码:[cpp]1. //将有序的X[s..u]和X[u+1..v]归并为有序的Z[s..v]2. void merge(int X[], int Z[], int s, int u, int v)3. {4. int i, j, q;5. i = s;6. j = u + 1;7. q = s;8.9. while( i <= u && j<= v )10. {11. if( X[i] <= X[j] )12. Z[q++] = X[i++];13. else14. Z[q++] = X[j++];15. }16.17. while( i <= u ) //将X中剩余元素X[i..u]复制到Z18. Z[q++] = X[i++];19. while( j <= v ) //将X中剩余元素X[j..v]复制到Z20. Z[q++] = X[j++];21. }2. ⼀趟归并扫描⼦算法:将参加排序的序列分成若⼲个长度为 t 的,且各⾃按值有序的⼦序列,然后多次调⽤归并⼦算法merge将所有两两相邻成对的⼦序列合并成若⼲个长度为2t 的,且各⾃按值有序的⼦序列。
简单的算法举例一、冒泡排序算法冒泡排序是一种基础的排序算法,通过比较相邻的元素并交换位置来进行排序。
它重复地遍历要排序的列表,比较每对相邻的元素,如果顺序不对就进行交换,直到整个列表排序完成。
二、选择排序算法选择排序算法是一种简单直观的排序算法,它将列表分为已排序和未排序两部分,每次从未排序的部分中选择最小(或最大)的元素,并将其放到已排序的部分的末尾。
三、插入排序算法插入排序算法是一种简单直观的排序算法,它将列表分为已排序和未排序两部分,每次从未排序的部分中选择一个元素插入到已排序的部分的合适位置。
四、归并排序算法归并排序算法是一种分治算法,它将列表递归地分成较小的部分,然后将这些部分按照顺序合并成一个有序的列表。
五、快速排序算法快速排序算法是一种分治算法,它通过选择一个基准元素将列表分成两部分,一部分小于基准元素,一部分大于基准元素,然后递归地对这两部分进行排序。
六、堆排序算法堆排序算法是一种利用堆这种数据结构进行排序的算法,它将列表看成一个完全二叉树,并将其调整为一个大顶堆或小顶堆,然后依次取出堆顶元素进行排序。
七、计数排序算法计数排序算法是一种非比较排序算法,它通过统计每个元素出现的次数,然后根据次数重新排列元素,从而实现排序。
八、桶排序算法桶排序算法是一种非比较排序算法,它将列表划分为若干个桶,然后将元素分配到相应的桶中,再对每个桶中的元素进行排序,最后将所有桶中的元素合并起来。
九、基数排序算法基数排序算法是一种非比较排序算法,它通过将元素按照各个位上的数字进行排序,先按照个位排序,再按照十位排序,依次类推,最终实现排序。
十、二分查找算法二分查找算法是一种在有序列表中查找特定元素的算法,它通过不断缩小查找范围,将查找时间复杂度从线性降低到对数级别。
各种排序算法的稳定性和时间复杂度小结选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法,冒泡排序、插入排序、归并排序和基数排序是稳定的排序算法。
冒泡法:这是最原始,也是众所周知的最慢的算法了。
他的名字的由来因为它的工作看来象是冒泡:复杂度为O(n*n)。
当数据为正序,将不会有交换。
复杂度为O(0)。
直接插入排序:O(n*n)选择排序:O(n*n)快速排序:平均时间复杂度log2(n)*n,所有内部排序方法中最高好的,大多数情况下总是最好的。
归并排序:log2(n)*n堆排序:log2(n)*n希尔排序:算法的复杂度为n的1.2次幂关于快速排序分析这里我没有给出行为的分析,因为这个很简单,我们直接来分析算法:首先我们考虑最理想的情况1.数组的大小是2的幂,这样分下去始终可以被2整除。
假设为2的k次方,即k=log2(n)。
2.每次我们选择的值刚好是中间值,这样,数组才可以被等分。
第一层递归,循环n次,第二层循环2*(n/2)......所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n所以算法复杂度为O(log2(n)*n)其他的情况只会比这种情况差,最差的情况是每次选择到的middle都是最小值或最大值,那么他将变成交换法(由于使用了递归,情况更糟)。
但是你认为这种情况发生的几率有多大??呵呵,你完全不必担心这个问题。
实践证明,大多数的情况,快速排序总是最好的。
如果你担心这个问题,你可以使用堆排序,这是一种稳定的O(log2(n)*n)算法,但是通常情况下速度要慢于快速排序(因为要重组堆)。
本文是针对老是记不住这个或者想真正明白到底为什么是稳定或者不稳定的人准备的。
首先,排序算法的稳定性大家应该都知道,通俗地讲就是能保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同。
在简单形式化一下,如果Ai = Aj, Ai原来在位置前,排序后Ai还是要在Aj位置前。
归并排序时间复杂度分析
归并排序是一种分治算法,它将一个大问题拆分成若干个小问题来解决。
它是通过将一个大的问题分解成小的问题来解决的,然后将小的问题解决后的结果合并起来,最终得到解决整个大问题的结果。
归并排序的基本思想是,将一个数组分成两半,将每一半分别排序,然后将排序的两个部分合并成一个有序的数组。
这个过程可以递归地进行,直到只剩下一个元素,然后再由有序的两部分合并为一个有序的数组。
归并排序的时间复杂度为O(nlogn)。
该算法的时间复杂度是由其分治策略决定的。
首先,将数组分成两部分,每部分都需要一次n/2次比较,这个过程需要O(n)时间;其次,将两个
有序数组合并成一个有序数组,这一步需要O(n)时间;最后,将这个有序数组划分成两部分,重复上述步骤,直到数组中只有一个元素,这一步需要O(logn)时间,因此,总的时间复杂
度就是O(nlogn)。
归并排序的空间复杂度也是O(nlogn),因为它需要一个辅助数组来保存排序后的结果,而这个辅助数组的大小是与原数组大小相同的。
总的来说,归并排序具有较高的效率,它的时间复杂度和空间复杂度都是O(nlogn),在实际应用中,归并排序可以很好
地解决许多排序问题,但是由于它需要额外的空间,所以它在处理海量数据时不是很实用。
C语言归并排序算法用归并排序法对一组数据由小到大进行排序,数据分别为695、458、362、789、12、15、163、23、2、986。
实现过程:(1) 自定义函数merge(),实现一次归并排序。
(2) 自定义函数merge_sort(),实现归并排序。
(3) 程序代码如下:1.#include<stdio.h>2.int merge(int r[],int s[],int x1,int x2,int x3)//自定义实现一次归并样序的函数3.{4.int i,j,k;5. i=x1;//第一部分的开始位置6. j=x2+1;//第二部分的开始位置7. k=x1;8.while((i<=x2)&&(j<=x3))//当i和j都在两个要合并的部分中时9.if(r[i]<=r[j])//筛选两部分中较小的元素放到数组s中10.{11. s[k]= r[i];12. i++;13. k++;14.}15.else16.{17. s[k]=r[j];18. j++;19. k++;20.}21.while(i<=x2)//将x1〜x2范围内未比较的数顺次加到数组r中22. s[k++]=r[i++];23.while(j<=x3)//将x2+l〜x3范围内未比较的数顺次加到数组r中24. s[k++]=r[j++];25.return0;26.}27.28.int merge_sort(int r[],int s[],int m,int n)29.{30.int p;31.int t[20];32.if(m==n)33. s[m]=r[m];34.else35.{36. p=(m+n)/2;37.merge_sort(r,t,m,p);//递归调用merge_soit()函数将r[m]〜r[p]归并成有序的t[m]〜t[p]38.merge_sort(r,t,p+1,n);//递归一调用merge_sort()函数将r[p+l]〜r[n]归并成有序的t[p+l]〜t[n]39.merge(t,s,m,p,n);//调用函数将前两部分归并到s[m]〜s[n】*/40.}41.return0;42.}43.44.int main()45.{46.int a[11];47.int i;48.printf("请输入10个数:\n");49.for(i=1;i<=10;i++)50.scanf("%d",&a[i]);//从键盘中输入10个数51.merge_sort(a,a,1,10);//调用merge_sort()函数进行归并排序52.printf("排序后的顺序是:\n");53.for(i=1;i<=10;i++)54.printf("%5d",a[i]);//输出排序后的数据55.printf("\n");56.return0;57.}运行结果:。
常⽤排序算法-归并排序简介 归并排序算法是基于归并操作的⼀种有效排序算法,是采⽤分治法的典型应⽤。
归并排序算法将待排序序列分为若⼲个⼦序列,先对每个⼦序列进⾏排序,等每个⼦序列都有序后,再将有序⼦序列合并为整体的有序序列,若将两个有序表合并为⼀个有序表,则称之为⼆路归并。
原理 归并排序的原理是将原始数组分解为多个⼦序列,然后对每个⼦序列进⾏排序,最后将排好序的⼦序列合并起来。
程序public class MergeSort {public static void sort(int[] arr){mergeSort(arr, 0, arr.length - 1);}private static void mergeSort(int[] arr, int left, int right){if(left >= right)return;int mid = left + (right - left) / 2;mergeSort(arr, left, mid);mergeSort(arr, mid+1, right);merge(arr, left, mid, right);}private static void merge(int[] arr, int left, int mid, int right){int[] tempArr = new int[right-left+1];int index = 0;int l = left, r = mid+1;while(l <= mid && r <= right){if(arr[l] <= arr[r])tempArr[index++] = arr[l++];elsetempArr[index++] = arr[r++];}while(l <= mid)tempArr[index++] = arr[l++];while(r <= right)tempArr[index++] = arr[r++];for(int i = 0; i < tempArr.length; ++i)arr[left+i] = tempArr[i];}}总结归并排序的时间复杂度最差为O(nlogn),最好情况时O(nlogn),平均时间复杂度为O(nlogn)。
归并排序算法
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个典型应用。
将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段之间有序。
将两个有序表合并成一个有序表,称为二路归并。
将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,得到n/2个长度为2的有序表;将这些有序序列再次归并,得到n/4个长度为4的有序序列;如此反复,最后得到一个长度为n的有序序列。
归并排序需要做两件事:
1)分解:将序列每次折半划分。
2)合并:将划分后的序列段两两合并后排序。
如何合并?
在每次合并过程中,都是对两个有序的序列段进行合并,然后再排序。
这两个有序的序列段分别为R[low, mid]和R[mid+1, high],先将它们合并到一个局部的暂存数组R2中,待合并完成后再将R2复制回R中。
每次从两个段中取出一个记录进行关键字的比较,将较小者放入R2中,最后将各段中余下的部分直接复制到R2中。
经过这样的过程,R2已经是一个有序的序列,再将其复制回R中,一次合并排序就完成了。
在某趟归并中,设各子表的长度为gap,则归并前R[0...n-1]中共有n/gap个有序的子表:R[0...gap-1], R[gap...2*gap-1], ... , R[(n/gap)*gap ... n-1]。
在将相邻的子表归并时,需要对表的特殊情况进行处理:
1)若子表个数为奇数,最后一个子表无须和其他子表归并(即本趟处理轮空);
2)若子表个数为偶数,到最后一对子表中后一个子表区间的上限为n-1;
时间复杂度:归并排序的形式就是一棵二叉树,需要遍历的次数就是二叉树的深度,时间复杂度是O(nlogn)。
空间复杂度:算法处理过程中,需要一个大小为n的临时存储空间用来保存合并序列。
算法稳定性:在归并排序中,相等元素的顺序不会改变,所以它是稳定的算法。
总结:
1)时间复杂度:O(nlogn)
2)空间复杂度:O(n)
3)稳定性:稳定
4)复杂性:较复杂。