我有一个ipv4地址文件,众所周知,每个文件都是4字节。我希望对文件内容进行二进制搜索以找到给定的IP地址。 Rust具有内置的二进制搜索功能,但它不允许您传递len,而是从向量中读取它。
我试图适应内置的rust二进制搜索,但是有点迷失了。这是我到目前为止的位置。也许有一种使用内置方法的方法?
fn binary_search(s: &Vec<&u8>, x: &u32) -> Result<usize, usize> {
let f = |p: &[u8]| p.cmp(x); // need to compare byte slices somehow
let mut size = s.len() / 4;
if size == 0 {
return Err(0);
}
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
let cmp = f(s[mid..mid+4]);
base = if cmp == Greater { base } else { mid };
size -= half;
}
let cmp = f(s[base..base+4]);
if cmp == Equal {
Ok(base)
} else {
Err(base + (cmp == Less) as usize)
}
}
答案 0 :(得分:1)
最好有一个切片,每个地址有一个元素,可以是4字节数组([u8; 4]
),某些等效结构(hey,Ipv4Addr
)或仅{{1 }}。不幸的是,我认为无法将长度为4的u32
重新解释为&[u8]
(其他选项需要对齐)。不过,您可以在分块读取文件的同时进行此转换。
首先,在一个等效的示例程序中:
&[[u8; 4]]
然后从文件中读取内容类似于:
use std::net::Ipv4Addr;
fn main() {
let vec: Vec<Ipv4Addr> = vec![
[10, 0, 0, 0].into(),
[20, 0, 0, 0].into(),
[30, 0, 0, 0].into(),
];
println!("vec {:?}", vec);
let found = vec.binary_search(&Ipv4Addr::from_str("20.0.0.0").unwrap());
println!("found {:?}", found);
}
(尽管这个稍微松懈,因为它忽略了所有不构成4的倍数的尾随字节)
其中let mut vec: Vec<Ipv4Addr> = vec![];
loop {
let mut address = [0; 4];
match f.read_exact(&mut address) {
Ok(()) => {},
Err(err) if err.kind() == ErrorKind::UnexpectedEof => break,
err => err?,
}
vec.push(address.into());
}
是文件周围的f
。
答案 1 :(得分:0)
我认为我现在有一个可行的解决方案,但是我不是rust的专家,所以请对其进行严厉的批评。
use std::cmp::Ordering::{self, Equal, Greater, Less};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
fn binary_search(s: Vec<u8>, x: Vec<u8>) -> Result<usize, usize> {
let f = |p: &[u8]| p.cmp(&x);
let mut size = s.len() / 4;
if size == 0 {
return Err(0);
}
let mut base = 0usize;
while size > 1 {
let half = size / 2;
let mid = base + half;
// mid is always in [0, size), that means mid is >= 0 and < size.
// mid >= 0: by definition
// mid < size: mid = size / 2 + size / 4 + size / 8 ...
let cmp = f(s[mid*4..(mid+1)*4].to_vec());
base = if cmp == Greater { base } else { mid };
size -= half;
}
// base is always in [0, size) because base <= mid.
let cmp = f(s[base*4..(base+1)*4].to_vec());
if cmp == Equal {
Ok(base*4)
} else {
Err(base*4 + ((cmp == Less) as usize) * 4)
}
}
fn main() {
let vec: Vec<u8> = vec![10, 0, 0, 0, 20, 0, 0, 0, 30, 0, 0, 0];
println!("vec {:?}", vec);
let found = binary_search(vec, Ipv4Addr::from_str("20.0.0.0").unwrap().octets().to_vec());
println!("found {:?}", found);
}