含有重复元素的二分查找算法

本文介绍了一种改进的二分查找算法,该算法能够有效处理包含重复元素的数组,并始终返回目标值的第一个出现位置。通过与Rust标准库中二分查找函数的比较,展示了其实现细节与性能表现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 实现

rust已经有binary_search了,但不能很好的处理有重复元素的查找。
下面这个是我按照网上查找到的原理自己实现的,这个处理重复元素比较好,如果key有重复,那么查找到的总是最小的那个index

fn main() {
    let s = [0, 0,0,0,0,1,1,1, 1, 1, 1, 2,2,3, 3, 5, 8, 13, 21, 34, 55];

    let seek = 1;
    let mut left = 0;
    let mut right = s.len()-1;
    let mut mid;
    while left < right {
        mid = (left + right) >> 1;
        assert!(mid < right);
        if s[mid] < seek {
            left = mid + 1;
        }else{
            right = mid;
        }
    }

    //自己实现的二分查找的结果
    println!("search value:{}\nleft:{},right:{}\nfind:\n  idx:{},value:{}",seek,left,right,left,s[left]);

    //调用rust实现的二分查找
    println!("{:?}",s.binary_search(&1));
}

Play地址:https://is.gd/1PJo67
运行结果:

search value:1
left:5,right:5
find:
  idx:5,value:1
Ok(10)

自己实现的二分查找找到了第一个”1”的位置了,而rust自带的binary_search找到的并不一定是第一个”1”

2 简单的性能测试

做了个简单的bench,可以看到我的这个实现与库实现的差别很小,估计库也没有做优化了,先贴结果:

test bench_binary_search … bench: 42 ns/iter (+/- 9)
test bench_binary_search_lib … bench: 41 ns/iter (+/- 11)

这几个全局变量控制测试长度的

static test_len:usize = 1000;
static test_linear_key:u32 = 500;
static test_binary_key:u32 = 200;

注:因为rust自带的binary_search不能很好的处理key重复的情况,所以就用不重复的数组进行测试

2.1 自己实现的算法:

#[bench]
fn bench_binary_search(b: &mut Bencher) {
    let mut v:Vec<u32> = Vec::with_capacity(test_len);
    for i in (0..test_len) {
        v.push(i as u32);
    }

    b.iter(|| {
        let mut left = 0;
        let mut right = test_len-1;
        let mut mid = 0;
        while left < right {
            mid = (left + right) >> 1;
            assert!(mid < right);
            if v[mid] < test_binary_key {
                left = mid + 1;
            }else{
                right = mid;
            }
        }
        assert!((left == right) && (v[left] == test_binary_key));
    });
}

2.2 使用库自带的二分查找:

#[bench]
fn bench_binary_search_lib(b: &mut Bencher) {
    let mut v:Vec<u32> = Vec::with_capacity(test_len);
    for i in (0..test_len) {
        v.push(i as u32);
    }

    b.iter(|| {
        if let Ok(idx) = v.binary_search(&test_binary_key) {
            assert!(v[idx] == test_binary_key);
        }else{
            assert!(false);
        }
    });
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值