注册一亩三分地论坛,查看更多干货!
您需要 登录 才可以下载或查看附件。没有帐号?注册账号 
x
最近看版上空气床的面经,发现大家经常提到一个ip2cidr的题目,找不到代码,于是自己现实了一把,供大家讨论参考。
题目:给一个IP地址范围,比如"10.10.1.1" - "10.12.235.12",转换成其CIDR表示。CIDR(classless inter-domain routing)的定义可以自行google,这题的主要意思就是转换成一系列的CIDR地址,刚好覆盖给出的IP地址范围(不多不少)。
算法:
从一个简单的例子开始:
比如IP地址范围是 0.0.0.111 - 0.0.0.120,对应的二进制表示如下
1101111 - 111
1110000 - 112
...
1110111 - 119
1111000 - 120
显然 0.0.0.(11000000)/24可以覆盖整个地址区间。但是这个CIDR不是一个“合格”的CIDR,因为它的范围太大了,超出了输入的IP地址范围,所以我们要进一步缩小。
缩小的办法是把这个最大的CIDR对半分得到两个CIDR:
- 0.0.0.(11000000)/24
- 0.0.0.(11100000)/25
我们可以把输入的IP地址范围分到这两个CIDR中去,然后再递归求解,直到CIDR恰好覆盖IP区间,则得到合格的CIDR。
具体代码
- uint32_t IpToInt(string &ip) {
- vector<string> segments;
- boost::split(segments, ip, [](char ch) {return ch == '.'; });
- uint32_t res = 0;
- uint32_t mul = 1;
- for (int i = 0; i < segments.size(); ++i) {
- res = res << 8; //every time left shift 8 bits
- res += boost::lexical_cast<uint32_t>(segments[i]);
- }
- return res;
- }
- string IntToIp(uint32_t ip) {
- string res;
- for (int i = 0; i < 4; ++i) {
- uint32_t mod = ip % 256;
- res = to_string(mod) + (i != 0 ? ".": "") + res;
- ip = ip >> 8;
- }
- return res;
- }
- void helper(uint32_t start, uint32_t end, uint32_t prefix, int prefix_length, vector<string> &ans) {
- uint32_t range_start = prefix;
- uint32_t range_end = prefix + ((uint64_t)1 << (32 - prefix_length)) - 1;
- if (start == range_start && end == range_end) {
- string cidr;
- cidr = IntToIp(prefix);
- cidr.append("/");
- cidr.append(to_string(prefix_length));
- ans.push_back(cidr);
- return;
- }
- uint32_t prefix_1 = prefix + (1 << (31 - prefix_length));
- if (end < prefix_1) {
- helper(start, end, prefix, prefix_length + 1, ans);
- }
- else if(start >= prefix_1){
- helper(start, end, prefix_1, prefix_length + 1, ans);
- }
- else {
- helper(start, prefix_1 - 1, prefix, prefix_length + 1, ans);
- helper(prefix_1, end, prefix_1, prefix_length + 1, ans);
- }
- }
- void IpToCidr(string start_ip, string end_ip, vector<string> &ans) {
- uint32_t start = IpToInt(start_ip);
- uint32_t end = IpToInt(end_ip);
- int prefix_length = 0;
- while (prefix_length <= 31) {
- uint32_t mask = 1 << (31 - prefix_length);
- if (mask & end) {
- break;
- }
- else {
- ++prefix_length;
- }
- }
- helper(start, end, 0, prefix_length, ans);
- }
复制代码 |