算法导论第三版 练手程序C++(第二章)(2)

实在闲的蛋疼,大神不要喷我


第二章

分治法排序:
伪代码:
MERGE(A,p,q,r)
    n1 = q-p+1
    n2 = r-q
    新建数组 L[1..n1+1] 和 R[1..n2+1]
    for i = 1 to n1
      L[i] = A[p+i-1]
    forj = 1 to n2
      R[j] = A[q+j]
    L[n1+1] = NaN
    R[n2+1] = NaN
    i = 1
    j = 1
    for k = p to r
      if L[i]<=R[j]
        A[k] = L[i]
        i = j+1
      else A[k] = R[j]
        j = j+1

MERGE-SORT(A,p,r)
    if p<r
      q = |_(p+r)/2_|
      MERGE-SORT(A,p,q)
      MERGE-SORT(A,q+1,r)
      MERGE(A,p,q,r)


这里有个蛋疼的问题,伪代码里,L和R每次调用merge时都是new出来(对C++而言)的,但是,要知道new一个数组画得时间远大于一般的计算,更不必说还要把new出来的数组delete掉了,那么咋办呢。。只好实现就新建一个全局的数组(类似缓存区的功能),每次需要新的数组时,直接利用全局数组,而merge里所需的数组的大小必然小于需要排序的数组的大小,那么,就创建一个和待排序数组大小一样的全局数组吧。
#include <stdlib.h>
#include <time.h>
#include <iostream>
#define PAI_LENGTH 10000
using namespace std;

int cache[PAI_LENGTH+2];

void merge(int A[],int p,int q,int r) {
  int i,j;
  int n1 = q-p+1;
  int n2 = r-q;
  int *L = cache;
  int *R = cache+n1+1;
  for(i = 0;i<n1;i++) {
    L[i] = A[p+i];
  }
  for(j=0;j<n2;j++) {
    R[j] = A[q+j+1];
  }
  L[n1] = 10000;
  R[n2] = 10000;
  i=0;
  j=0;
  for(int k=p;k<=r;k++) {
    if(L[i]<=R[j]) {
      A[k] = L[i];
      i++;
    }else{
      A[k] = R[j];
      j++;
    }
  }
}

void merge_sort(int A[],int p,int r) {
  if(p<r) {
    int  q = (p+r)/2;
    merge_sort(A,p,q);
    merge_sort(A,q+1,r);
    merge(A,p,q,r);
  }
}

void printAll(int A[],int length) {
  for(int i=0;i<length;i++) {
    cout<<A[i]<<endl;
  }
}

int main() {
  clock_t start,end;
  int raw[PAI_LENGTH];
  srand((unsigned)time(NULL));
  for(int i=0;i<PAI_LENGTH;i++) {
    raw[i] = rand()%10000+1;
  }
  start = clock();
  merge_sort(raw,0,PAI_LENGTH-1);
  end = clock();
  cout<<"use"<<(end-start)<<"us"<<endl;
}
嗯,对,又是直接一大片代码。。其实看过上一篇的可以发现mian函数大部分的代码是在创建随机数组和计时的,看看结果:
use 4243 us
还有谁!!!同样10000个随机数,为什么分治算法这么快呢,没错,你没有看错,答案将会在第3,4章揭晓。。。。
下面顺便分享一下习题2.3-2的做法。要求是重写merge函数,使之不使用哨兵排,所以伪代码变成下面的样子:
MERGE(A,p,q,r)
    n1 = q-p+1
    n2 = r-q
    let L[1..n1] and R[1..n2] be new arrays
    for i = 1 to n1
      L[i] = A[p+i-1]
    forj = 1 to n2
      R[j] = A[q+j]
    i = 1
    j = 1
    k=p
    while i<=n1 and j<=n2
      if L[i]<=R[j]
        A[k] = L[i]
        i = j+1
      else 
        A[k] = R[j]
        j = j+1
      k++
    if i<=n1
      for k=k to r
        A[k]=R[j]
        j=j+1
    else
      for k=k to r
        A[k]=L[i]
        i=i+1

  MERGE-SORT(A,p,r)
    if p<r
      q = |_(p+r)/2_|
      MERGE-SORT(A,p,q)
      MERGE-SORT(A,q+1,r)
      MERGE(A,p,q,r)


恩好像没差嘛。看看对应的程序:
#include <stdlib.h>
#include <time.h>
#include <iostream>
#define PAI_LENGTH 10000
using namespace std;

int cache[PAI_LENGTH+2];

void merge(int A[],int p,int q,int r) {
  int i,j;
  int n1 = q-p+1;
  int n2 = r-q;
  int *L = cache;
  int *R = cache+n1;
  for(i = 0;i<n1;i++) {
    L[i] = A[p+i];
  }
  for(j = 0;j<n2;j++) {
    R[j] = A[q+j+1];
  }
  i=0;
  j=0;
  int k=p;
  for(;i<n1&&j<n2;k++) {
    if(L[i]<=R[j]) {
      A[k] = L[i];
      i++;
    }else{
      A[k] = R[j];
      j++;
    }
  }
  if(i>=n1) {
    for(;k<=r;k++) {
      A[k] = R[j];
      j++;
    }
  }else{
    for(;k<=r;k++) {
      A[k] = L[i];
      i++;
    }
  }
}

void merge_sort(int A[],int p,int r) {
  if(p<r) {
    int  q = (p+r)/2;
    merge_sort(A,p,q);
    merge_sort(A,q+1,r);
    merge(A,p,q,r);
  }
}

void printAll(int A[],int length) {
  for(int i=0;i<length;i++) {
    cout<<A[i]<<endl;
  }
}

int main() {
  clock_t start,end;
  int raw[PAI_LENGTH];
  srand((unsigned)time(NULL));
  for(int i=0;i<PAI_LENGTH;i++) {
    raw[i] = rand()%10000+1;
  }
  start = clock();
  merge_sort(raw,0,PAI_LENGTH-1);
  end = clock();
  printAll(raw,PAI_LENGTH);
  cout<<"use"<<(end-start)<<"us"<<endl;
}

恩,好像也没差嘛。。。
再看看运行结果:
use 4297 us 
恩,果然没差。。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值