实现自动分配子网的功能,其核心思想是利用哈夫曼编码算法来合理地将一个给定的可分配网段划分为多个子网,以满足不同数量主机的需求。下面分别对两个文件进行详细解释:
文件1:子网自动分配主程序
import Huffman
# Assignable_network_segment 可分配网段
ANS = '192.168.127.0/17'
tail = int(ANS.split('/')[1]) # 网络号位数
# 将十进制IP转化为二进制
def get_BinaryIP(IP):
tmp = IP.split('.')
Blist = []
Blist.append("{:08b}".format(int(tmp[0])))
Blist.append("{:08b}".format(int(tmp[1])))
Blist.append("{:08b}".format(int(tmp[2])))
Blist.append("{:08b}".format(int(tmp[3].split('/')[0])))
Blist.append(int(tmp[3].split('/')[1]))
BIPtmp = ''
for i in Blist:
BIPtmp += str(i)
BIP = BIPtmp[:32:] + '/' + BIPtmp[32::]
return BIP
# 将二进制IP转化为十进制
def get_DecimalIP(IP):
tmp = IP.split('/')
Dlist = []
Dlist.append(int(tmp[0][:8:], 2))
Dlist.append(int(tmp[0][8:16:], 2))
Dlist.append(int(tmp[0][16:24:], 2))
Dlist.append(int(tmp[0][24:32:], 2))
DIPtmp = ''
for i in Dlist:
DIPtmp += str(i)
DIPtmp += '.'
DIP = DIPtmp[:-1:] + '/' + str(tmp[1])
return DIP
# 输出大于num的 2的n次方序列 的最小项
def limit_2_index(num):
for i in range(0, 32):
if num < 2**i - 2: # 减2是因为要考虑网络号(全0)和广播号(全1)
return 2**i
def autoAllocateSubnets():
capacity = 2**(32 - tail) # 计算 提供的网段 所能容纳的 主机数量
dic0, dic = {}, {} # dic0存放原始输入信息,dic存放经过limit_2_index函数处理过的输入信息
int_input = list(map(eval, input().split(' '))) # 输入
for i in range(len(int_input)):
dic0[i] = int_input[i]
dic[i] = limit_2_index(int_input[i])
if sum(dic.values()) > capacity:
print("给定的组 主机数量过多")
exit()
frequency = dic
huffman_codes = Huffman.huffman_encoding(frequency)
sorted_huffman_codes = sorted(huffman_codes.items(), key=lambda x: x[0])
for key, value in sorted_huffman_codes:
btail = tail + len(value) # 子网的网络号位数
for i in range(32 - btail): # 将子网的非网络位补齐
get_BinaryIP(ANS)
value += '0'
BIP = get_BinaryIP(ANS)[:tail] + str(value) + '/' + str(btail)
print(dic0[key], ':', get_DecimalIP(BIP))
# print(BIP)
autoAllocateSubnets()
代码功能解释
-
IP地址转换函数:
get_BinaryIP(IP)
:将十进制的IP地址转换为二进制表示。它会将IP地址按点分十进制拆分,然后将每个部分转换为8位二进制字符串,最后拼接起来并添加网络号位数。get_DecimalIP(IP)
:将二进制的IP地址转换为十进制表示。它会将二进制字符串按每8位拆分,然后将其转换为十进制整数,最后拼接成点分十进制格式并添加网络号位数。
-
主机数量适配函数:
limit_2_index(num)
:找到大于num
的最小的2的n次方。由于每个子网需要排除网络号(全0)和广播号(全1),所以这里使用2**i - 2
进行比较。
-
子网自动分配函数:
autoAllocateSubnets()
:- 计算可分配网段所能容纳的主机数量。
- 读取用户输入的每个子网所需的主机数量,并将其转换为大于该数量的最小的2的n次方。
- 检查所有子网所需的主机数量总和是否超过可分配网段的容量,如果超过则输出错误信息并退出程序。
- 使用哈夫曼编码算法对每个子网所需的主机数量进行编码,得到每个子网的哈夫曼编码。
- 根据哈夫曼编码计算每个子网的网络号位数,并将非网络位补齐为0。
- 将二进制的子网IP地址转换为十进制并输出。
文件2:哈夫曼编码实现
import heapq
from collections import defaultdict, deque
class Node:
def __init__(self, char=None, freq=0):
self.char = char
self.freq = freq
self.left = None
self.right = None
# 定义比较运算符,用于优先队列(最小堆)
def __lt__(self, other):
return self.freq < other.freq
def build_huffman_tree(frequency):
heap = [Node(char, freq) for char, freq in frequency.items()]
heapq.heapify(heap)
while len(heap) > 1:
left = heapq.heappop(heap)
right = heapq.heappop(heap)
merged = Node(freq=left.freq + right.freq)
merged.left = left
merged.right = right
heapq.heappush(heap, merged)
return heap[0]
def generate_huffman_codes(root, prefix="", codebook={}):
if root is not None:
if root.char is not None:
codebook[root.char] = prefix
generate_huffman_codes(root.left, prefix + "0", codebook)
generate_huffman_codes(root.right, prefix + "1", codebook)
return codebook
def huffman_encoding(frequency):
root = build_huffman_tree(frequency)
huffman_codes = generate_huffman_codes(root)
return huffman_codes
代码功能解释
-
节点类:
Node
:定义了哈夫曼树的节点结构,包含字符、频率、左子节点和右子节点。__lt__
方法用于定义节点之间的比较规则,以便在优先队列(最小堆)中使用。
-
哈夫曼树构建函数:
build_huffman_tree(frequency)
:根据输入的字符频率构建哈夫曼树。它首先将每个字符及其频率封装成节点,并将这些节点放入最小堆中。然后不断从堆中取出两个频率最小的节点,合并成一个新节点,并将新节点放回堆中,直到堆中只剩下一个节点,该节点即为哈夫曼树的根节点。
-
哈夫曼编码生成函数:
generate_huffman_codes(root, prefix="", codebook={})
:递归地遍历哈夫曼树,生成每个字符的哈夫曼编码。对于左子树,编码添加0
;对于右子树,编码添加1
。当遍历到叶子节点时,将字符及其编码存入字典codebook
中。
-
哈夫曼编码主函数:
huffman_encoding(frequency)
:调用build_huffman_tree
构建哈夫曼树,然后调用generate_huffman_codes
生成哈夫曼编码,并返回编码字典。
测试用例
请将两个文件复制在同一路径下并运行,文件1命名为AutoAllocateSubnets.py
文件2命名为Huffman.py
,并运行文件1。
-
输入1:
58 100 27 15
-
输出1:
58 : 194.2.3.128/26
100 : 194.2.3.0/25
27 : 194.2.3.192/27
15 : 194.2.3.224/27 -
输入2:
1 1 1 1
-
输出2:
1 : 194.2.3.64/26
1 : 194.2.3.192/26
1 : 194.2.3.0/26
1 : 194.2.3.128/26 -
输入3:
56 100 32 15
-
输出3:
给定的组 主机数量过多
注意
- 可根据需求修改文件1代码第四行
ANS = '192.168.127.0/17'
部分 - 当修改 ANS 时,为了确保程序能够正确运行并合理地分配子网,以下是相关的提醒与注意事项:
- 网段格式:ANS 必须遵循 IP地址/子网掩码长度 的格式,例如 192.168.127.0/17。其中,IP 地址是点分十进制形式,子网掩码长度是一个介于 0 到 32 之间的整数,表示网络号的位数。
- 子网掩码长度:子网掩码长度决定了可分配网段中主机的数量(2 ^ (32 - 子网掩码长度))。修改 ANS 时,需要确保子网掩码长度合理,既能满足实际需求,又不会浪费过多的 IP 地址。同时,要考虑到每个子网需要排除网络号(全 0)和广播号(全 1),因此实际可用的主机数量为 2 ^ (32 - 子网掩码长度) - 2。
- 网络地址合法性:确保修改后的 ANS 所代表的网络地址是合法的。例如,不能使用私有 IP 地址范围之外的地址,除非你明确知道自己的网络环境允许这样做。常见的私有 IP 地址范围包括:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16