Chinaunix首页 | 论坛 | 博客
  • 博客访问: 181893
  • 博文数量: 22
  • 博客积分: 1069
  • 博客等级: 准尉
  • 技术积分: 240
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-01 13:40
文章分类

全部博文(22)

文章存档

2015年(4)

2011年(2)

2010年(12)

2009年(4)

我的朋友

分类: C/C++

2010-01-10 16:41:23

 
===========================================
一个函数找出一个整数数组中,第二大的数
分析:利用选择排序法,一趟即可找出
int find_se_max( int data[] , int count)
{
    int maxnumber = data[0] ;
    int se_max = -32767 ;  //int类型中最小的整数
    for ( int i = 1 ; i < count ; i++)
    {
        if ( data[i] > maxnumber )
        {
             se_max = maxnumber ;
             maxnumber = data[i] ;
        }
        else if ( data[i] > se_max )
        {
             se_max = data[i] ;
        }
    }
    return se_max ;
}
===========================================

n个数进行排序(用选择排序法)

1.程序分析:可以利用选择法,即从后n-1个比较过程中,选择一个最小的与第一个元素交换,
  依次类推,即用第二个元素与后n-2个进行比较,并进行交换。
2.程序源代码:

void sortData(int data[],int n)
{
      int i,j,min,temp;
      for(i=0;i      { 
         min=i;
         for(j=i+1;j             if(data[min]>data[j])  //如后面的数小于前面的数,则更改最小数的下标号
                 min=j;

         if(min!=i)

         {
             temp=data[i];                //数据交换
             data[i]=data[min];
             data[min]=temp;

         }
      }
}

===========================================

猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个
第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下
的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
1.程序分析:采取逆向思维的方法,从后往前推断。
2.程序源代码:

int get_first_nums(int day)

{

    int x1=0,x2=1;

    for(;day-1>0;day--) //day为当天,数目为x2(初始为1);day-1为前一天,数目为x1=(x2+1)*2; day-- 为向后退一天

    {

        x1=(x2+1)*2;

        x2=x1;

    }

    return x1;

}

===========================================

输出9*9口诀:

1*1=1

1*2=2 2*2=4

...

1*9=9 2*9=18 ...9*9=81

void print9_9(void)
{
      int i,j,result;
      printf("\n");
      for (i=1;i<10;i++)
      {
          for(j=1;j<=i;j++)
          {
              result=i*j;
              printf("%d*%d=%-3d",i,j,result);/*-3d表示左对齐,占3位*/
          }
          printf("\n");/*每一行后换行*/
      }
}
===========================================

有n个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
1.程序分析:可填在百位、十位、个位的数字都是1234。组成所有的排列后再去掉不满足条件的排列。
2.程序源代码:
void printData(int data[],int n)
{
    int i,j,k;
    for(i=0;i<n;i++)    /*以下为三重循环,组成n位数就组织n重循环*/
   for(j=0;j<n;j++) 
   for (k=0;k<n;k++)
   {
     if (data[i]!=data[k]&&data[i]!=data[j]&&data[j]!=data[k] /*确保ijk三位互不相同*/
     printf("%d,%d,%d\n",data[i],data[j],data[k]);
   }
}

===========================================
从M个数中取出N个最大的数(M>=N)
思路:从M个数据中取出N个数据放到存储量为N的数组中,然后继续遍历直到比数组中最小的元素大时,数组中最小的元素替换为M当前元素,遍历到末尾,数组中的数据即是最终结果。
常用堆排序法维护N个数据,网上的方法很多,先记住这个!
===========================================
一次遍历单向链表找到中间节点:
思路:设计两个指针,一个走两步,一个走一步,两步的到尾时,一步的到中间
inode_p *get_middle_node(inode_p *head)
{
  inode_p *p1=head;
  inode_p *p2=p1;
  while(p2)
  {
    p2=p2->next;
    if(p2)
    {
      p2=p2->next;
      p1=p1->next;
    }
  }
  return p1;
}
一次遍历单向链表找到倒数第n个节点:
思路:设计两个指针p1、p2,p1先走n步,然后一起走,p1到尾时,p2到倒数第n个。
inode_p *get_middle_node(int n,inode_p *head)
{
  inode_p *p1=head;
  inode_p *p2=NULL;
  while((p1 != NULL)&&(--n)>0) 
    p1=p1->next;
  if((p1==NULL)&&(n==0)) //节点数量刚好够
    return head;
  else if(p1!=NULL)      //节点数量够
    p2=head;
  while(p1 != NULL)
  {
    p1=p1->next;
    p2=p2->next;
  }
  return p2;
}
或:
inode_p *get_middle_node(int n,inode_p *head)
{
  inode_p *p1=head;
  inode_p *p2=head;
  int counter;
  for(counter=0;(counter
    p1=p1-next;
  if(n != counter)
    return NULL;
  while(p1 != NULL)
  {
    p1=p1->next;
    p2=p2->next;
  }
  return p2;
}
====================================
确定CPU是大端还是小端:
int check_CPU(void)
{
  union w
  {
    int a;
    char b;
  }c;
  c.a=1;
  return (c.b==1);//c.b==1则返回1,是小端;否则返回0,是大端
}
所谓的大端模式:是指数据的位保存在内存的地址中,而数据的位保存在内存的地址中,
  这样的存储模式有点儿类似于把数据当作字符串顺序处理,地址由小向大增加,而数据从高位往低位放;
所谓的小端模式:是指数据的位保存在内存的地址中,而数据的位保存在内存的地址中,
  这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
====================================
给定一个整型变量a,写两段代码,第一个设置a的bit 3,第二个清除a的bit 3。在以上两个操作中,要保持其它位不变。
解答:采用#defines 和 bit masks 操作;这是一个有极高可移植性的方法,是应该被用到的方法;最佳的解决方案如下:
#define BIT3 (0x1<<3)
static int a;
void set_bit3(void)
{
  a |= BIT3;
}
void clear_bit3(void)
{
  a &= ~BIT3;
}
一些人喜欢为设置和清除值而定义一个掩码同时定义一些说明常数,这也是可以接受的。
主要考点:说明常数、|=和&=~操作。
====================================
试题:写一个函数返回1+2+3+…+n的值(假定结果不会超过长整型变量的范围)
解答:
int Sum( int n )
{
  return ( (long)1 + n) * n / 2; //或return  (1l + n) * n / 2;
}
============================================
访问固定的内存位置(Accessing fixed memory locations)
嵌入式系统经常具有要求程序员去访问某特定的内存位置的特点。在某工程中,要求设置一绝对地址为0x67a9的整型变量的值为0xaa66。编译器是一个纯粹的ANSI编译器。写代码去完成这一任务。
这一问题测试你是否知道为了访问一绝对地址把一个整型数强制转换(typecast)为一指针是合法的。这一问题的实现方式随着个人风格不同而不同。典型的类似代码如下:
int *ptr;
ptr = (int *)0x67a9;
*ptr = 0xaa55;
一个较晦涩的方法是:
*(int * const)(0x67a9) = 0xaa55;
建议采用第一种方法;
=======================================
交换两个变量的值,不使用第三个变量。即a=3,b=5,交换之后a=5,b=3;
有两种解法, 一种用算术算法, 一种用^(异或)
a = a + b;
b = a - b;
a = a - b;
or
a = a^b;// 只能对int,char..
b = a^b;
a = a^b;
or
a ^= b ^= a;
===================================
int a,b,c 请写函数实现C=a+b ,不可以改变数据类型,如将c改为long int,关键是如何处理溢出问题
bool add (int a, int b,int *c)
{
  *c=a+b;
  return(a>0&&b>0&&(*ca||*c>b)));
}
==================================
输出和为一个给定整数的所有组合
例如n=5
5=1+4;5=2+3(相加的数不能重复)
则输出
1,4;2,3。
 
#include

int main(void)
{
  unsigned long int i,j,k;

  printf("please input the number\n");
  scanf("%d",&i); 
  if( i % 2 == 0) 
    j = i / 2;
  else
    j = i / 2 + 1;

  printf("The result is \n"); 
  for(k = 0; k < j; k++) 
    printf("%d = %d + %d\n",i,k,i - k);
  return 0;
}

#include
void main()
{
  unsigned long int a,i=1;
  scanf("%d",&a);
  if(a%2==0)
  { 
    for(i=1;i      printf("%d",a,a-i);
  }
  else
    for(i=1;i<=a/2;i++) 
      printf(" %d, %d",i,a-i);
}
=======================================
读文件file1.txt的内容(例如):
12
34
56
输出到file2.txt:
56
34
12
(逆序)
#include
#include

int main(void)
{
  int MAX = 10;
  int *a = (int *)malloc(MAX * sizeof(int));
  int *b;
   
  FILE *fp1;
  FILE *fp2;

  fp1 = fopen("a.txt","r");
  if(fp1 == NULL)
  {  printf("error1");
     exit(-1);
  }

  fp2 = fopen("b.txt","w");
  if(fp2 == NULL)
  {  printf("error2");
     exit(-1);
  }

  int i = 0; 
  int j = 0;

  while(fscanf(fp1,"%d",&a[i]) != EOF)
  {
    i++;
    j++;
    if(i >= MAX)
    {
       MAX = 2 * MAX;
       b = (int*)realloc(a,MAX * sizeof(int));
       if(b == NULL)
       {
          printf("error3");
          exit(-1);
       }
       a = b;
    } 
  }

  for(;--j >= 0;)
    fprintf(fp2,"%d\n",a[j]);

  fclose(fp1);
  fclose(fp2); 
  return 0;
}
 
一个递规反向输出字符串的例子,可谓是反序的经典例程.

void inverse(char *p)
{
    if( *p = = '\0' )
      return;
    inverse( p+1 );
    printf( "%c", *p );
}

int main(int argc, char *argv[])
{
    inverse("abc\0"); 
    return 0;
}
 
借签了“递规反向输出” ,程序改为:
#include
void test(FILE *fread, FILE *fwrite)
{
  char buf[1024] = {0};
  if (!fgets(buf, sizeof(buf), fread)) 
    return; 
  test( fread, fwrite );
  fputs(buf, fwrite);
}
int main(int argc, char *argv[])
{
  FILE *fr = NULL;
  FILE *fw = NULL;
  fr = fopen("data", "rb");
  fw = fopen("dataout", "wb"); 
  test(fr, fw); 
  fclose(fr); 
  fclose(fw); 
  return 0;
}
=================================
用递归算法判断数组a[N]是否为一个递增数组。
递归的方法,记录当前最大的,并且判断当前的是否比这个还大,大则继续,否则返回false结束:
bool fun( int a[], int n )
{
  if( n= =1 )
    return true;
  if( n= =2 )
    return a[n-1] >= a[n-2];
  return fun( a,n-1) && ( a[n-1] >= a[n-2] );
}
==================================
请列举一个软件中时间换空间或者空间换时间的例子。
时间优化: 
void swap(int *a,int *b)

  int c; c=*a;*a=*b;*b=c;
}
空间优化:
void swap(int *a,int *b)
{
  *a=*a+*b;*b=*a-*b;*a=*a-*b;
}
==================================
有一个16位的整数,每4位为一个数,写函数求他们的和。
解释:
整数1101010110110111
和  1101+0101+1011+0111
感觉应该不难,当时对题理解的不是很清楚,所以写了一个函数,也不知道对不对。
疑问:
    既然是16位的整数,1101010110110111是2进制的,那么函数参数怎么定义呢,请大虾指教。
答案:用十进制做参数,计算时按二进制考虑。
/* n就是16位的数,函数返回它的四个部分之和 */
char SumOfQuaters(unsigned short n)
{
    char c = 0;
    int i = 4;
    do
    {
        c += n & 15; //0b1111
        n = n >> 4;
    } while (--i);

    return c;
}
==================================
写出程序把一个链表中的接点顺序倒排
typedef struct linknode
{
  int data;
  struct linknode *next;
}node;
//将一个链表逆置
node *reverse(node *head)
{
  node *p,*q,*r;
  if((p=head)==NULL) //空链
      return NULL;
  q=p->next;
  while(q!=NULL)     //不只一个节点时
  {
    r=q->next;
    q->next=p;
    p=q;
    q=r;
  }

  head->next=NULL;
  head=p;
  return head;
}
=============================
两个字符串,s,t;把t字符串插入到s字符串中,s字符串有足够的空间存放t字符串
void insert(char *s, char *t, int i)
{
  char *q = t;
  char *p =s;
  if(q == NULL)
    return;
  while(*p!='\0')
  {
    p++;
  }
  while(*q!='\0')
  {
    *p=*q;
    p++;
    q++;
  }
  *p = '\0';
}
===========================================
写一个函数,功能:完成内存之间的拷贝
memcpy source code:
void* memcpy( void *dst, const void *src, unsigned int len )

    register char *d; 
    register char *s; 

    if (len == 0) 
       return dst; 
 
    //if (is_overlap(dst, src, len, len)) 
       //complain3("memcpy", dst, src, len); 
    if(dst==NULL||src==NULL)
        return NULL;
    if(dst==src)
        return src;

    if ( dst > src ) //目标地址在源地址后面时,从后向前复制,避免空间有重叠
    { 
       d = (char *)dst + len - 1; 
       s = (char *)src + len - 1; 
       while ( len >= 4 )
       { 
          *d-- = *s--; 
          *d-- = *s--; 
          *d-- = *s--; 
          *d-- = *s--; 
          len -= 4; 
       } 
       while ( len-- )
       { 
          *d-- = *s--; 
       } 
    }
    else if ( dst < src ) //目标地址在源地址前面时,从前向后复制,避免空间有重叠
    { 
       d = (char *)dst; 
       s = (char *)src; 
       while ( len >= 4 )
       { 
          *d++ = *s++; 
          *d++ = *s++; 
          *d++ = *s++; 
          *d++ = *s++; 
          len -= 4; 
       } 
       while ( len-- )
       { 
          *d++ = *s++; 
       } 
    } 
    return dst; 
}
公司考试这种题目主要考你编写的代码是否考虑到各种情况,是否安全(不会溢出)
各种情况包括:
1、参数是指针,检查指针是否有效
2、检查复制的源目标和目的地是否为同一个,若为同一个,则直接跳出
3、读写权限检查
4、安全检查,是否会溢出
==================================
memcpy拷贝一块内存,内存的大小你告诉它
strcpy是字符串拷贝,遇到'\0'结束
/* memcpy ─── 拷贝不重叠的内存块 */  
void memcpy(void* pvTo, void* pvFrom, size_t size)
{
  void* pbTo = (byte*)pvTo;
  void* pbFrom = (byte*)pvFrom;
  ASSERT(pvTo != NULL && pvFrom != NULL); //检查输入指针的有效性
  ASSERT(pbTo>=pbFrom+size || pbFrom>=pbTo+size);//检查两个指针指向的内存是否重叠
  while(size-->0)
    *pbTo++ == *pbFrom++;
  return(pvTo);
}
===================================
怎么判断链表中是否有环?
bool CircleInList(Link* pHead)
{
  if(pHead = = NULL || pHead->next = = NULL)//无节点或只有一个节点并且无自环
    return (false);
  if(pHead->next = = pHead)//自环
    return (true);
  Link *pTemp1 = pHead;//step 1
  Link *pTemp = pHead->next;//step 2
  while(pTemp != pTemp1 && pTemp != NULL && pTemp->next != NULL)
  { //pTemp走两步,pTemp1走一步,如有环,最终有pTemp=pTemp1
    pTemp1 = pTemp1->next;
    pTemp = pTemp->next->next;
  }
  if(pTemp = = pTemp1) //因有环而退出while循环
    return (true);
  return (false); //无环:pTemp==NULL || pTemp->next==NULL
}
===============================
请编写一个 C 函数,该函数在给定的内存区域搜索给定的字符,并返回该字符所在位置索引值。
int search(char *cpSource, int n, char ch)
{
  int i;
  for(i=0; i  return i;
}
====================================
写一个函数比较两个字符串str1和str2的大小,若相等返回0,若str1大于
str2返回1,若str1小于str2返回-1
int strcmp ( const char * src,const char * dst)
{
  int ret = 0 ;
  while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
  {
    ++src;
    ++dst;
  }
  if ( ret < 0 )
    ret = -1 ;
  else if ( ret > 0 )
    ret = 1 ;
  return( ret );
}
===================================
求1000!的未尾有几个0(用素数相乘的方法来做,如72=2*2*2*3*3);
求出1->1000里,能被5整除的数的个数n1,n1中能再被5整除的数的个数n2,n2中能再被5整除的数的个数n3,依此类推,直到个数n小于5
1000!末尾的零的个数=n1+...+n4(n4<5);

#include
#define NUM 1000

int find5(int num)

  int ret=0;
  while((num=num/5)>0) 
    ret+=num; 
  return ret;
}
int main()

  printf(" the total zero number is %d\n",find5(NUM));
  return 0;
}
========================================
有双向循环链表结点定义为:
struct node
{ int data;
  struct node *front,*next;
};
有两个双向循环链表A,B,知道其头指针为:pHeadA,pHeadB,请写一函数将两链表中data值相同的结点删除

BOOL DeteleNode(Node *pHeader, DataType Value)
{
  if (pHeader == NULL)
    return;
  BOOL bRet = FALSE;
  Node *pNode = pHead;
  while (pNode != NULL)
  {
    if (pNode->data == Value)
    {
      if (pNode->front == NULL) 
      {
        pHeader = pNode->next;
        pHeader->front = NULL;
      }
      else
      {
        if (pNode->next != NULL)
        {
          pNode->next->front = pNode->front;
        }
        pNode->front->next = pNode->next; 
      }

      Node *pNextNode = pNode->next;
      delete pNode;
      pNode = pNextNode;

      bRet = TRUE;
      //不要break或return, 删除所有
    }
    else
    {
      pNode = pNode->next;
    }
  } //while(...)

  return bRet;
} //DeteleNode(...)

void DE(Node *pHeadA, Node *pHeadB)
{
  if (pHeadA == NULL || pHeadB == NULL) 
    return;
  Node *pNode = pHeadA;
  while (pNode != NULL)
  {
    if (DeteleNode(pHeadB, pNode->data))
    {
      if (pNode->front == NULL)
      {
        pHeadA = pNode->next;
        pHeadA->front = NULL;
      }
      else
      { 
        pNode->front->next = pNode->next;
        if (pNode->next != NULL)
        {
          pNode->next->front = pNode->front;
        }
      }
      Node *pNextNode = pNode->next;
      delete pNode;
      pNode = pNextNode;
    }
    else
    {
      pNode = pNode->next;
    }
  } //while(...)
}
========================
编程实现:找出两个字符串中最大公共子字符串,如"abccade","dgcadde"的最大子串为"cad"
思路:通过一次循环找到一次公共字符的开始位置和个数,和上一次的个数对比,若大则更新公共字符的数据,循环结束则返回最大公共字符个数和开始位置。
函数返回:最大公共子字符串的长度,最大公共子字符串的开始处
int GetCommon(char *s1, char *s2, char **r1, char **r2)
{
  int len1 = strlen(s1);
  int len2 = strlen(s2);
  int maxlen = 0;

  for(int i = 0; i < len1; i++)
  {
    for(int j = 0; j < len2; j++)
    {
      if(s1[i] == s2[j])
      {
        int as=i+1, bs=j+1, count=1; //as,bs指向下一个元素
        while(as
            count++;
        //通过s1[++as]==s2[++bs],确定一次内循环找到的公共字符数
       
        if(count > maxlen) //如果本次的公共字符数大,则更新数据
        {
          maxlen = count;
          *r1 = s1 + i;    //指向字符串1最大公共字符的开始处
          *r2 = s2 + j;    //指向字符串2最大公共字符的开始处
        } 
      }
    } //for(...)
  if(len1-i-maxlen<=maxlen) //当不可能产生新的最大公共字符个数时
    break;                  //循环退出,
  }//for(...)
  return maxlen;
}
============================
编程实现:把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列库函数
十六进制形式输出:
char* test16(long num)
{
  char* buffer = (char*)malloc(11);
  buffer[0] = '0';
  buffer[1] = 'x';
  buffer[10] = '\0';

  char* temp = buffer + 2;
  for (int i=0; i < 8; i++)
  {
    temp[i] = (char)(((num<<4*i)>>28)&0xF); //先算最高4位,依次类推 
    temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55; //转为字符0~9,A~F
  }
  return buffer;
}
二进制形式输出:
char* test2(long num)
{
  char* buffer = (char*)malloc(35);
  buffer[0] = '0';
  buffer[1] = 'x';
  buffer[34] = '\0';

  char* temp = buffer + 2;
  for (int i=0; i < 32; i++)
  {
    temp[i] = (char)(((num<>31)&1)+48;
    //先算最高1位,依次类推,转为字符0或1
  }
  return buffer;
}
==============================
题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
程序分析:兔子的规律为数列 1,1,2,3,5,8,13,21...
    本项的值为前两项之和。1,2,3,4,5,6,7 ,8 ...
斐波拉契数列递归实现的方法如下:
 int  Funct( int n )
{
   if(n==0) return 1;
   if(n==1) return 1;
   retrurn  Funct(n-1) + Funct(n-2);
}
请问,如何不使用递归,来实现上述函数? 

解答:int Funct( int n )  //  n 为非负整数
{
   int a=0;
   int b=1;
   int c;
   if(n==0 || n==1)         //第一个月
     c=1; 
   else
     for(int i=2;i<=n;i++)  //应该n从2开始算起
     {
       c=a+b;
       a=b;
       b=c;
     }
   return c;
}
========================================
判断一个字符串是不是回文 :如"abccba"
int IsReverseStr(char *aStr)
{
  int i,j;
  int found=1;
  if(aStr==NULL)
    return -1;
  j=strlen(aStr);
  for(i=0;i    if(*(aStr+i)!=*(aStr+j-i-1)) //第一个和最后一个比较;向中间靠拢
    {
      found=0;
      break;
    }
  return found; //1:是,0:否,-1:空指针
}
=================================
Josephu 问题为:设编号为1,2,… n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m 的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
数学实现:
int lastone(int nums,int step,int start)//nums为个数,step为步数,start为起始位置;所有参数1为起始数
{
    int i,s=0;
    if(nums<2)
      return 0;
    for(i=2;i<=nums;i++)      //通过数学公式得出最后的序号
      s=(s+step)%i;           //效率最高的方法
    return (s+start-1)%nums+1;
}
数组实现:
(1)
#include
int lastone(int num,int steps)//num为总个数,steps为步数
{
  int i,m=num;
  int temp[m];
  int *p=temp;
  for(i=1;i<=num;i++) //初始化数组为1~num
  {
    temp[i-1]=i;
  }
  i=0; //初始化步数
  while(num>1)
  {
    if(*p++ != 0)  //指向数组的指针移动,若指向的值不为0时,步数加1
      i++; 
    if(i==steps-1) //步数到达时,把数组中的数据置为0
    {
      i=0;
      num--;       //退出计数,表明有多少个数据退出
      while(*p==0) //若值为0时,指针移动
      {
        p++;
        if(p>&temp[m-1]) //指针越界时,重置为初始值
          p=temp;           
      }
      *p=0;        //置为0,表明其退出
    }
    if(p>&temp[m-1])  //指针越界时,重置为初始值
      p=temp;
  }
  p=temp;
  while(!(*p++));  //找到不为0的数据
  return *--p;     //返回数据中元素的值,即其序号(1~num)
}
int main(void)
{
  int i,m=7,s=5;
  i=lastone(m,s);
  printf("%d",i);
  getchar();
  return 0;   

(2)
#include
#include
int Josephu(int n, int m)
{
  int flag, i, j = 0;
  int *arr = (int *)malloc(n * sizeof(int));
  for (i = 0; i < n; ++i)
    arr[i] = 1;      //初始化为数组空间1
  for (i = 1; i < n; ++i)  //i是标号,即标示有多少个退出
  {
    flag = 0;        //flag是步数
    while (flag < m) //步数没到时
    {
      if (j == n)    //出界时,重置为0,回头
        j = 0;
      if (arr[j])    //元素数据为1时,步数增加1
        ++flag;
      ++j;           //向前推进一步
    }
    arr[j - 1] = 0;  //元素数据置为0,表明数据退出
    printf("第%4d个出局的人是:%4d号\n", i, j);
  }
  j=1;
  while(!arr[j-1])   //找到最后一个不为0的元素
    j++; 
  free(arr);
  return j;
}
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
  printf("最后胜利的是%d号!\n", Josephu(n, m));
  system("pause");
  return 0;
}
链表实现:
#include
#include
typedef struct Node
{
  int index;
  struct Node *next;
}JosephuNode;
int Josephu(int n, int m)
{
  int i, j;
  JosephuNode *head, *tail;
  head = tail = (JosephuNode *)malloc(sizeof(JosephuNode));
  for (i = 1; i < n; ++i)
  {
    tail->index = i;
    tail->next = (JosephuNode *)malloc(sizeof(JosephuNode));
    tail = tail->next;
  }
  tail->index = i;
  tail->next = head;
 
  for (i = 1; tail != head; ++i)
  {
    for (j = 1; j < m; ++j)
    {
      tail = head;
      head = head->next;
    }
    tail->next = head->next;
    printf("第%4d个出局的人是:%4d号\n", i, head->index);
    free(head);
    head = tail->next;
  }
  i = head->index;
  free(head);
  return i;
}
int main()
{
  int n, m;
  scanf("%d%d", &n, &m);
  printf("最后胜利的是%d号!\n", Josephu(n, m));
  system("pause");
  return 0;
}
========================================
已知strcpy函数的原型是:
char * strcpy(char * strDest,const char * strSrc);
1.不调用库函数,实现strcpy函数。
2.解释为什么要返回char *。
解说:
1.strcpy的实现代码
#include
char * strcpy(char * strDest,const char * strSrc)
{
  //if ((strDest==NULL)||(strSrc==NULL))        //[1] 
    //return NULL;//throw "Invalid argument(s)";//[2]
  assert(strDest!=NULL);
  assert(strSrc!=NULL);     //断言分开判断
  char * strDestCopy=strDest;                 //[3]
  while((*strDest++=*strSrc++)!='\0');       //[4] 
    return strDestCopy;
}
错误的做法:
[1]
(A)不检查指针的有效性,说明答题者不注重代码的健壮性。
(B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。
(C)检查指针的有效性时使用((strDest==0)||(strSrc==0)),说明答题者不知道使用常量的好处。直接使用字面常量(如本例中的0)会减少程序的可维护性。0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误,编译器不能发现,生成的程序内含逻辑错误,很难排除。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
[2]
(A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
(B)return 0;,说明答题者没有掌握异常机制。调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。
[3]
(A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。
[4]
(A)循环写成while (*strDest++=*strSrc++);,同[1](B)。
(B)循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
=========================
unsigned int intvert(unsigned int x,int p,int n)
实现对x的进行转换,p为起始转化位,n为需要转换的长度,假设起始点在右边.
如x=0b0001 0001,p=4(bit 4),n=3(共3位),转换后x=0b0110 0001
unsigned int intvert(unsigned int x,int p,int n)
{
  unsigned int _t = 0;
  unsigned int _a = 1;
  for(int i = 0; i < n; ++i)
  {
    _t |= _a;    //把_t转为MARK(掩码),_t=0b0111;
    _a = _a << 1;
  }
  _t = _t << p;
  x ^= _t;
  return x;
}
========================
阅读(5025) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-08-02 13:30:06

已阅