算法之二分法查找及其变种

二分查找就是将查找的键和子数组的中间键作比较,如果被查找的键小于中间键,就在左子数组继续查找;如果大于中间键,就在右子数组中查找,否则中间键就是要找的元素。

一、二分法查找

/**
 * 二分法查找,前提:数组必须先排好序
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int binarySearch(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = (low + high) / 2;
        if(arrs[m] == target) {
            return m;
        }
        if(target < arrs[m]) {
            high = m - 1;
        }
        if(target > arrs[m]) {
            low = m + 1;
        }
    }
    return -1;
}

二、二分法查找变种

关于二分查找,如果条件稍微变换一下,比如:数组之中的数据可能可以重复,要求返回匹配的数据的最小(或最大)的下标;更近一步, 需要找出数组中第一个大于key的元素(也就是最小的大于key的元素的)下标,等等。 这些,虽然只有一点点的变化,实现的时候确实要更加的细心。

二分查找的变种和二分查找原理一样,主要就是变换判断条件(也就是边界条件),还有就是注意判断返回值,是 low还是 high。

二分查找变种较多,不过它们的“套路”是一样的,基本步骤如下:
1. 根据要求判断出比较条件。
2. 判断出是返回low, 还是返回high。
题目中有“第一个/最左边“关键词就返回 low, 题目中有“最后一个/最右边”关键词就返回high。

1、查找第一个与target相等的元素

/**
 * 查找第一个与target相等的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findFirstEqual(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //只要target小于等于就往左移
        if(arrs[m] >= target) {
            high = m - 1;
        } else {
            low = m +1;
        }
    }
    if(low < arrs.length && arrs[low] == target) {
        return low;
    }
    return -1;
}

2、查找最后一个与target相等的元素

/**
 * 查找最后一个与target相等的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findLastEqual(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //只要target小于等于就往右移
        if(arrs[m] <= target) {
            low = m +1;
        } else {
            high = m - 1;
        }
    }
    if(high >= 0 && arrs[high] == target) {
        return high;
    }
    return -1;
}

3、查找最后一个小于target的元素

/**
* 查找最后一个小于target的元素.也就是说返回小于target的最右边元素下标。
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findLastSmaller(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //条件就是题目中的小于target
        if(arrs[m] < target) {
            low = m +1;
        } else {
            high = m - 1;
        }
    }
    //返回最右边
    return high;
}

4、查找第一个等于或者大于target的元素

/**
 * 查找第一个等于或者大于target的元素
 * 
 * @param arrs
 * @param target
 * @return
 */
public static int findFirstEqualLarger(int[] arrs, int target) {
    int low = 0;
    int high = arrs.length - 1;
    int m = 0;

    while(low <= high) {
        m = low + (high - low) / 2;
        //条件就是题目中的等于或者大于target
        if(arrs[m] >= target) {
            high = m - 1;
        } else {
            low = m +1;
        }
    }
    //返回最左边
    return low;
}
以下是C++实现顺序查找算法二分法查找算法的示例代码: ```c++ #include <iostream> #include <vector> #include <algorithm> using namespace std; // 顺序查找算法 int seqSearch(vector<int>& nums, int target) { for (int i = 0; i < nums.size(); i++) { if (nums[i] == target) { return i; } } return -1; // 查找失败 } // 二分法查找算法 int binarySearch(vector<int>& nums, int target) { int left = 0, right = nums.size() - 1; while (left <= right) { int mid = (left + right) / 2; if (nums[mid] == target) { return mid; } else if (nums[mid] < target) { left = mid + 1; } else { right = mid - 1; } } return -1; // 查找失败 } int main() { vector<int> nums = {3, 5, 2, 8, 4, 7, 1, 6}; sort(nums.begin(), nums.end()); // 二分法查找算法需要有序表 int target = 4; int index1 = seqSearch(nums, target); // 调用顺序查找算法 int index2 = binarySearch(nums, target); // 调用二分法查找算法 if (index1 != -1) { cout << "顺序查找成功,目标元素下标为:" << index1 << endl; } else { cout << "顺序查找失败,未找到目标元素" << endl; } if (index2 != -1) { cout << "二分法查找成功,目标元素下标为:" << index2 << endl; } else { cout << "二分法查找失败,未找到目标元素" << endl; } return 0; } ``` 以上代码中,我们使用了STL中的vector容器来存储顺序表元素,并使用sort函数对其进行排序,以便二分法查找算法能够正确执行。在main函数中,我们分别调用了顺序查找算法二分法查找算法,查找目标元素的值为4。最后,根据返回的下标值,输出查找结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值