判斷兩個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是否屬於同一子網(牛客網)

兩個題目在輸入輸出要求是不一樣的,所以寫了兩個 

綜上

 

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