数据结构 二分法查找

/* 二分法查找 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
二分法查找是一种在有序数组中查找特定元素的搜索算法
二分法查找的时间复杂度O(logn)
*/

//递归算法
int recurbinary(int *a, int key, int low, int high)
{
    int mid;
    if (low > high)
    {
        return -1;
    }

    mid = low + (high - low) / 2;
    if (a[mid] == key)
    {
        return mid;
    }
    else if (a[mid] > key)
    {
        return recurbinary(a, key, low, mid - 1);
    }
    else
    {
        return recurbinary(a, key, mid + 1, high);
    }
        
}

//非递归算法
int binary(int *a, int key, int n)
{
    int left = 0, right = n - 1, mid = 0;

    mid = left + (right - left) / 2;
    while (left < right && a[mid] != key)
    {
        if (a[mid] < key) 
        {
            left = mid + 1;
        }
        else if (a[mid] > key)
        {
            right = mid;
        }
        mid = (left + right) / 2;
    }

    if (a[mid] == key)
    {
        return mid;
    }

    return -1;

}

int test()
{
    int a[] = { 1,2,3,4,5,6,7,8,9,12,13,45,67,89,99,101,111,123,134,565,677 };
    int b[] = { 677,1,7,11,67 };
    int i = 0;
    for (i = 0; i < sizeof(b) / sizeof(b[0]); i++)
    {
        printf("%d\n", binary(a, b[i], sizeof(a) / sizeof(a[0])));
    }
    return 0;
}

int main()
{
    test();
    printf("-----ok------\n");
    getchar();
    return 0;
}

 进阶版本

/* 二分法查找 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
二分查找中有一个难点,就是我们通常不理解到底是left+还是right-1

红绿灯模型
假设我们需要查找的元素a的值是13,那么我们可以认为小于等于13的部分是红灯区
大于13的部分是绿灯区,
left游标永远处于红灯区,right游标永远处于绿灯区
那么13这个元素就是位于红灯区的最大值
即如果数组中有指定元素,那么最后的取值一定是left
用上述思想,可以很顺利的找到指定元素

有个特殊情况需要考虑,如果数组全红或者全绿,上述逻辑就存在漏洞,
如果是全绿那么left的位置就会处于绿灯区,这与模型思想违背。
优化设计模式,虚拟出一个红节点,一个绿节点,left=-1,right=n,
这样left初始化的时候一定处于红灯区,right一定处于绿灯区。

终止条件是唯一的 left+1=right 
此时left的值等于查找的元素,那么表示找到,
如果left的值不等于查找的元素,那么表示找不到

*/

int red_green_binary_search(int* arr, unsigned int capacity, int key)
{
    int left, right, mid;

    left = -1;
    right = capacity;

    while (left + 1 != right)
    {
        mid = (left + right) / 2;

        if (arr[mid] <= key)
        {
            left = mid;
        }
        else
        {
            right = mid;
        }
    }

    if (left == -1 || arr[left] != key)
    {
        return -1;
    }
    
    return 0;

}

int test()
{
    int a[] = { 1,2,3,4,5,6,7,8,9,12,13,45,67,89,99,101,111,123,134,565,677 };
    int b[] = { 677,1,7,11,67 };
    int i = 0;
    for (i = 0; i < sizeof(b) / sizeof(b[0]); i++)
    {
        printf("check key: %d, %d\n", 
            b[i], 
            red_green_binary_search(a, 
                sizeof(a) / sizeof(a[0]), 
                b[i]));
    }
    return 0;
}

int main()
{
    test();
    printf("-----ok------\n");
    return 0;
}

 

posted on 2019-05-12 17:00  寒魔影  阅读(371)  评论(0)    收藏  举报

导航