分治法之归并排序

来源:互联网 发布:淘宝cad画图接活群 编辑:程序博客网 时间:2024/05/21 01:58

分治法之归并排序

目录

  • 分治法之归并排序
    • 目录
    • 摘要
    • 分治法的步骤
    • 主方法The master method
      • 主方法的实例
    • 归并排序
      • 归并排序的实例1
      • 归并排序的实例2
      • 思路分析
      • aha

摘要

本小节中主要讨论分治法归并排序的应用:

  • 分治法的步骤
  • 主方法
  • 归并排序的算法
  • 归并排序的实例

分治法的步骤

  • Divide the problem into one or more subproblem
  • 分解:将原问题划分为一些子问题,子问题的形式和原问题的相同,但是规模减小
  • Conquer the subproblems by solving them recursively.
  • 解决:利用递归求解出子问题的解,如果子问题的规模足够小,则停止递归,直接求解
  • Combine the solutions to the subproblems into the solution for the original problem
  • 合并:将子问题的解合并成原问题的解
  • -

主方法(The master method)

Master theorem 是判断递归式,求解估算算法复杂度比较常用的方法,它的主要内容如下:

Master theorem (reprise)
T(n) = aT(n/b) + f(n)
CASE 1: f(n) = O(n log b a – ε ), constant ε > 0
⇒ T(n) = Θ(n log b a ) .
CASE 2: f(n) = Θ(n log b a lg k n), constant k ≥ 0
⇒ T(n) = Θ(n log b a lg k+1 n) .
CASE 3: f(n) = Ω(n log b a + ε ), constant ε > 0,
and regularity condition
⇒ T(n) = Θ(f(n)) .

主方法的实例

eg1 : T(n)=4T(n/2)+n

由于f(n)=n=O(n^2),属于CASE1,==>T(n)=Θ(n^2)


eg2 : T(n)=2T(n/2)+n

由于f(n)=n=Θ(n^2),属于CASE2,==>T(n)=Θ(nlgn)


eg3 : T(n)=4T(n/2)+n^3

由于f(n)=n^3=Ω(n^2),属于CASE3,==>T(n)=Θ(n^3)

归并排序

merge算法伪代码1 :

算法导论中的伪代码:使用哨兵

Merge算法伪代码2 :

Merge(B[0...p-1],C[0...q-1],A[0,p+q-1])//将两个有序数组合并成一个有序数组//输入:两个有序数组B[0...p-1],C[0...q-1]//输出:A[0,p+q-1]中已经有序存放了BC的元素 i<-0;j<-0;k<-0; while i<p && j<q do    if B[i]<=C[j]       A[k] <- B[i];i <- i+1    else       A[k] <- C[j];j <- j+1    k <- k+1 if i=p    copyC[j...q-1] to A[k..p+q-1] else    copyB[i...p-1] to A[k..p+q-1]

MergeSort算法伪代码1 :

这里写图片描述

MergeSort算法伪代码2 :

MergeSort(A[0,n-1])//递归调用mergesort对数组A进行排序//输入:一个可排序数组A[0...n-1]//输出:非降序排列的数组A[0,n-1]if n>1  copy a[0...n/2] to B[0...n/2]  copy a[n/2+1...n-1] to C[0...n/2]MergeSort(B[0...n/2])MergeSort(C[0...n/2])Merge(B,C,A)

MergeSort 的例子 :

这里写图片描述

归并排序的实例1

eg : 应用归并算法将序列EXAMPLE按照字母表顺序排序

/** 归并排序:C 语言** @author Erice_s* @date 2017/10/13** 参数说明:*    a -- 一个可排序的数组*    first -- 第一个有序数组下标最小的数*    last -- 第二个有序数组下标最大的数*    mid -- 第一个有序数组结束,第二个有序数组开始的下标*/#include <stdio.h>#include <stdlib.h>#include <string.h>void merge(char *a, int first, int mid, int last){     int i = first;    int j = mid + 1;    int m = 0;    char *ptmp = (char*)malloc((last - first + 1)*sizeof(char));    while (i <= mid&&j <= last)    {        if ((int)a[i] < (int)a[j])            ptmp[m++] = a[i++];        else            ptmp[m++] = a[j++];    }    while (i <= mid)        ptmp[m++] = a[i++];    while (j<=last)        ptmp[m++] = a[j++];    for (i = 0; i < last - first + 1; i++)        a[first+i] = ptmp[i];    free(ptmp);}void mergeSort(char *a, int first, int last){    if (a==NULL||first >= last)        return;    int mid = (first & last) +((first^last) >> 1);    //int mid = (first + last)/2;//may cause overflow    mergeSort(a, first, mid);    mergeSort(a, mid+1, last);    merge(a,first,mid,last);}void print(char *p,int len){    for (int i = 0; i < len; i++)    {        printf("%c", p[i]);    }    printf("\n");}int main(void){    char p[] = { 'E','X','A','M','P','L','E' };    int len = sizeof(p)/sizeof(*p);    printf("mergeSort before: ");    print(p, len);    mergeSort(p, 0, len-1);    printf("mergeSort  after: ");    print(p, len);    system("pause");    return 0;}

运行结果 :

归并排序结果


归并排序的实例2

eg 2 :有N个整数,A[1]…A[N],需要找到这样的(i,j)的数对d的数量;满足要求:

1 <= i < j<= N && A[i]>A[j]
数据范围:1<=N<=65537 , 0< A[i] <10^9
算法时间复杂度为O(nlgn)


思路分析:

采用归并排序的思想,先把问题的规模变小,问题可以简化为三个子问题,解决A[]左边存在多少逆序对,A[]右边存在多少逆序对,横跨mid的有多少逆序对。

逆序对问题


/** 归并排序:C 语言** @author Erice_s* @date 2017/10/13** 参数说明:*    a -- 一个可排序的数组*    l -- 左边界*    m -- 中值*    r -- 右边界*/#define _CRT_SECURE_NO_WARNINGS#include  <iostream>#include  <cstdio>using  namespace  std;#define  MAXN  65537int  a[MAXN];int  la[MAXN], ra[MAXN];long  long  cnt; // 逆序对数目void  merge (int l,  int m, int r) //l  左边界,m 中值 , r 右边界{   int  p1 = 0, p2 = 0, j, k;    for ( int i = l ; i <= m; i++)        la[p1++] = a[i]; // 初始化 la 数组    for (int  i = m+ 1; i <= r; i++)        ra[p2++] = a[i]; // 初始化 ra 数组        la[p1] = ra[p2] = 0x3f3f3f3f;    j = k = 0;    for (int  i = l; i <= r; i++)    {        if (la[j] <= ra[k])            a[i] = la[j++];        else        {            a[i] = ra[k++];            cnt += p1 -j;        }    }}void  mergeSort( int l, int  r){    if (l >= r)            return;    int  m = (l & r) +((l ^ r)>> 1);    mergeSort(l, m);    mergeSort(m + 1, r);    merge(l, m, r);}int  main(){    int  n;    while (~scanf("%d", &n))    {        cnt = 0;        for (int i = 0; i < n; i++)            scanf("%d", &a[i]);        mergeSort(0, n -1);        printf("测试数组的元素个数: %d\n", n);        printf("逆序对个数为:%lld \n", cnt);    }    return 0;}

运行结果
逆序对

aha

好久没写过博客了,今天就写到这里了,欢迎小伙伴叨扰! merci…

原创粉丝点击