Chinaunix首页 | 论坛 | 博客
  • 博客访问: 914888
  • 博文数量: 119
  • 博客积分: 2493
  • 博客等级: 大尉
  • 技术积分: 2363
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-03 14:00
文章分类

全部博文(119)

文章存档

2013年(19)

2012年(100)

分类: LINUX

2012-08-11 09:50:26

       线性表不难理解,就是所谓的数组,链表。基于该数据结构常用
的查找方式就是二分查找,时间复杂度是O(log(n)),而不可能使用遍
历的方式查找,那样时间复杂度是O(n),在内核里面使用二分查找的场
景还比较多,所以想总结下二分查找。
-------------------------------------------------------------------------------
一,二分查找我所理解的算法。
 算法:
      <1>,将n个元素分成个数大致相同的两半。
      <2>,取a[n/2]与x的值比较有如下三种结果:
           2.1,如果x = a[n/2],则找到x,算法结束。
           2.2,如果x > a[n/2],则只需在数组a的右半部找。
                   将left = mid + 1,然后转到<1>。
           2.3,如果x < a[n/2],则只需在数组a的左半部找。
                   将right = mid - 1,然后转到<1>。
      <3>,如果没有找到,则返回一个没有找到的标志,算法结束。
--------------------------------------------------------------------------------
二,我眼中的二分查找代码。
   尽管写的比较简单,但整个算法的思想还是体现出来了。

  1. int binary_search(int a[],int lo,int hi,int x)
  2. {
  3. int left = lo;
  4. int right = hi;
  5. int mid = 0;

  6. while (left <= right) {
  7. mid = (left + right) >> 1;
  8. if (x == a[mid])
  9. return mid;
  10. else if (x > a[mid])
  11. left = mid + 1;
  12. else
  13. right = mid - 1;
  14. }

  15. return -1;

  16. }
--------------------------------------------------------------------------------
三,二分查找的扩展。
假如现在排序数组中有出现重复的数字,而我要搜索这重复数字中的第一个。
例如,a[] = {1,2,3,3,3,3,4,5}当要搜索3时返回第一个3的下标。

算法思想:
         可以使用“二分查找嵌套”的思想,首先是找到这个数字,然后在这些
重复的数字中查找第一个。

算法的实现代码如下:

  1. int get_first_k(int a[],int start,int end,int k)
  2. {
  3.             if (start > end)
  4.                 return -1;
  5.             int mid = (start + end) >> 1;
  6.             int mid_data = a[mid];
  7.             
  8.             if (mid_data == k) {
  9.                     if (mid == 0 || (mid > 0 && a[mid-1] != k)) {
  10.                             return mid;
  11.                     }else {
  12.                             end = mid - 1;
  13.                     }
  14.             } else if (mid_data > k) {
  15.                     end = mid - 1;
  16.             } else {
  17.                     start = mid + 1;
  18.             }
  19.         return get_first_k(a,start,end,k);
  20. }
同样,如果是要搜索这排序数组的某个数字,如果这个这个数字有重复,则返回
最后的一个。算法思想是一样的。

--------------------------------------------------------------------------------
四,内核里面二分查找的实现代码分析。

  1. /*
  2.  * bsearch - binary search an array of elements
  3.  * @key: pointer to item being searched for
  4.  * @base: pointer to first element to search
  5.  * @num: number of elements
  6.  * @size: size of each element
  7.  * @cmp: pointer to comparison function
  8.  *
  9.  * This function does a binary search on the given array. The
  10.  * contents of the array should already be in ascending sorted order
  11.  * under the provided comparison function.
  12.  *
  13.  * Note that the key need not have the same type as the elements in
  14.  * the array, e.g. key could be a string and the comparison function
  15.  * could compare the string with the struct's name field. However, if
  16.  * the key and elements in the array are of the same type, you can use
  17.  * the same comparison function for both sort() and bsearch().
  18.  */
  19. void *bsearch(const void *key, const void *base, size_t num, size_t size,
  20.      int (*cmp)(const void *key, const void *elt))
  21. {
  22.     size_t start = 0, end = num;
  23.     int result;

  24.     while (start < end) {
  25.         size_t mid = start + (end - start) / 2;

  26.         result = cmp(key, base + mid * size);
  27.         if (result < 0)
  28.             end = mid;
  29.         else if (result > 0)
  30.             start = mid + 1;
  31.         else
  32.             return (void *)base + mid * size;
  33.     }

  34.     return NULL;
  35. }
内核里面的二分查找的实现有什么优点呢?
 我觉得可拓展性特别好,就是代码没有写死,只要是想用二分查找的场景
都可以用。

1,类型的可拓展性。人家的函数的形参都是用的void *类型,这说明所有
类型的数组都可以适合,void表示“无”,“无”就表示“任意”,就像
白光是有七色光组成的一样。

2,比较的可拓展性。人家的比较需要自己写比较函数,如何比较由用户自己
决定,比较的方式也通过参数的方式传入到函数里面。

3,查找范围的可拓展性。这地方有一个base参数,说的就是从哪个地方开始
查找。这样用户就可以自己按照想查找的范围进行查找了。
--------------------------------------------------------------------------------
四,学习内核里面的二分查找,我们也可以把内核里面的二分查找的思想和
代码复用到用户态下。
    

下面有一个简单的实例:
    my_bsearch.rar  

----------------------------------------------------------------------------

阅读(2054) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~