编程珠玑 Pearls(2)
来源:互联网 发布:c语言文件打开方式手机 编辑:程序博客网 时间:2024/05/21 09:03
[TOC]
基本操作的威力
B. 将一个n元一维向量左旋转i个位置。例如,当n=8且i=3时,向量abcdefg旋转为defghabc。简单的代码使用一个n元中间向量在n步内完成该工作。你能仅使用10个额外字节的存储空间,在正比于n的时间内完成向量的旋转。
将x的前i个元素复制到一个临时数组,然后将余下的n-i个元素左移动i个位置,最后将最初的i个元素复制到x余下的位置。
定义一个函数将x左旋转一个位置(其时间正比于n),然后调用函数i次,但该方法产生量过多的运行时间消耗。
杂技算法 -> 要在有限的资源内解决该问题,显然需要更加复杂的程序。有一个成功的方法有点像精巧的杂技动作:移动x[0]到临时变量t,然后移动x[i]到x[0],x[2i]移动到x[i] 以此类推(将x中所有下标对n取模),直到返回取x[0]中的元素,此时改为从t取值,然后终止过程。至此,一次移动结束。循环gcd(n,i)次即可,gcd为最大公约数。
求逆运算 -> x看作a,b两段,其中a的长度为i,旋转操作可化为
a -> a' b -> b'
ab=(a'b')'
- 杂技算法
#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
一点说明:
- 关于解决问题,把程序化成一个个小块,每个小块实现一个小的功能,然后把各个功能块连接起来,组成一个大的应用。上面的程序就是一个很好的例子,
- sign.c负责生成单词的标识,并把生成的表示和单词输出。
- squash.c负责把临近的标识相同的单词按行放在同一行输出。
- 借助linux的sort命令把单词把标识单词相同的聚到一起。
- 关于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]$
阅读全文
0 0
- 编程珠玑 Pearls(2)
- 编程珠玑 Pearls(1)
- 编程珠玑 Pearls(8)
- 编程珠玑 Pearls(15)
- 编程珠玑 Pearls(11 .排序)
- 编程珠玑 Pearls(5)编程小事
- 编程珠玑column15 strings of pearls
- 读《编程珠玑》Programming Pearls <一>
- 【编程珠玑-15章】Strings of pearls
- 编程珠玑 Pearls(3.2) python脚本
- 编程珠玑 Pearls(9. 代码调优)
- 编程珠玑 (续)(1) Pearls C/C++性能监测工具
- 编程珠玑 Pearls(4) 编写正确的程序
- 编程珠玑(2)
- 《编程珠玑》读书笔记2
- 编程珠玑 Chap 2
- 编程珠玑笔记2
- 精美的珍珠来自饱经磨砺——重读《Programming Pearls 编程珠玑》有感
- 编程珠玑 (续)(1) Pearls C/C++性能监测工具
- JEESZ-SSO解决方案
- Zsh配置
- 事件冒泡和事件捕获
- Spring学习笔记之AOP
- 编程珠玑 Pearls(2)
- linux 使用遇到的问题
- 编程珠玑 Pearls(3.2) python脚本
- 编程珠玑 Pearls(1)
- 编程珠玑 Pearls(4) 编写正确的程序
- linux shell脚本攻略笔记
- Cygwin
- 编程珠玑 Pearls(8)
- Java SE Demos and Samples 阅读笔记(1.1 db)