C/C++程序题(21-25)

来源:互联网 发布:数据库基础pdf 编辑:程序博客网 时间:2024/05/16 00:54

21.

通过键盘输入100以内正整数的加、减运算式,请编写一个程序输出运算结果字符串。

输入字符串的格式为:“操作数1 运算符 操作数2”,“操作数”与“运算符”之间以一个空格隔开。

 补充说明:

1. 操作数为正整数,不需要考虑计算结果溢出的情况。

2. 若输入算式格式错误,输出结果为“0”

示例

输入:“4 + 7”  输出:“11”

输入:“4 - 7”  输出:“-3”

输入:“9 ++ 7”  输出:“0” 注:格式错误

#include<iostream>using namespace std;int calculate(char *input,int n){char *p=new char[n];char *q=new char[n];int j=0,m=0;for(int i=0;i<n;){while(1){p[j++]=input[i++];if(input[i]<'0'||input[i]>'9') break;}if(input[i]<'0'||input[i]>'9') break;}int num1=0;for(int i=0;i<j;i++){num1+=(p[i]-'0')*pow(10.0,j-i-1);}if(input[j]!=' '||input[j+2]!=' ') return 0;for(int k=j+3;k<n;){while(1){q[m++]=input[k++];if(input[k]<'0'||input[k]>'9') break;}if(input[k]<'0'||input[k]>'9') break;}int num2=0;for(int i=0;i<m;i++){num2+=(q[i]-'0')*pow(10.0,m-i-1);}int num3=0;if(input[j+1]='+') num3=num1+num2;else if(input[j+1]='-') num3=num1-num2;    else return 0;return num3;}void main(){char *input=new char[100];cin.get(input,100);int n=strlen(input);int result=calculate(input,n);cout<<result<<endl;}

注:分别存取、转换(字符到整数)加数与被加数。




22.

IP地址匹配

问题描述: 
在路由器中,一般来说转发模块采用最大前缀匹配原则进行目的端口查找,具体如下:
IP地址和子网地址匹配:
IP地址和子网地址所带掩码做AND运算后,得到的值与子网地址相同,则该IP地址与该子网匹配。
 
比如:
IP地址:192.168.1.100
子网:192.168.1.0/255.255.255.0,其中192.168.1.0是子网地址,255.255.255.0是子网掩码。
192.168.1.100&255.255.255.0 = 192.168.1.0,则该IP和子网192.168.1.0匹配
 
IP地址:192.168.1.100
子网:192.168.1.128/255.255.255.192
192.168.1.100&255.255.255.192 = 192.168.1.64,则该IP和子网192.168.1.128不匹配
 
最大前缀匹配:
任何一个IPv4地址都可以看作一个32bit的二进制数,比如192.168.1.100可以表示为:11000000.10101000.00000001.01100100,
192.168.1.0可以表示为11000000.10101000.00000001.00000000
最大前缀匹配要求IP地址同子网地址匹配的基础上,二进制位从左到右完全匹配的位数尽量多(从左到右子网地址最长)。比如:
IP地址192.168.1.100,同时匹配子网192.168.1.0/255.255.255.0和子网192.168.1.64/255.255.255.192,
但对于子网192.168.1.64/255.255.255.192,匹配位数达到26位,多于子网192.168.1.0/255.255.255.0的24位,
因此192.168.1.100最大前缀匹配子网是192.168.1.64/255.255.255.192。
 
请编程实现上述最大前缀匹配算法。
要求实现函数: 
void max_prefix_match(const char *ip_addr, const char *net_addr_array[], int *n)
【输入】ip_addr:IP地址字符串,严格保证是合法IPv4地址形式的字符串
        net_addr_array:子网地址列表,每一个字符串代表一个子网,包括子网地址和掩码,
                        表现形式如上述,子网地址和子网掩码用’/’分开,严格保证是
                        合法形式的字符串;如果读到空字符串,表示子网地址列表结束
【输出】n:最大前缀匹配子网在*net_addr_array[]数组中对应的下标值。如果没有匹配返回-1
示例 
输入:
ip_addr = "192.168.1.100"
net_addr_array[] =
{
"192.168.1.128/255.255.255.192",
"192.168.1.0/255.255.255.0",
"192.168.1.64/255.255.255.192",
"0.0.0.0/0.0.0.0",
""
}
输出:n = 2

#include <iostream>  #include<cmath>  using namespace std;    void max_prefix_match(const char *ip_addr,const char *net_addr_array[],int *n)  {      char num[4];      int n1=strlen(ip_addr);      int q=0;      long long s1=0;      int p=3;    for(int i=0;i<n1;i++)//将输入的IP地址转换成长整型      {          if(ip_addr[i]=='.')          {              int t1=0;              for(int j=0;j<q;j++)                  t1+=(num[j]-'0')*pow(10.0,q-j-1);              s1+=t1*pow(256.0,p--);              q=0;          }          else              num[q++]=ip_addr[i];      }      int temp=0;      for(int j=0;j<q;j++)          temp+=(num[j]-'0')*pow(10.0,q-j-1);      s1+=temp;//加上D段,转换后的IP地址存于s1          int m=0;      while(1)      {n1=strlen(net_addr_array[m]);        int k=0;          long long s2=0,s3=0;          q=0;p=3;          for(int i=0;;i++)          {              if(net_addr_array[m][i]=='/') break;              if(net_addr_array[m][i]=='.')              {                  int t1=0;                  for(int j=0;j<q;j++)                      t1+=(num[j]-'0')*pow(10.0,q-j-1);                  s2+=t1*pow(256.0,p--);                  q=0;              }              else                  num[q++]=net_addr_array[m][i];              k++;          }          temp=0;          for(int j=0;j<q;j++)              temp+=(num[j]-'0')*pow(10.0,q-j-1);          s2+=temp;//转换后的子网IP地址存于s2            q=0;p=3;            for(int i=k+1;i<n1;i++)          {              if(net_addr_array[m][i]=='.')              {                  int t1=0;                  for(int j=0;j<q;j++)                      t1+=(num[j]-'0')*pow(10.0,q-j-1);                  s3+=t1*pow(256.0,p--);                  q=0;              }              else                  num[q++]=net_addr_array[m][i];          }          temp=0;          for(int j=0;j<q;j++)              temp+=(num[j]-'0')*pow(10.0,q-j-1);          s3+=temp;//转换后的子网掩码存于s3            long long s4=0;          if((s1&s3)==s2)          {              if(s3>s4)              {                  s4=s3;                  *n=m;            }          }          m++;        if(net_addr_array[m]=="") break;        }    }  void main()  {      int *n=new int;      const char* ip_addr = "192.168.1.100";      const char *net_addr_array[] =      {          "192.168.1.128/255.255.255.192",          "192.168.1.0/255.255.255.0",           "192.168.1.64/255.255.255.192",           "0.0.0.0/0.0.0.0",           ""      };      max_prefix_match(ip_addr,net_addr_array,n);      cout<<*n<<endl;    }  


注:点分十进制IP地址:XXX.XXX.XXX.XXX  分为四段:A.B.C.D ——> 长整型:A*256^3+B*256^2+C*256+D

点分十进制IP转换成长整型:第一步,先把每段字符型数字转化为整型数字{(char-'0')*10的相应倍数再相加}

第二步,公式A*256^3+B*256^2+C*256+D

一个目的地址可能与多个表项匹配。最明确的一个表项,即子网掩码最长的一个,就叫做最长前缀匹配。

IP地址 点十分制转换成长整数型再与掩码的长整型进行&操作。


另:const 修饰函数参数,返回值,函数体 http://blog.csdn.net/youoran/article/details/8517611

1.用const 修饰函数的参数:const 只能修饰输入参数;如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。

2.用const 修饰函数的返回值:如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例如函数:const char * GetString(void);  正确的用法是 const char *str = GetString();(不可去掉const)




23.

数字排序

编写一个程序,实现排序算法,从小到大输出,数字间以逗号分隔,所有数字为非负整数。数目小于1028

输入:1,6,3,5

输出:1,3,5,6

#include <iostream>#include <cmath>using namespace std; void main() { char *input=new char[100]; char *output=new char[100]; int *num=new int[100]; cin>>input; int n=strlen(input); char *temp=new char[10]; int m=0; for(int i=0;i<n;) { int k=0; while(i<n)//防止死循环 { temp[k++]=input[i++]; if(input[i]==',')  { i++;//滤去',' break; } } num[m]=0; for(int j=0;j<k;j++) { num[m]+=(temp[j]-'0')*pow(10.0,k-j-1); } m++;//获取字符串中的数字 }  //大小排序 int tp; for(int i=0;i<m;i++) { for(int j=1;j+i<m;j++) { if(num[i]>num[i+j]) { tp=num[i]; num[i]=num[i+j]; num[i+j]=tp; } } }  int N=0; for(int i=0;i<m;i++)//将排序后的数字变成字符串输出 { int a[10],l=0,p=0; while(p=num[i]%10) { a[l++]=p; num[i]=num[i]/10; } for(int j=0;j<l;j++) { output[N++]=a[l-j-1]+'0'; } if(N<n) output[N++]=','; } for(int i=0;i<n;i++) cout<<output[i]; delete []input; delete []output; delete []num; delete []temp; }
注:思路:先提取数字块(类比前面“块”的提取),字符转整型—>大小排序—>整型转字符—>输出字符串




24.

我们把只包含因子2,3,5的数称为丑数,把1当作第一个丑数,求从小到大的第n个丑数

输入:1都500之间的整数(包含1和500)

输出:第n个丑数。不在1-500输出-1

#include <iostream>using namespace std;bool ISUGLY(int number){while(number%2==0)number=number/2;while(number%3==0)number=number/3;while(number%5==0)number=number/5;if(number==1) return true;else return false;}int find(int n){if(n<1||n>500) return -1;int k=0;for(int i=1;;i++)//注意i的初始值,为0的话造成死循环{if(ISUGLY(i)){k++;if(k==n) return i;}}}void main(){int n;cin>>n;int ugly=find(n);cout<<ugly<<endl;}
注:关键点是丑数判断函数!对2、3、5进行整除,如果最后能整除到底,返回true。这是遍历寻找法。

还有一种方法,比较难理解,但是运行时间短。其主要思想是只计算丑数,而不在非丑数的整数上花费时间。根据丑数的定义,丑数应该是另一个丑数乘以2、3或者5的结果(1除外)。因此我们可以创建一个数组,里面的数字是排好序的丑数。里面的每一个丑数是前面的丑数乘以2、3或者5得到的。
这种思路的关键在于怎样确保数组里面的丑数是排好序的。我们假设数组中已经有若干个丑数,排好序后存在数组中。我们把现有的最大丑数记做M。现在我们来生成下一个丑数,该丑数肯定是前面某一个丑数乘以2、3或者5的结果。我们首先考虑把已有的每个丑数乘以2。在乘以2的时候,能得到若干个结果小于或等于M的。由于我们是按照顺序生成的,小于或者等于M肯定已经在数组中了,我们不需再次考虑;我们还会得到若干个大于M的结果,但我们只需要第一个大于M的结果,因为我们希望丑数是按从小到大顺序生成的,其他更大的结果我们以后再说。我们把得到的第一个乘以2后大于M的结果,记为M2。同样我们把已有的每一个丑数乘以3和5,能得到第一个大于M的结果M3和M5。那么下一个丑数应该是M2、M3和M5三个数的最小者。
前面我们分析的时候,提到把已有的每个丑数分别都乘以2、3和5,事实上是不需要的,因为已有的丑数是按顺序存在数组中的。对乘以2而言,肯定存在某一个丑数T2,排在它之前的每一个丑数乘以2得到的结果都会小于已有最大的丑数,在它之后的每一个丑数乘以2得到的结果都会太大。我们只需要记下这个丑数的位置,同时每次生成新的丑数的时候,去更新这个T2。对乘以3和5而言,存在着同样的T3和T5。

#include <iostream>using namespace std; int min(int a,int b,int c) { if(a>b) a=b; if(a>c) a=c; return a; } void main() { int n; cin>>n; if(n<1||n>500)  cout<<"-1"<<endl; int *p=new int[n]; p[0]=1; int a=0,b=0,c=0; for(int i=1;i<n;i++) { p[i]=min(2*p[a],3*p[b],5*p[c]);//每个丑数都是前面的丑数*2或*3或*5 if(p[i]==2*p[a]) a++; if(p[i]==3*p[b]) b++; if(p[i]==5*p[c]) c++; } cout<<p[n-1]<<endl; delete []p; }
注:每个丑数都是前面的丑数*2或*3或*



25.

描述: 俗话说“条条道路通罗马”,我们要从数学上计算出到底有多少条路。已知有N个城市(N<=10),从0到9编号,城市间要么有一条路,要么没有路,请帮忙计算下从城市A到城市B之间到底有多少条路。
 运行时间限制: 无限制 
内存限制: 128 MByte 
输入: 题目首先输入一行“N A B”(1 < N <= 10; 0 <= A,B <= 9; A != B),N表示有多少个城市,A标识从编号为A的城市出发,B标识目的城市。紧接着输入N行,每行包含N个数字,要么为0,要么为1,标识从该行编号标识的城市到其他所有城市是否有路。
 输出: 一个整数,标识从A到B有多少条路
 样例输入: 3 0 2
1 1 1
1 1 1
1 1 1 
样例输出: 2 

#include <iostream>using namespace std;void main(){int n,a,b;cin>>n>>a>>b;int **mat=new int*[n];int *visit=new int[n];int *que=new int[n];for(int i=0;i<n;i++){mat[i]=new int[n];visit[i]=0;}for(int i=0;i<n;i++)for(int j=0;j<n;j++)cin>>mat[i][j];int top=0,tail=0,num=0;que[tail++]=a;//起点入栈visit[a]=1;//起点标记为已访问状态while(tail!=top){int s=que[top++];for(int i=0;i<n;i++){if(mat[s][i]==1&&visit[i]==0&&i!=b){que[tail++]=i;visit[i]=1;}else if(mat[s][i]==1&&i==b)//找到一条路径,对b不作处理,继续遍历{num++;}}}cout<<num<<endl;delete []que;delete []visit;for(int i=0;i<n;i++){delete []mat[i];}}
此方法是用广度优先搜索(BFS)来寻找路径,第一个寻找到的为最短路径,依次类推。此程序是用数组来实现队列。

直接使用queue结构,示例程序如下(可尝试下打印路径):

#include <iostream>#include <queue>using namespace std;void main(){int n,a,b;cin>>n>>a>>b;queue<int> que;int **mat=new int*[n];int *visit=new int[n];int *pre=new int[n];for(int i=0;i<n;i++){mat[i]=new int[n];visit[i]=0;}for(int i=0;i<n;i++)for(int j=0;j<n;j++)cin>>mat[i][j];que.push(a);//起点入栈visit[a]=1;int num=0;while(!que.empty()){int s=que.front();que.pop();//取出栈顶的值for(int i=0;i<n;i++){if(mat[s][i]==1&&visit[i]==0&&i!=b){que.push(i);visit[i]=1;}else if(mat[s][i]==1&&i==b){num++;}}}cout<<num<<endl;delete []visit;for(int i=0;i<n;i++)delete []mat[i];}




0 0
原创粉丝点击