CIDR合并90分

这是一个关于处理和合并IPv4地址前缀的C++程序。程序首先定义了一个结构体来存储IP前缀,然后实现了判断前缀合法性、进制转换、比较IP前缀及合并子网等功能。主要目的是优化IP地址集合,移除被其他IP包含的子网。程序包括初始化IP前缀、检查子网关系和同级合并等步骤。
摘要由CSDN通过智能技术生成
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include<algorithm>
#include <cstdio>
using namespace std;
struct IP_pre{
//存放标准IP前缀
    int a[4]={0};
    int plen=-1;
};
int z1[8],z2[8],z3[8];
vector<IP_pre> vec;
bool judge(IP_pre ip){
    //判断前缀是否合法,即低n位都为0
    if(ip.plen==32)return true;
    else if(ip.plen==0){
        for(int i=0;i<4;i++){
            if(ip.a[i]==0)continue;
            else return false;
        }
        return true;
    }
    else if(ip.plen%8==0){
        int x=ip.plen/8;
        for(int i=x;i<4;i++){
            if(ip.a[i]==0)continue;
            else return false;
        }
        return true;
    }
    else {
        //不能整除8
        int x=ip.plen/8;
        int y=ip.plen%8;

        for(int i=0;i<8;i++){
            z3[i]=0;
        }
        int a=ip.a[x];
        int num1=0;
        do{//转化为2进制
            z3[num1++]=a%2;
            a=a/2;
        }while(a!=0);
        for(int i=0;i<8-y;i++){//判断后面有无非零数
            if(z3[i]!=0)return false;
        }
        for(int i=x+1;i<4;i++){
            if(ip.a[i]!=0)return false;
        }
        return true;
    }
    return true;
}
void convert(int a,int b){
//进制转换,将10进制转化为2进制
    for(int i=0;i<8;i++){
        z1[i]=0;
        z2[i]=0;
    }
    int num1=0,num2=0;
    do{
        z1[num1++]=a%2;
        a=a/2;
    }while(a!=0);
    do{
        z2[num2++]=b%2;
        b=b/2;
    }while(b!=0);

}
bool cmp(IP_pre ip1,IP_pre ip2){
    for(int i=0;i<4;i++){
        if(ip1.a[i]==ip2.a[i])continue;
        return ip1.a[i]<ip2.a[i];
    }
    return ip1.plen<ip2.plen;
}
void init(string s){
    //初始化为标准串,并存入vector;
    int pos=-1;
    string s1;
    IP_pre ip;
    if(s.find("/")!=string::npos){
        //计算前缀长度
        pos=s.find("/");
        s1=s.substr(pos+1,s.size()-pos);
        ip.plen=atoi(s1.c_str());
        s=s.substr(0,pos+1);
    }
    //标准化
    int i=0;
    while((pos=s.find("."))!=string::npos&&i<=3){
        s1=s.substr(0,pos);
        ip.a[i]=atoi(s1.c_str());
        s=s.substr(pos+1,s.size()-pos);
        i++;
    }
    if(i<4)ip.a[i]=atoi(s.c_str());
    if(ip.plen==-1){
        //说明是省略长度型
        ip.plen=(i+1)*8;
    }
    vec.push_back(ip);
}
void ip_merge(){
//若b为a的子集,移除b
    for(int i=0;i<vec.size()-1;i++){
        if(!judge(vec[i])){
                //不合法的串保留
                continue;
            }
        for(int j=i+1;j<vec.size();j++){
            if(!judge(vec[j])){
                //不合法的串保留
                break;
            }
            int len=vec[i].plen;
            int num=0;
            int flag=1;//如果为0表示不是子集,如果为1表示是子集
            while(len){
                if(len>=8){
                    if(vec[i].a[num]==vec[j].a[num]){
                        num++;
                        len-=8;
                    }
                    else {flag=0;break;}
                }
                else {
                    //前缀长度小于8
                    convert(vec[i].a[num],vec[j].a[num]);
                    int v=7;
                    while(len--){
                        if(z1[v]==z2[v]){v--;}
                        else {flag=0;break;}
                    }
                    break;
                }

            }
            if(flag){
                //是子集
                vec.erase(vec.begin()+j);
                j--;
            }else{
                i++;
            }
        }
    }
}
bool judge_set(IP_pre ip1,IP_pre ip2){
//判断是不是子集
    int len=ip1.plen;
    int num=0;
    if(len==0)return true;
    while(len){
        if(len>=8){
            if(ip1.a[num]==ip2.a[num]){
                num++;
                len-=8;
            }
            else {return false;}
        }
        else {
        //前缀长度小于8
            convert(ip1.a[num],ip2.a[num]);
            int v=7;
            while(len--){
                if(z1[v]==z2[v]){v--;}
                else {return false;}
            }
            if(len<=0)return true;
        }
        
    }
    return true;
}
void rank_merge(){
//同级合并
    int i=0,j=1;
    while(i<vec.size()&&j<vec.size()&&i<j){
        if(vec[i].plen==vec[j].plen){
            IP_pre ip;
            ip.plen=vec[i].plen-1;
            for(int x=0;x<4;x++){
                ip.a[x]=vec[i].a[x];
            }
            if(judge(ip)){
                //表示合法
                if(judge_set(ip,vec[i])&&judge_set(ip,vec[j])){
                    //两个都是子集
                    vec.insert(vec.begin()+i,ip);
                    vec.erase(vec.begin()+i+1);
                    vec.erase(vec.begin()+i+1);
                    for(int j=i+1;j<vec.size();j++){
                        if(judge_set(ip,vec[j])){
                            vec.erase(vec.begin()+j);
                            j--;
                        }
                        else break;
                    }
                    if(i>0){
                        //之前存在元素
                        i--;
                        j--;
                    }
                }
                else {
                    i++;j++;
                }
            }else{
                i++;j++;
            }
        }
        else{i++;j++;}
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--){
        string str;
        cin>>str;
        init(str);
    }
   sort(vec.begin(),vec.end(),cmp);
   ip_merge();
   rank_merge();
   for(int i=0;i<vec.size();i++){
    cout<<vec[i].a[0]<<"."<<vec[i].a[1]<<"."<<vec[i].a[2]<<"."<<vec[i].a[3]<<"/"<<vec[i].plen<<endl;
   }
}
写了好久,超时没拿满分,不知道什么原因。。。。。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值