【算法】算法的艺术(六)

报数游戏

   n个小孩围成一圈,从1开始报数,报到k的人退出,其余人重新从1报数,仍是报到k退出,直到圈中只剩m个小孩,问最后剩下的是哪些人?
  实例解析:
  本题在这里将借助于数组求解,用链表求解的方法放在第17章算法与数据结构实例中。
  设计思路:用数组元素模拟小孩。定义一个数组,每个元素存入一个数值作为小孩的编号,然后从第一个元素开始报数,报到k的人将编号清0,表示已退出圈子。在报数的过程中,凡是编号为0的人不再参加报数。当数组所有元素都报数后,重新从数组头开始报数,周而复始,直到圈中只剩m个小孩。
#define N 100
  int main()
  {int a[N], n, m, k;
   int i, count, j;
   scanf(“%d%d%d”, &n, &k, &m);
   for(i = 1; i <= n; i++)
     a[i] = i;
   j = n;                         //j:圈中剩余小孩数
   count = 0;                    //为报数做准备,以便第一个小孩报1
   i = 1;                        //从数组的1号元素开始报数       
   while(j > m){
     if(a[i] != 0){             //若小孩未退出圈子
       count++;                  //参加报数
       if(count == k){          //若报到k
         a[i] = 0;               //退出圈子
      count = 0;              //清零,以便重新从1开始报数
         j--;                     //剩余人数减1
       }  
     }
    i++;                         //下一个小孩准备报数
     if(i > n)                   //若越过最后小孩
       i = 1;                    //转到第一个小孩
   }
   for(i = 1; i <= n; i++)
    if(a[i] != 0)
      printf(“%4d”, a[i]);
   getch();
   return 0;
  }
 
 
 

时钟程序
   编写一个程序,显示系统时间,包括小时、分、秒,以及上下午,每秒刷新一次。
  实例解析:
  本实例需要用到与系统时间有关的一些函数。为方便程序员使用,Turbo C在dos.h中,定义了两个结构体,专门用于时间和日期处理:
struct time{
    unsigned char ti_min;    //分
    unsigned char ti_hour;   //小时
   unsigned char ti_hund;   //百分秒
   unsigned char ti_sec;    //秒
  };
  struct date{
    int da_year;           //自1900年以来的年数
    char da_day;          //天数
    char da_mon;         //月数
  };
 
 
  Turbo C还在time.h中提供了一些与时间有关的函数:
  (1)char *ctime(const time_t *clock);
  作用:把clock所指的时间换成如下格式的字符串:Mon Nov 21 11:31:54  2009\n\0。最后两个字符是换行符和空字符。
  (2)char *asctime(const struct tm *t);
  作用:把t所指的时间换成如下格式的字符串:Mon Nov 21 11:31:54  2009\n\0。
  (3)double difftime(time_t time2, time_t time1);
  作用:返回两个时间的差,单位:秒。
   (4)struct tm *localtime(long *clock);
  作用:把clock所指时间转换为当地标准时间并以tm结构指针的形式返回。
long time(long *p);
   作用:给出自1970年1月1日凌晨至今经过的秒数,并将该值写入p所指变量中。
int stime(long *p);
   作用:将p所指时间写入计算机中。
 
   而在dos.h中提供了以下与时间有关的函数:
void gettime(struct time *timep);
   作用:将计算机系统内的时间写入timep所指结构体变量中。
settime(struct time *timep);
   作用:将系统时间设为timep所指的时间。
   本例中只用到函数gettime()。
   程序代码:
#include <dos.h>
#include <conio.h>
int main()
{struct time curtime;
 float cur_hour, cur_min, cur_sec;
 clrscr();
 do{
   printf("The current time is:\n");
   gettime(&curtime);            //得到当前时间
   if(curtime.ti_hour <= 12)
     printf("AM ");
   else{
     printf("PM ");
     curtime.ti_hour -= 12;
   }
   if(curtime.ti_hour < 10)
     printf("0");
   printf("%d:", curtime.ti_hour);
   if(curtime.ti_min < 10)
     printf("0");
   printf("%d:", curtime.ti_min);
   if(curtime.ti_sec < 10)
     printf("0");
   printf("%d", curtime.ti_sec);
   sleep(1);                    //需要conio.h头文件
   clrscr();
 }while(!kbhit());
 return 0;
}
 
 

简单的计算器(一)
   编程,用来计算用户输入的四则运算表达式的值,只含加减乘除,不含括号。
  实例解析:
  表达式中含有加减乘除,乘除的优先级别比加减高。
  我们以键盘输入-3.12 + 2*3.5/4 + 8/2 - 3*6为例来说明算法。
  式子中的2*3.5/4、8/2和3*6要先算,算完之后整个表达式将只有4个数据项,剩下的问题就很简单了。为此我们可以把整个表达式分成4部分(4块),块与块之间必定是由加减号连接的,每块中间只有乘除,没有加减。
  实际上,没有必要先把每块的值都计算出来,在计算表达式的过程中,每遇到一块,可以先把这一块的结果算出来,然后与前面的计算结果进行加减运算,后面块的值可以在用到的时候再计算。
  具体的计算方法是:
  程序开始先定义一个变量result,并初始化为0。
  从头开始处理每一块:提取一个数据,如果数据后面是乘(除),则表示该块计算未结束,继续提取第二个数据并与第一个数据进行乘(除)运算,然后再看后面的运算符,如果还是’*’或’/’,则继续提取数据并进行计算……直到遇到运算符‘+’、‘-’或空字符为止。
  遇到运算符‘+’、‘-’或空字符,都表示该块的计算已经结束,可以将计算结果累加到result中了。
  重复上面的方法,对每一块都作这样的处理,直到表达式结束。result就是最后的结果。
程序代码:
#include "stdio.h"
  #include "stdlib.h"
  float get_num(char **);             
  int main()
  {char a[80];
   int sign = 1;      //对于表达式中的 ‘+’,sign = 1,对于‘-’,sign = -1
   float result = 0;
   char *p;            //用来指向要处理的字符
   clrscr();
   gets(a);
   p = a;
   if(*p == '-') {     //表达式第一个字符若是‘-’
      sign = -1;        //存储符号
      p++;        
   }
   while(*p != 0) {           //没有遇到空字符,则循环
      float  m;                //m用来存储某块的计算结果
    m = sign*get_num(&p);   //get_num执行过程中,p会向后移动
      while( *p == '*' || *p == '/' ){ //该循环求解某块的结果
         if( *p == '*' ) {
         p++;
         m *= get_num(&p);
       }
         else {
          int div;
       p++;
          div = get_num(&p);
          if( div == 0 ) {
         printf("错误!除数为0!\n");
             exit(1);
          }
          else
             m /= div;
       }
      }
      if(*p != '+' && *p != '-' && *p != 0){
         printf("错误!遇到非法字符:%c\n", *p);
         exit(0);
      }
      result += m;    //将上面计算出的某块的结果累加到result中
      if(*p == '+'){
         sign = 1;
         p++;
      }
      else if(*p == '-') {
         sign = -1;
         p++;
      }
      else          //遇到空字符,退出循环
        break;
     }
   printf("The result is %f\n", result);
   getch();
   return 0;
  }
  float get_num(char **pp)    //pp指向p
  {float x = 0, m = 10;
   if(**pp != '.' && (**pp <'0' || **pp >'9') ) {
      printf("错误!运算符后面不是一个有效的数据\n");
      exit(1);
   }
   while(**pp >= '0' && **pp <= '9') {
    x = x*10 + **pp - 48;
      (*pp)++;
   }
   if(**pp == '.') {
      (*pp)++;
      while(**pp >= '0' && **pp <= '9') {
         x += (**pp - 48)/m;
         (*pp)++;
         m *= 10;
      }
   }
   return x;
  }
 
 

简单的计算器(二)
   编程,用来计算用户输入的四则运算表达式的值,含加减乘除和括号。
  实例解析:
  本实例与上例的区别在于表达式中有括号。其实每个括号中的内容都可以看作是一个单独的表达式(也可能又带括号),考虑到这一点,我们可以把程序写为递归调用的方式,遇到括号则调用自己计算括号中表达式的值。相应的程序代码如下:
#include "stdio.h"
  #include "stdlib.h"
  float get_num(char **);
  float calculate(char **);
  int main()
  {char a[80];
   float result;
   char *p;
   clrscr();
   gets(a);
   p = a;
   result = calculate(&p);
   printf("%f\n", result);
   getch();
   return 0;
  }
  float calculate(char **p)
  {float result = 0;
   int sign = 1;
   if(**p == '-') {
      sign = -1;
      (*p)++;
   }
   while(**p != 0 && **p != ')' ) {
     float  m;
     if(**p == '(' ) {
        (*p)++;
        m = sign*calculate(p);  //遇到括号调用自己计算括号中的值
     }
     else
        m = sign*get_num(p);
     while(**p == '*' || **p == '/') {
       if(**p == '*') {
       (*p)++;
       if(**p == '(') {
          (*p)++;
          m *= calculate(p);  //遇到括号调用自己计算括号中的值
       }
       else
         m *= get_num(p);
     }
       else {     
       int div;
       (*p)++;
       if(**p == '(') {
         (*p)++;
         div = calculate(p); //遇到括号调用自己计算括号中的值
       }
       else
         div = get_num(p);
       if(div == 0) {
          printf("diveide by 0!\n");
          exit(1);
       }
       else
          m /= div;
     }
     }
     if(**p != '+' && **p != '-' && **p != 0 && **p != ')'){
         printf("illege character: %c\n",**p);
         exit(0);
     }
     result += m;
     if(**p == '+') {
        sign = 1;
        (*p)++;
     }
     else
       if(**p == '-' ) {
       sign = -1;
       (*p)++;
     }
       else
       if(**p == ')' ) { //遇到右括号,跳过并退出循环返回结果
          (*p)++;
          break;
       }
       else
          break;
   }
   return result;
  }
  float get_num(char **p)
  {float n = 0, m = 10;
   if(**p != '.' && (**p <'0' || **p >'9')) {
      printf("get num error!\n");
      exit(1);
   }
   while(**p >= '0' && **p <= '9') {
      n = n*10 + **p - 48;
      (*p)++;
   }
   if(**p == '.') {
      (*p)++;
      while(**p >= '0' && **p <= '9') {
         n += (**p - 48)/m;
         (*p)++;
         m *= 10;
      }
   }
   return n;
  }
 
 
 
 

本文出自 “成鹏致远” 博客,请务必保留此出处http://infohacker.blog.51cto.com/6751239/1171349

posted @ 2013-06-27 17:37  Leo.cheng  阅读(420)  评论(0编辑  收藏  举报