归并排序算法
- 格式:docx
- 大小:98.31 KB
- 文档页数:6
C语言常用算法总结1、冒泡排序算法:冒泡排序是一种简单的排序算法,它重复地遍历要排序的序列,一次比较两个相邻的元素如果他们的顺序错误就把他们交换过来。
时间复杂度为O(n^2)。
2、快速排序算法:快速排序是一种基于分治的排序算法,通过递归的方式将数组划分为两个子数组,然后对子数组进行排序最后将排好序的子数组合并起来。
时间复杂度为O(nlogn)。
3、插入排序算法:插入排序是一种简单直观的排序算法,通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描找到相应位置并插入。
时间复杂度为O(n^2)。
4、选择排序算法:选择排序是一种简单的排序算法,每次循环选择未排序部分的最小元素,并放置在已排序部分的末尾。
时间复杂度为O(n^2)。
5、归并排序算法:归并排序是一种稳定的排序算法,基于分治思想,将数组递归地分为两个子数组,将子数组排序后再进行合并最终得到有序的数组。
时间复杂度为O(nlogn)。
6、堆排序算法:堆排序是一种基于完全二叉堆的排序算法,通过构建最大堆或最小堆,然后依次将堆顶元素与末尾元素交换再调整堆,得到有序的数组。
时间复杂度为O(nlogn)。
7、二分查找算法:二分查找是一种在有序数组中查找目标元素的算法,每次将待查找范围缩小一半,直到找到目标元素或范围为空。
时间复杂度为O(logn)。
8、KMP算法:KMP算法是一种字符串匹配算法,通过利用模式字符串的自重复性,避免不必要的比较提高匹配效率。
时间复杂度为O(m+n),其中m为文本串长度,n为模式串长度。
9、动态规划算法:动态规划是一种通过将问题分解为子问题,并通过组合子问题的解来求解原问题的方法。
动态规划算法通常使用内存空间来存储中间结果,从而避免重复计算。
时间复杂度取决于问题规模。
10、贪心算法:贪心算法是一种通过选择局部最优解来构建全局最优解的算法并以此构建最终解。
时间复杂度取决于问题规模。
11、最短路径算法:最短路径算法用于求解图中两个节点之间的最短路径,常见的算法包括Dijkstra算法和Floyd-Warshall算法。
归并排序的细节讲解与复杂度分析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];}}}。
学习编程的十大经典算法学习编程是现代社会中一个非常重要的技能,而掌握经典算法是成为一个优秀的程序员的必备条件之一。
下面将介绍十大经典算法,详细解释它们的原理和应用。
1. 二分查找算法(Binary Search)二分查找算法是一种在有序数组中快速查找特定元素的算法。
它将查找范围不断缩小一半,直到找到目标元素或确定目标元素不存在。
二分查找算法的时间复杂度为O(log n)。
2. 冒泡排序算法(Bubble Sort)冒泡排序算法是一种简单但效率较低的排序算法。
它通过多次遍历数组,将相邻的元素进行比较并交换位置,使得较大(或较小)的元素逐渐移动到数组的末尾。
冒泡排序的时间复杂度为O(n^2)。
3. 快速排序算法(Quick Sort)快速排序算法是一种高效的排序算法。
它通过选择一个基准元素,将数组分为左右两个子数组,并对子数组进行递归排序。
快速排序算法的时间复杂度为O(n log n),在大多数情况下具有较好的性能。
4. 归并排序算法(Merge Sort)归并排序算法是一种分治思想的排序算法。
它将数组一分为二,递归地对子数组进行排序,然后将排好序的子数组合并成一个有序的数组。
归并排序算法的时间复杂度为O(n log n),稳定且适用于大规模数据的排序。
5. 插入排序算法(Insertion Sort)插入排序算法是一种简单且稳定的排序算法。
它通过将未排序的元素逐个插入已排序的序列中,以达到整体有序的目的。
插入排序的时间复杂度为O(n^2),但对于小规模数据或基本有序的数组,插入排序具有较好的性能。
6. 选择排序算法(Selection Sort)选择排序算法是一种简单但效率较低的排序算法。
它通过多次遍历数组,选择出最小(或最大)的元素,并放置到已排序的序列中。
选择排序的时间复杂度为O(n^2),但它适用于小规模数据或交换成本较高的情况。
7. 堆排序算法(Heap Sort)堆排序算法是一种高效的排序算法。
算法—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); //归并结果}} 此算法基于原地归并的抽象实现了另⼀种递归归并,这也是应⽤⾼效算法设计中分治思想的最典型的⼀个例⼦。
二叉树的快速排序、归并排序方法一、快速排序快速排序采用的是分治法策略,其基本思路是先选定一个基准数(一般取第一个元素),将待排序序列抽象成两个子序列:小于基准数的子序列和大于等于基准数的子序列,然后递归地对这两个子序列排序。
1. 递归实现(1)选定基准数题目要求采用第一个元素作为基准数,因此可以直接将其取出。
(2)划分序列接下来需要将待排序序列划分成两个子序列。
我们定义两个指针 i 和 j,从待排序序列的第二个元素和最后一个元素位置开始,分别向左和向右扫描,直到 i 和 j 相遇为止。
在扫描过程中,将小于等于基准数的元素移到左边(即与左侧序列交换),将大于基准数的元素移到右边(即与右侧序列交换)。
当 i=j 时,扫描结束。
(3)递归排序子序列完成划分后,左右两个子序列就确定了下来。
接下来分别对左右两个子序列递归调用快速排序算法即可。
2. 非递归实现上述方法是快速排序的递归实现。
对于大量数据或深度递归的情况,可能会出现栈溢出等问题,因此还可以使用非递归实现。
非递归实现采用的是栈结构,将待排序序列分成若干子序列后,依次将其入栈并标注其位置信息,然后将栈中元素依次出栈并分割、排序,直至栈为空。
二、归并排序归并排序同样采用的是分治思想。
其基本思路是将待排序序列拆分成若干个子序列,直至每个子序列只有一个元素,然后将相邻的子序列两两合并,直至合并成一个有序序列。
1. 递归实现(1)拆分子序列归并排序先将待排序序列进行拆分,具体方法是将序列平分成两个子序列,然后递归地对子序列进行拆分直至每个子序列只剩下一个元素。
(2)合并有序子序列在完成子序列的拆分后,接下来需要将相邻的子序列两两合并为一个有序序列。
我们先定义三个指针 i、j 和 k,分别指向待合并的左侧子序列、右侧子序列和合并后的序列。
在进行合并时,从两个子序列的起始位置开始比较,将两个子序列中较小的元素移动到合并后的序列中。
具体操作如下:- 当左侧子序列的第一个元素小于等于右侧子序列的第一个元素时,将左侧子序列的第一个元素移动到合并后的序列中,并将指针 i 和 k 分别加 1。
五种常见的排序方法在计算机科学中,排序是一种非常重要的操作,它可以将一组数据按照一定的顺序排列。
排序算法是计算机科学中最基本的算法之一,它的应用范围非常广泛,例如数据库查询、数据压缩、图像处理等。
本文将介绍五种常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序和归并排序。
一、冒泡排序冒泡排序是一种简单的排序算法,它的基本思想是将相邻的元素两两比较,如果前面的元素大于后面的元素,则交换它们的位置,一遍下来可以将最大的元素放在最后面。
重复这个过程,每次都可以确定一个最大的元素,直到所有的元素都排好序为止。
冒泡排序的时间复杂度为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),在处理小规模的数据时比较适用。
793的六种算法一、插入排序算法插入排序算法是一种简单直观的排序算法,它的基本思想是将待排序的元素插入到已排序序列的适当位置,使得插入后的序列仍然有序。
具体步骤如下:1. 将数组分为已排序区间和未排序区间,初始时已排序区间只有一个元素,即数组的第一个元素。
2. 从未排序区间取出第一个元素,将其与已排序区间中的元素依次比较,找到合适的位置插入。
3. 重复上述步骤,直到未排序区间为空。
插入排序算法的时间复杂度为O(n^2),空间复杂度为O(1),适用于数据量较小的排序场景。
二、冒泡排序算法冒泡排序算法是一种简单的排序算法,它的基本思想是通过相邻元素的比较和交换,将最大或最小的元素逐渐“冒泡”到数组的一端。
具体步骤如下:1. 从数组的第一个元素开始,依次比较相邻的两个元素,如果它们的顺序不对,则交换位置。
2. 重复上述步骤,直到数组中的所有元素都排好序。
冒泡排序算法的时间复杂度为O(n^2),空间复杂度为O(1),适用于数据量较小且基本有序的排序场景。
三、选择排序算法选择排序算法是一种简单直观的排序算法,它的基本思想是每次从未排序的部分选择最小或最大的元素,放到已排序部分的末尾。
具体步骤如下:1. 将数组分为已排序区间和未排序区间,初始时已排序区间为空。
2. 从未排序区间中找到最小或最大的元素,将其放到已排序区间的末尾。
3. 重复上述步骤,直到未排序区间为空。
选择排序算法的时间复杂度为O(n^2),空间复杂度为O(1),适用于数据量较小的排序场景。
四、快速排序算法快速排序算法是一种高效的排序算法,它的基本思想是通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有元素都比另一部分的所有元素小,然后再按此方法对两部分分别进行排序,最终得到有序序列。
具体步骤如下:1. 选择一个基准元素,将数组分成两部分,所有小于基准元素的元素放在左边,所有大于基准元素的元素放在右边。
2. 对左右两部分分别进行快速排序。
归并排序算法
算法思路:采用递归的方式将一串数组逐级划分,直至不可分割时,此时顺序唯一,将元素放回排序序列中。
设置递归函数(Merge_Sort)那么递归中需要进行如下操作:
(1)划分数组,设定划分区间
这里我们向下取整(左序列短于右序列,另一种方式
当然也是可以的)
设数组起点为p,终点为r,则:
令:q=(r+p-1)/2;
(2)分别处理左右区间
Merge_Sort(array[],p,q);
Merge_Sort(array[],q+1,r);
(3)合并左右两个区间
Merge(array[],p,q,r);
这里用到了一个归并操作的函数,我们来简单分析一下这个函数中需要处理的任务。
首先:这个函数需要实现的功能为合并两个排好顺序的数组,这里简单说明一下为什么是已经排好顺序的两个数组,我们设想最简单的情况,利用Merge_Sort()函数进行逐级递归,当递归到左右区间都只剩一个的情况下,此时再对左右区间进行递归不再处理任何内容,此时回到上层递归中,这时候函数就第一次行进到Merge()函数,此时需要对这两个都只有一
个数当然是算是已经排好序的数组进行排序,那么就得到了包含这两个数的一个次小有序数组。
按这种逻辑可推知每次执行Merge()时,左右两个数组都是有序数组。
那么我们在Merge()内的任务就是归并两个有序数组,并且令归并后的数组有序。
下面用一张图来说明:
假设我们要排列这样一个数组[1,3,7,9,2,4,6,8];
1,3,7,9,2,4,6,8
1,3,7,92,4,6,8 1,3,7,9,2,4,6,8
1,3,7,9,2,4,6,8
1,3,7,92,4,6,8 1,2,3,7,9,4,6,8
1,3,7,9,2,4,6,8
1,3,7,92,4,6,8 1,2,3,4,7,9,6,8
1,3,7,9,2,4,6,8
1,3,7,92,4,6,8 1,2,3,4,6,7,9,8
1,3,7,9,2,4,6,8
1,3,7,92,4,6,8
1,2,3,4,6,7,8,9
从上图中分析我们可以知道,在函数中我们需要进行如下处理:(1)划分数组,元素个数分别为:
n1=q-p+1;
n2=r-q;
分别申请两个动态数组L,R需比其中元素个数多1用
于存放一个极大值。
(2)分别进行赋值:
from i=0 to n1-1
L[i]=array[p+i];
From j=0 to n2-1;
R[j]=array[q+j+1];
L(n1)=inf;R(n2)=inf;
I=0;j=0;
(3)归并操作
from k=p to r
if L(i)<R(j);
array[k]=L[i];
i++;
else
array[k]=R[j];
j++;
代码实现(C语言):
#include <stdio.h>
#include <stdlib.h>
#define INF 65535
void Merge(int array[],int p,int q,int r){ int n1=q-p+1;
int n2=r-q;
int i,j,k;
int *L=malloc(sizeof(int)*(n1+1));
int *R=malloc(sizeof(int)*(n2+1));
for(i=0;i<n1;i++)
L[i]=array[p+i];
for(j=0;j<n2;j++)
R[j]=array[q+j+1];
L[n1]=INF;
R[n2]=INF;
i=0;j=0;
for(k=p;k<=r;k++){
if(L[i]<R[j]){
array[k]=L[i];
i++;
}
else{
array[k]=R[j];
j++;
}
}
}
void Merge_Sort(int array[],int p,int r){ int q;
if(p<r){
q=(r+p-1)/2;
Merge_Sort(array,p,q);
Merge_Sort(array,q+1,r);
Merge(array,p,q,r);
}
}
int main()
{
int i;
int array[10]={1,3,7,5,4,2,6,9,5,8};
printf("Merge Sort Example\n");
printf("Before sort:\n");
for(i=0;i<10;i++)
printf("%d ",array[i]);
printf("\n");
Merge_Sort(array,0,9);
printf("After sort:\n");
for(i=0;i<10;i++)
printf("%d ",array[i]);
printf("\n");
return 0;
}。