《编程珠玑》笔记

第二章

例子:将一个具有n个元素的一围向量向左旋转i个位置。例如假设n=8,i=3,那么向量abcdefgh旋转后为defghabc

解法:先考虑ab,转置a得到a`b,再转置b得到a`b`,然后再转置整个a`b`得到(a`b`)`,实际上就是ba。这就导致了下面产生 旋转作用的代码,注释显示了abcdefgh向左旋转三个元素的结果。

reverse(0,i-1)  //cbadefgh

reverse(i,n-1)  //cbahgfed

reverse(0,n-1)  //defghabc

程序:

#include <stdio.h>

char *reverse(char str[], int b, int e)
{
 char temp;
 int i,j;
 for (i=b,j=e;i<(b+e)/2;i++,j--)
 {
  temp = str[i];
  str[i] = str[j];
  str[j] = temp;
 }
 return str;
}

void main()
{
 char string[] = "abcdefgh";
 reverse(string,0,2);//cbadefgh
 printf("%s/n",string);
 reverse(string,3,7);//cbahgfed
 printf("%s/n",string);
 reverse(string,0,7);//defghabc
 printf("%s/n",string);
}

第七章

 利特尔法则:系统中物体的平均数量就是系统中物体离开系统的平均比率和每个物体在系统中所花费的平均时间的乘积。

简洁概括:队列中的平均物体数量是进入率和平均滞留时间之乘积。

例子1:一个夜总会可以容纳60个人,平均来说进入的人们会在里头呆上大约3个小时,所以进入率大约就是每小时20个人。队列上已经排着20个人了,所以我们可能还要等一个小时才能进去。我还不如先回家。

例子2:我在地下室中存有150个盛酒容器,每年我都要喝完(和买回)25个容器的酒。请问每个容器我要保存多少年?利特尔法则告诉我们用150个容器除以25个容器/年即得到6年。

第八章

例子:输入是一个具有n个整型数字(原文中是浮点数字)的向量x,输出其在输入的任何相邻子向量中找出的最大和。例如:如果输入向量包含下面10个元素,a[]={31,-41,59,26,-53,58,97,-93,-23,84},那么该程序返回a[2]和a[6]之和187。

解法:方法1,普通解法,运行时间为O(n*n)

方法2,分治解法,运行时间为O(nlogn)

方法3,扫描算法,它从最左端(元素x[0])开始,一直扫描到最右端(元素x[n-1]),记下所碰到过的最大总和子向量。最大值最初是0。前i个元素中,最大总和子数组要么在i-1个元素中(存储在masxsofar中),要么截至到位置i(存储在maxendinghere中)。我们不计算截至于位置i的最大子向量,反而使用截至于位置i-1的最大子向量。这个方法的关键就是变量maxendinghere。在该循环的第一个赋值语句前,maxendinghere包含了截至于位置i-1的最大子向量的值,复制语句修改它以包含截至于位置i的最大子向量的值。运行时间为O(n)

程序:

#include <stdio.h>
int max(int a,int b)
{
 return a>b?a:b;
}

int maxsum1(int b[])
{
 int sum,maxsofar = 0;
 for (int i=0;i<10;i++)
 {
  sum = 0;
  for (int j=i;j<10;j++)
  {
   sum += b[j];
   maxsofar = max(maxsofar,sum);
  }
 }
 return maxsofar;
}

int maxsum2(int b[],int l,int h)
{
 int i,m,lmax,rmax,sum,t;
 if (l > h)
 {
  return 0;
 }
 if (l == h)
 {
  return max(0,b[l]);
 }
 m = (l+h)/2;
 lmax = sum = 0;
 for (i=m;i>=l;i--)//找左半部分最大子分量
 {
  sum += b[i];
  lmax = max(lmax,sum);
 }
 rmax = sum = 0;
 for (i=m+1;i<=h;i++)//找右半部分最大子分量
 {
  sum += b[i];
  rmax = max(rmax,sum);
 }
 t = max(maxsum2(b,l,m),maxsum2(b,m+1,h));
 return max(lmax+rmax,t);
}

int maxsum3(int b[])
{
 int maxsofar = 0;
 int maxendinghere = 0;
 for (int i=0;i<10;i++)
 {
  maxendinghere = max(maxendinghere+b[i],0);
  maxsofar = max(maxsofar,maxendinghere);
 }
 return maxsofar;
}

void main()
{
 int a[]={31,-41,59,26,-53,58,97,-93,-23,84};
 printf("%d/n",maxsum1(a));
 printf("%d/n",maxsum2(a,0,9));
 printf("%d/n",maxsum3(a));
}

第九章

例子1:递归解法和标记值解法返回数组x[0..n-1]中(n值较大)的最大值(用递归时max最好用函数实现而不用宏实现)

程序:

#include <stdio.h>
int max(int a,int b)
{
 return a>b?a:b;
}

int arrmax1(int x[],int n)//递归解法
{
 if (n == 1)
  return x[0];
 else
  return max(x[n-1],arrmax1(x,n-1));
}

int arrmax2(int x[],int n)//标记值解法
{
 int i=0,maxnumber;
 while (i<n)
 {
  maxnumber = x[i];
  i++;
  while (x[i]<maxnumber)
   i++;
 }
 return maxnumber;
}

void main() x
{
 int a[]={1,9,8,7,6,5,4,3,2,10};
 int len = sizeof(a)/sizeof(a[0]);
 printf("The Max Number in Array is :%d/n",arrmax1(a,len));
 printf("The Max Number in Array is :%d/n",arrmax2(a,len));
}

例子2:多项式Y=Anpow(X,n)+An-1pow(X,n-1)+...+A1pow(X,1)+A0求和

程序:

#include <stdio.h>

int polynomial1(int a[],int x,int n)
{
 int y,xi;
 y = a[0];
 xi = 1;
 for (int i=1;i<n;i++)
 {
  xi = x * xi;
  y = y + a[i] * xi;
 }
 return y;
}

int polynomial2(int a[],int x,int n)
{
 int y;
 y = a[n-1];
 for (int i=n-2;i>=0;i--)
 {
  y = x*y +a[i];
 }
 return y;
}

void main()
{
 int arr[]={1,2,3,4,5,6};
 int len = sizeof(arr)/sizeof(arr[0]);
 printf("多项式Y=Anpow(X,n)+An-1pow(X,n-1)+...+A1pow(X,1)+A0求和/n");
 printf("The Sum Of Polynomial is :%d/n",polynomial1(arr,2,len));
 printf("The Sum Of Polynomial is :%d/n",polynomial2(arr,2,len));
}

第十一章

例子:快速排序法找第k小元素

程序:

#include <stdio.h>
#include <stdlib.h>

void swap(int x[],int a, int b)
{
 int temp = x[a];
 x[a] = x[b];
 x[b] = temp;
}

int randint(int l,int u)
{
 return l+rand()%(u-l+1);
}

void select(int x[],int l,int u,int k)
{
 int i,j,temp,t;
 if (l>=u)
  return;
 swap(x,l,randint(l,u));
 t = x[l];
 i = l;
 j = u+1;
 while (1)
 {
  do
  {
   i++;
  } while(i<=u && x[i]<t);
  do
  {
   j--;
  } while(x[j]>t);
  if (i>j)
   break;
  temp = x[i];
  x[i] = x[j];
  x[j] = temp;
 }
 swap(x,l,j);
 if (j<k)
 {
  select(x,j+1,u,k);
 }
 else if (j>k)
 {
  select(x,l,j-1,k);
 }
}

void main()
{
 int x[8] = {1, -2, 3, 10, -4, 7, 2, -5};
 int k;
 printf("输入要找的第k小元素(0<=k<=7):");
 scanf("%d",&k);
 select(x,0, 7, k);
 printf("%d/n", x[k]);
}

扩展:分治法找第k小元素。找到数组第K小元素后,有且只有x[0]至x[k-1]是比x[k]小的。所以同样算法可解决下面问题,复杂度同为O(n)。
“给定一个具有n个元素的整数集,一个整数t以及一个整数k,如何快速确定该整数集是否存在一具有k个元素的子集,其中各元素的总和至多只能为t”http://hi.baidu.com/balancelife/blog/item/619e73243686b628d507424e.html

程序:

#include <stdio.h>
#define MAXN 8
int x[MAXN] = {1, -2, 3, 10, -4, 7, 2, -5};

void swap(int a, int b)
{
 int ntemp = x[a];
 x[a] = x[b];
 x[b] = ntemp;
}
//分治发(二分)类似快速排序
int MinK(int l, int h, int k)
{
 if (l > h)
  return 0;
 
 int m = l;
 for (int i=l+1; i<=h; i++)
 {
  if (x[i] < x[m])
   swap(++m, i);
 }
 swap(m, l);
 
 if (k == m)
  return x[m];
 else if (k < m)
  return MinK(l, m-1, k);
 else
  return MinK(m+1, h, k);
}

int main(int argc, char* argv[])
{
 //第0小元素是最小元素
 int n = MinK(0, MAXN-1, 6);
 printf("%d/n", n);
 return 0;
}

第十二章

例子1:产生随机整数的排序子集:输入m和n(m<=n),输出一个由m个随机数字组成的有序数列,这些随机数范围是0..n-1。

程序:

#include <iostream.h>
#include <stdlib.h>
void genknuth(int m,int n)
{
 for (int i=0;i<n;i++)
 {
  if (rand()%(n-i)<m)
  {
   cout<<i<<"/n";
   m--;
  }
 }
}
void main()
{
 genknuth(40,50);
}

例子2:弄乱数组内元素顺序

程序:

#include <iostream.h>
#include <stdlib.h>

int randint(int l,int u)
{
 return l+rand()%(u-l+1);
}

void swap(int x[],int a, int b)
{
 int temp = x[a];
 x[a] = x[b];
 x[b] = temp;
}

void main()
{
 int i,n;
 cout<<"输入数组元素个数:";
 cin>>n;
 int *arr = new int[n];
 for (i=0;i<n;i++)
 {
  arr[i] = i+1;
 }
 for (i=0;i<n;i++)
 {
  swap(arr,i,randint(i,n-1));
 }
 for (i=0;i<n;i++)
 {
  cout<<arr[i]<<' ';
 }
 delete [] arr;
}

例子3:两个函数分别返回一个较大的随机数和一个指定输入范围内的随机数

程序:

#include <iostream.h>
#include <stdlib.h>

int bigrand()
{
 return RAND_MAX*rand()+rand();
}

int randint(int l,int u)
{
 return l+rand()%(u-l+1);
}

void main()
{
 cout<<"返回一个较大的随机数:"<<bigrand()<<endl;
 cout<<"返回一个制定输入范围内的随机数:"<<randint(1,10)<<endl;
}

例子4:从0..n-1中随机选择m个整数,既允许重复又需要按照随机顺序输出结果

程序:

#include <stdlib.h>
#include <iostream.h>

void main()
{
 int m,n;
 cout<<"Input m and n(m<=n):"<<endl;
 cin>>m>>n;
 for (int i=0;i<m;i++)
 {
  cout<<rand()%n<<' ';
 }
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值