判断两个IP时候属于同一个子网(华为机试)

题目:

子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。 最为简单的理解就是两台计算机各自的IP地址与子网掩码进行AND运算后,如果得出的结果是相同的,则说明这两台计算机是处于同一个子网络上的,可以进行直接的通讯。

给定两个IP和一个子网掩码,判断两个IP是否属于同一子网。输出0代表不是同一子网,输出1代表是同一子网。同时输出第一个IP与子网掩码相与的结果。

保证输入数据合法

相与过程示范:

IP地址:192.168.0.1 子网掩码:255.255.255.0 AND运算 转化为二进制进行运算:

IP地址:11010000.10101000.00000000.00000001

子网掩码:11111111.11111111.11111111.00000000

AND运算:11010000.10101000.00000000.00000000 转化为十进制后为: 192.168.0.0

输入:

输入一行字符 代表两个ip和一个子网掩码,中间实用空格隔开

eg1: 192.168.1.1 192.168.1.2 255.255.255.0

eg2: 182.168.1.1 192.168.2.1 255.255.255.0

输出:

如果两个ip是同一子网输出0,否则输出1。同时输出第一个ip与子网掩码相与的结果(10进制)

与输入相对应输出:

eg1: 1 192.168.1.0

eg2: 0 192.168.1.0

核心思想1(这是一种很笨的解法):

  1. 输入我是读入了三个字符串,然后使用遍历的方法将数字给分离出来的(这很蠢)
  2. 将IP1,IP2,mask分别转换成对应的32位二进制形式的01数组(对每个数字进行十进制到二进制的转换)
  3. 两个IP分别于mask相与,结果仍然是32位的二进制数组,然后逐位进行比较,即可得出是否是同一子网
  4. 将IP1与mask相与后的二进制数组再转换为对应的十进制形式的IP输出即可

    很明显,这种转换费时费力,很麻烦,很容易出错。所以这种方法很笨

代码:

#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;
vector<int> transToArray(char str[]); //将一个ip字符串转换为各个部分对应的整数,进一步转换为二进制返回
vector<int> trans_to_b2(int num); //将一个十进制的数转换为它的二进制逆序 eg:2 -->01
void isRight(vector<int> ip1, vector<int> ip2, vector<int> mask);//判断两个ip是否在同一子网下,并打印ip1与mask的与值
int trans_to_num(vector<int> ip);//将二进制的ip再转换为十进制
int main()
{
    char ip1[50];
    char ip2[50];
    char mask[50];
    scanf("%s %s %s",ip1,ip2,mask);
    
    vector<int> ip1_trans = transToArray(ip1);
    vector<int> ip2_trans = transToArray(ip2);
    vector<int> mask_trans = transToArray(mask);
    
    isRight(ip1_trans, ip2_trans, mask_trans);
    
}
void isRight(vector<int> ip1, vector<int> ip2, vector<int> mask)
{
	int k = 1;
	for(int i=0; i<32; i++){
		if( ip1[i]==1 && mask[i]==1 ){
			ip1[i] = 1;
		}else{
			ip1[i] = 0;
		}
	}
	for(int i=0; i<32; i++){
		if( ip2[i]==1 && mask[i]==1 ){
			ip2[i] = 1;
		}else{
			ip2[i] = 0;
		}
	}
	for(int i=0; i<32; i++){
		if( ip1[i]!=ip2[i] ){
			k = 0;
		}
	}
	printf("%d ",k);
	trans_to_num(ip1);
}
vector<int> transToArray(char str[])//把字符串转换为二进制存储
{
	vector<int> b2(32);
	b2.clear();
    int len = strlen(str);
    str[len]='.';
    len++;
    int i=0; int j=0;
    for(j=0; j<len; j++){
        if(str[j]=='.'){
            int num = 0;
            for(int k=j-1,t=0; k>=i; t++,k--){
                num += (str[k]-48)*(int)pow(10,t);
            }
            vector<int> t = trans_to_b2(num);
			if( t.size()<8 ){
				for(int k=0; k<8-t.size(); k++)
					b2.push_back(0);
			}
			for(int k=t.size()-1; k>=0; k--){
				b2.push_back(t[k]);
			}
            i = j+1;
        }
    }
    return b2;
}
vector<int> trans_to_b2(int num)
{
	vector<int> tra(8);
	tra.clear();
	while(num!=0){
		tra.push_back(num%2);
		num = num/2;
	}
	return tra;
}
int trans_to_num(vector<int> ip)
{
	int j=7;
	for(int k=0; k<4; k++){
		int num=0;
		for(int i=j,t=0;i>=j-7;i--,t++){
			num+=ip[i]*(int)pow(2,t);
		}
		j+=8;
		if(k<3){
			printf("%d.",num);
		}else{
			printf("%d\n",num);
		}
	}
}

通过图:

核心思想2(目前来说,我觉得这是思路比较清晰的):

  1. 对一个字符串型的ip怎么分割?详见C我的另一篇博客:C++中的字符串分割函数-----strtok
  2. 对应数字也不需要转换为二进制进行相与运算,直接用位与运算符即可。eg: 1&2 等价00000001&00000010,结果就是十进制的0

代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
using namespace std;

vector<char*> split(char str[]);  
//将字符串192.168.1.1 转换为四个字符串 192 168 1 1存储在vector<char*>数组中 
vector<int> trans_to_num(vector<char*> s);
//将vector<char*>数组中的四个字符串 转换成四个整数 存储在vector<int>数组中  
bool isSame(vector<int> ip1,vector<int> ip2,vector<int> mask); 
//判断ip1和ip2是否在同一个子网,采用与运算,就不用转换2进制了
void print(vector<int> ip1,vector<int> mask); 
//输出第一个ip与mask相与的结果 

int main()
{
	char ip1[50];
	char ip2[50];
	char mask[50];
	scanf("%s %s %s",ip1,ip2,mask);
	
	vector<char*> ip1_str = split(ip1);
	vector<char*> ip2_str = split(ip2);
	vector<char*> mask_str = split(mask);
	
	vector<int> ip1_num = trans_to_num(ip1_str);
	vector<int> ip2_num = trans_to_num(ip2_str);
	vector<int> mask_num = trans_to_num(mask_str);
	
	if( isSame(ip1_num,ip2_num,mask_num) ){
		printf("1 "); //在同一子网下 
		print(ip1_num,mask_num);
	}else{
		printf("0 "); //不在同一子网下 
		print(ip1_num,mask_num);
	} 
	
	return 0;
} 
vector<char*> split(char str[])
{
	vector<char*> s;
	char *p;
	
	p = strtok(str, ".");
	s.push_back(p);
	do{
		p = strtok(NULL, ".");
		if(p){
			s.push_back(p);
		}
	}while(p);
	
	return s;
}
vector<int> trans_to_num(vector<char*> s)
{
	vector<int> nums;
	for(int i=0; i<s.size(); i++){
		int num = 0;
		for(int j=strlen(s[i])-1,t=0; j>=0; j--,t++){
			num += (s[i][j]-48)*pow(10,t);
		}
		nums.push_back(num);
	}
	return nums;
}
bool isSame(vector<int> ip1,vector<int> ip2,vector<int> mask) 
{ 
	for(int i=0; i<ip1.size(); i++){
		if((ip1[i]&mask[i])!=(ip2[i]&mask[i])){  //注意,&的优先级低于!=,所以要加括号 
			return false;
		}
	}
	return true;
} 
void print(vector<int> ip1,vector<int> mask)
{
	for(int i=0; i<ip1.size()-1; i++){
		printf("%d.",ip1[i]&mask[i]);
	}
	printf("%d\n",ip1[3]&mask[3]);
}

核心思想3(最变态):

怎么搞呢?使用scanf的格式化输入,直接得到数字(不需要和傻子一样先拆分,再转换,没错,我就是傻子)!!!

 具体是,如果在格式控制字符串中除了格式声明以外还有其他字符,则在输入数据时必须在对应位置上输入与这些字符相同的字符

代码:
int a,b,c;
scanf("a=%d,b=%d,c=%d",&a,&b,&c);
命令行输入:
a=1,b=3,c=2
这时才会将1 3 2分别送入整形变量a,b,c中

我们只用规定一个scanf("%d.%d.%d.%d",&a,&b,&c,&d);就可以轻松分解输入的ip了 

具体实现见我的另一篇博客:判断两个IP是否属于同一子网(牛客网)

两个题目在输入输出要求是不一样的,所以写了两个 

综上

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章