编程珠玑 Pearls(2)

来源:互联网 发布:c语言文件打开方式手机 编辑:程序博客网 时间:2024/05/21 09:03

[TOC]

基本操作的威力

B. 将一个n元一维向量左旋转i个位置。例如,当n=8且i=3时,向量abcdefg旋转为defghabc。简单的代码使用一个n元中间向量在n步内完成该工作。你能仅使用10个额外字节的存储空间,在正比于n的时间内完成向量的旋转。

  1. 将x的前i个元素复制到一个临时数组,然后将余下的n-i个元素左移动i个位置,最后将最初的i个元素复制到x余下的位置。

  2. 定义一个函数将x左旋转一个位置(其时间正比于n),然后调用函数i次,但该方法产生量过多的运行时间消耗。

  3. 杂技算法 -> 要在有限的资源内解决该问题,显然需要更加复杂的程序。有一个成功的方法有点像精巧的杂技动作:移动x[0]到临时变量t,然后移动x[i]到x[0],x[2i]移动到x[i] 以此类推(将x中所有下标对n取模),直到返回取x[0]中的元素,此时改为从t取值,然后终止过程。至此,一次移动结束。循环gcd(n,i)次即可,gcd为最大公约数。

  4. 求逆运算 -> x看作a,b两段,其中a的长度为i,旋转操作可化为
    a -> a' b -> b'
    ab=(a'b')'

  1. 杂技算法
#include<stdio.h>#include<stdlib.h>int gcd(int p,int q){    if(q == 0) return p;    return gcd(q,p%q);}void reverse(char arr[],int sz,int cnt){    int tmp,loopCnt = gcd(sz,cnt);    int i,j,k;    for(i=0;i<loopCnt;i++)    {        tmp = arr[i];        j = i;        while(1)        {            k = j + cnt;            if(k >= sz)                k = k - sz;            if(k == i)                break;            arr[j] = arr[k];            j = k ;        }        arr[j] = tmp;    }}int main(void){    char carr[]={'a','b','c','d','e','f','g','h'};    int sz = 8,i=0;    reverse(carr,sz,3);    printf("========\n");    for(i = 0 ;i < sz;i++)    {        printf("%c ",carr[i]);    }    printf("\n");    printf("========\n");    return 0;} 

比较

杂技算法的速度显然是求逆运算的两倍。杂技算法对数组中的每个元素仅仅存储和读取一次,而求逆算法需要两次。

思考

反转代码在文本编辑器中实现了行的移动

/* Copyright (C) 1999 Lucent Technologies *//* From 'Programming Pearls' by Jon Bentley *//* rotate.c -- time algorithms for rotating a vector    Input lines:        algnum numtests n rotdist        algnum:          1: reversal algorithm          2: juggling algorithm          22:  juggling algorithm with mod rather than if          3: gcd algorithm          4: slide (don't rotate): baseline alg for timing    To test the algorithms, recompile and change main to call testrot */#include <stdio.h>#include <stdlib.h>#include <time.h>#define MAXN 10000000int x[MAXN];int rotdist, n;/* Alg 1: Rotate by reversal */void reverse(int i, int j){   int t;    while (i < j) {        t = x[i]; x[i] = x[j]; x[j] = t;        i++;        j--;    }}void revrot(int rotdist, int n){   reverse(0, rotdist-1);    reverse(rotdist, n-1);    reverse(0, n-1);}/* Alg 2: Juggling (dolphin) rotation */int gcd(int i, int j){   int t;    while (i != 0) {        if (j >= i)            j -= i;        else {            t = i; i = j; j = t;        }    }    return j;}void jugglerot(int rotdist, int n){   int cycles, i, j, k, t;    cycles = gcd(rotdist, n);    for (i = 0; i < cycles; i++) {        /* move i-th values of blocks */        t = x[i];        j = i;        for (;;) {            k = j + rotdist;            if (k >= n)                k -= n;            if (k == i)                break;            x[j] = x[k];            j = k;        }        x[j] = t;    }}void jugglerot2(int rotdist, int n){   int cycles, i, j, k, t;    cycles = gcd(rotdist, n);    for (i = 0; i < cycles; i++) {        /* move i-th values of blocks */        t = x[i];        j = i;        for (;;) {          /* Replace with mod below            k = j + rotdist;            if (k >= n)                k -= n;           */            k = (j + rotdist) % n;            if (k == i)                break;            x[j] = x[k];            j = k;        }        x[j] = t;    }}/* Alg 3: Recursive rotate (using gcd structure) */void swap(int i, int j, int k) /* swap x[i..i+k-1] with x[j..j+k-1] */{   int t;    while (k-- > 0) {        t = x[i]; x[i] = x[j]; x[j] = t;        i++;        j++;    }}void gcdrot(int rotdist, int n){   int i, j, p;    if (rotdist == 0 || rotdist == n)        return;    i = p = rotdist;    j = n - p;    while (i != j) {        /* invariant:            x[0  ..p-i  ] is in final position            x[p-i..p-1  ] = a (to be swapped with b)            x[p  ..p+j-1] = b (to be swapped with a)            x[p+j..n-1  ] in final position        */        if (i > j) {            swap(p-i, p, j);            i -= j;        } else {            swap(p-i, p+j-i, i);            j -= i;        }    }    swap(p-i, p, i);}int isogcd(int i, int j){   if (i == 0) return j;    if (j == 0) return i;    while (i != j) {        if (i > j)            i -= j;        else             j -= i;    }    return i;}void testgcd(){    int i,j;    while (scanf("%d %d", &i, &j) != EOF)        printf("%d\n", isogcd(i,j) );}/* Test all algs */void slide(int rotdist, int n) /* Benchmark: slide left rotdist (lose 0..rotdist-1) */{   int i;    for (i = rotdist; i < n; i++)        x[i-rotdist] = x[i];}void initx(){    int i;    for (i = 0; i < n; i++)        x[i] = i;}void printx(){   int i;    for (i = 0; i < n; i++)        printf(" %d", x[i]);    printf("\n");}void roterror(){    fprintf(stderr, " rotate bug %d %d\n", n, rotdist);    printx();    exit (1);}void checkrot(){   int i;    for (i = 0; i < n-rotdist; i++)        if (x[i] != i+rotdist)            roterror();    for (i = 0; i < rotdist; i++)        if (x[n-rotdist+i] != i)            roterror();}void testrot(){   for (n = 1; n <= 20; n++) {        printf(" testing n=%d\n", n);        for (rotdist = 0; rotdist <= n; rotdist++) {            /* printf("  testing rotdist=%d\n", rotdist); */            initx(); revrot(rotdist, n);     checkrot();            initx(); jugglerot(rotdist, n);  checkrot();            initx(); jugglerot2(rotdist, n); checkrot();            initx(); gcdrot(rotdist, n);     checkrot();        }    }}/* Timing */void timedriver(){   int i, algnum, numtests, start, clicks;    while (scanf("%d %d %d %d", &algnum, &numtests, &n, &rotdist) != EOF) {        initx();        start = clock();        for (i = 0; i < numtests; i++) {            if (algnum == 1)                revrot(rotdist, n);            else if (algnum == 2)                jugglerot(rotdist, n);            else if (algnum == 22)                jugglerot2(rotdist, n);            else if (algnum == 3)                gcdrot(rotdist, n);            else if (algnum == 4)                slide(rotdist, n);        }        clicks = clock() - start;        printf("%d\t%d\t%d\t%d\t%d\t%g\n",            algnum, numtests, n, rotdist, clicks,            1e9*clicks/((float) CLOCKS_PER_SEC*n*numtests));    }}/* Main */int main(){   /* testrot(); */    timedriver();    return 0;}

变位词程序的实现(边栏)

sign.c

#include<stdio.h>#include<stdlib.h>#define WORDMAX 100intcharcmp (char *x, char *y){  return *x - *y;}intmain (void){  char word[WORDMAX], sig[WORDMAX];  while (scanf ("%s", word) != EOF)    {      strcpy (sig, word);      qsort (sig, strlen (sig), sizeof (char), charcmp);      printf ("%s %s\n", sig, word);    }  return 0;}

squash.c

#include<stdio.h>#include<stdlib.h>#define WORDMAX 100intmain (void){  char word[WORDMAX], oldsig[WORDMAX], sig[WORDMAX];  int linenum = 0;  strcpy (oldsig, "");  while (scanf ("%s %s", sig, word) != EOF)    {      if (strcmp (oldsig, sig) != 0 && linenum > 0)    printf ("\n");      strcpy (oldsig, sig);      linenum++;      printf ("%s ", word);    }  printf ("\n");  return 0;}

sign < dic | sort | squash > gramlist 改命令将文件dic输入到程序,连接sign的输出至sort,连接sort的输出至squash,并将squash的输出写入文件gramlist。
运行结果:

[hadoop@Arch Pearls]$ gcc sign.c -o sign[hadoop@Arch Pearls]$ gcc squash.c -o squash   [hadoop@Arch Pearls]$ sign < dic | sort | squash > gramlist [hadoop@Arch Pearls]$ cat dicpanspotsoptsnapstoptops[hadoop@Arch Pearls]$ cat gramlist pans snap pots stop tops opt 

一点说明:

  1. 关于解决问题,把程序化成一个个小块,每个小块实现一个小的功能,然后把各个功能块连接起来,组成一个大的应用。上面的程序就是一个很好的例子,
  • sign.c负责生成单词的标识,并把生成的表示和单词输出。
  • squash.c负责把临近的标识相同的单词按行放在同一行输出。
  • 借助linux的sort命令把单词把标识单词相同的聚到一起。
  1. 关于qsort,快速排序,需要指定排序的方法,原型
void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*));
[hadoop@Arch Pearls]$ a.outage=10,height=180age=10,height=190age=18,height=180[hadoop@Arch Pearls]$ cat qsort.c#include<stdio.h>struct Student{  int age;  int height;};intstucmp (struct Student *s1, struct Student *s2){  if (s1->age != s2->age)    return s1->age - s2->age;  else    return s1->height - s2->height;}intmain (void){  struct Student stu[3];  stu[0].age = 10, stu[0].height = 190;  stu[1].age = 18, stu[1].height = 180;  stu[2].age = 10, stu[2].height = 180;  qsort (stu, 3, sizeof (struct Student), stucmp);  int i = 0;  for (i = 0; i < 3; i++)    printf ("age=%d,height=%d\n", stu[i].age, stu[i].height);  return 0;}[hadoop@Arch Pearls]$ a.outage=10,height=180age=10,height=190age=18,height=180[hadoop@Arch Pearls]$ 
原创粉丝点击