二分查找和hash查找

转载:http://blog.csdn.net/feixiaoxing/article/details/6844723

无论是数据库,还是普通的ERP系统,查找功能数据处理的一个基本功能。数据查找并不复杂,但是如何实现数据又快又好地查找呢?前人在实践中积累的一些方法,值得我们好好学些一下。我们假定查找的数据唯一存在,数组中没有重复的数据存在。

(1) 普通的数据查找

设想有一个1M的数据,我们如何在里面找到我们想要的那个数据。此时数据本身没有特征,所以我们需要的那个数据可能出现在数组的各个位置,可能在数据的开头位置,也可能在数据的结束位置。这种性质要求我们必须对数据进行遍历之后才能获取到对应的数据。

 1 int find(int array[], int  length, int value)
 2 {
 3     if(NULL == array || 0 == length)
 4         return -1;
 5
 6     for(int index = 0; index < length; index++){
 7         if(value == array[index])
 8             return index;
 9         }
10     return -1;
11 }

分析:

由于我们不清楚这个数据判断究竟需要多少次。但是,我们知道,这样一个数据查找最少需要1次,那么最多需要n次,平均下来可以看成是(1+n)/2,差不多是n的一半。我们把这种比较次数和n成正比的算法复杂度记为o(n)。

(2)上面的数据没有任何特征,这导致我们的数据排列地杂乱无章。试想一下,如果数据排列地非常整齐,那结果会是什么样的呢?就像在生活中,如果平时不注意收拾整齐,那么找东西的时候非常麻烦,效率很低;但是一旦东西放的位置固定下来,所有东西都归类放好,那么结果就不一样了,我们就会形成思维定势,这样查找东西的效率就会非常高。那么,对一个有序的数组,我们应该怎么查找呢?二分法就是最好的方法。

 1 int binary_sort(int array[], int length, int value)
 2 {
 3     if(NULL == array || 0 == length)
 4         return -1;
 5
 6     int start = 0;
 7     int end = length -1;
 8
 9     while(start <= end){
10
11         int middle = start + ((end - start) >> 1);
12         if(value == array[middle])
13             return middle;
14         else if(value > array[middle]){
15             start = middle + 1;
16         }else{
17             end = middle -1;
18         }
19     }
20
21     return -1;
22 }

分析:

上面我们说到普通的数据查找算法复杂度是o(n)。那么我们可以用上面一样的方法判断一下算法复杂度。这种方法最少是1次,那么最多需要多少次呢?我们发现最多需要log(n+1)/log(2)即可。大家可以找个例子自己算一下,比如说7个数据,我们发现最多3次;如果是15个数据呢,那么最多4次;以此类推,详细的论证方法可以在《算法导论》、《计算机编程艺术》中找到。明显,这种数据查找的效率要比前面的查找方法高很多。

(3) 上面的查找是建立在连续内存基础之上的,那么如果是指针类型的数据呢?怎么办呢?那么就需要引入排序二叉树了。排序二叉树的定义很简单:(1)非叶子节点至少一边的分支非NULL;(2)叶子节点左右分支都为NULL;(3)每一个节点记录一个数据,同时左分支的数据都小于右分支的数据。可以看看下面的定义:

1 typedef struct _NODE
2 {
3     int data;
4     struct _NODE* left;
5     struct _NODE* right;
6 }NODE;

那么查找呢,那就更简单了。

 1 const NODE* find_data(const NODE* pNode, int data){
 2     if(NULL == pNode)
 3         return NULL;
 4
 5     if(data == pNode->data)
 6         return pNode;
 7     else if(data < pNode->data)
 8         return find_data(pNode->left, data);
 9     else
10         return find_data(pNode->right, data);
11 }

(4)同样,我们看到(2)、(3)都是建立在完全排序的基础之上,那么有没有建立在折中基础之上的查找呢?有,那就是哈希表。哈希表的定义如下:1)每个数据按照某种聚类运算归到某一大类,然后所有数据链成一个链表;2)所有链表的头指针形成一个指针数组。这种方法因为不需要完整排序,所以在处理中等规模数据的时候很有效。其中节点的定义如下:

1 typedef struct _LINK_NODE
2 {
3     int data;
4     struct _LINK_NODE* next;
5 }LINK_NODE;

那么hash表下面的数据怎么查找呢?

 1 LINK_NODE* hash_find(LINK_NODE* array[], int mod, int data)
 2 {
 3     int index = data % mod;
 4     if(NULL == array[index])
 5         return NULL;
 6
 7     LINK_NODE* pLinkNode = array[index];
 8     while(pLinkNode){
 9         if(data == pLinkNode->data)
10             return pLinkNode;
11         pLinkNode = pLinkNode->next;
12     }
13
14     return pLinkNode;
15 }

分析:

hash表因为不需要排序,只进行简单的归类,在数据查找的时候特别方便。查找时间的大小取决于mod的大小。mod越小,那么hash查找就越接近于普通查找;那么hash越大呢,那么hash一次查找成功的概率就大大增加。

上述为:除留余数法

取关键字k被某个不大于表长m的数p除后所得余数作为哈希函数地址的方法。即:

H(k)=k  mod p

这种方法的关键是选择好p。使得数据集合中的每一个关键字通过该函数转化后映射到哈希表的任意地址上的概率相等。理论研究表明,一般取p为小于m的最大质数或不包含小于20的质因素的合数。

时间: 2024-08-28 00:46:36

二分查找和hash查找的相关文章

trie树查找和hash查找比较(大量数据)

trie树代码 #include<iostream> #include<stdio.h> #include<iostream> #include<string> #include<stdlib.h> #include<fstream> #include<sstream> #include<vector> #include<string> #include<time.h> using na

9.算法之顺序、二分、hash查找

9.算法之顺序.二分.hash查找 一.查找/搜索 - 我们现在把注意力转向计算中经常出现的一些问题,即搜索或查找的问题.搜索是在元素集合中查找特定元素的算法过程.搜索通常对于元素是否存在返回 True 或 False.有时它可能返回元素被找到的地方.我们在这里将仅关注成员是否存在这个问题. - 在 Python 中,有一个非常简单的方法来询问一个元素是否在一个元素列表中.我们使用 in 运算符. >>> 15 in [3,5,2,4,1] False >>> 3 in

协议栈处理中的conntrack HASH查找/Bloom过滤/CACHE查找/大包与小包/分层处理风格

1.路由CACHE的优势与劣势 分级存储体系已经存在好多年了,其精髓在于"将最快的存储器最小化,将最慢的存储器最大化",这样的结果就使资源利用率的最大化,既提高了访问效率,又节省了资源.这是所有的CACHE设计的基本原则. 对于内存访问,几乎所有的CPU都内置了一级cache,二级cache,亲和力好的几个核心甚至设计了三级cache乃至四级cache,然后才是物理 内存,然后是经过精密优化的磁盘交换分区,最后是远程的存储器,这些存储空间逐级变大,访问开销也逐级变大,构成了一个金字塔型

二分查找(折半查找)

二分查找条件:有序数组. 查找原理:查找过程从数组的中间元素开始,如果中间元素正好等于要查找的元素,则搜索过程结束: 如果某一特定元素大于或小于中间元素,则在数组大于或小于中间原色的那一半中查找,而且跟开始一样从中间元素开始比较. 如果在某一步骤数组为空,则代表找不到. 这种搜索算法每一次比较都使搜索范围缩小一半. 时间复杂度:O(logn) 使用二分查找有两个前提条件: 1,待查找的列表必须有序. 2,必须使用线性表的顺序存储结构来存储数据. 下面是实现代码. C#版: namespace B

二分查找 (折半查找)

二分查找又称折半查找,它是一种效率较高的查找方法. [二分查找要求]:1.必须采用顺序存储结构          2.必须按关键字大小有序排列. [优缺点]折半查找法的优点是比较次数少,查找速度快,平均性能好;             其缺点是要求待查表为有序表,且插入删除困难. 因此,折半查找方法适用于 不经常变动而 查找频繁的有序列表. [算法思想]首先,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功:                              否则利用中

Java中常用的查找算法——顺序查找和二分查找

Java中常用的查找算法——顺序查找和二分查找 一.顺序查找: a) 原理:顺序查找就是按顺序从头到尾依次往下查找,找到数据,则提前结束查找,找不到便一直查找下去,直到数据最后一位. b) 图例说明: 原始数据:int[] a={4,6,2,8,1,9,0,3}; 要查找数字:8 代码演示: import java.util.Scanner; /* * 顺序查找 */ public class SequelSearch { public static void main(String[] arg

【1】二分查找(折半查找)

二分查找又称折半查找,它是一种效率较高的查找方法.  [二分查找要求]:1.必须采用顺序存储结构 2.必须按关键字大小有序排列. /** * 二分查找又称折半查找,它是一种效率较高的查找方法. [二分查找要求]:1.必须采用顺序存储结构 2.必须按关键字大小有序排列. * * @author Administrator * */ public static void main(String[] args) { int[] src = new int[] { 1, 3, 5, 7, 8, 9 };

查找算法:二分查找、顺序查找

08年9月入学,12年7月毕业,结束了我在软件学院愉快丰富的大学生活.此系列是对四年专业课程学习的回顾,索引参见:http://blog.csdn.net/xiaowei_cqu/article/details/7747205 查找算法 查找算法是在存在的序列(list) 中查找特定的目标(target),要求序列中每个记录必须与一个关键词(key)关联才能进行查找. 查找算法通常需要两个输入: 1.被查找的序列 2.要查找的关键词 查找算法的输出参数和返回值: 1.返回类型为 Error_co

查找练习 hash——出现过的数字

查找练习 hash--出现过的数字 题目描述 有一个数据字典,里面存有n个数字(n<=100000),小明现在接到一个任务,这项任务看起来非常简单--给定m个数字,分别查询这m个数字是否出现在字典之中:但是考虑到数据量的问题,小明找到了善于编程的你,希望你可以帮他解决这个问题. 输入 输入数据只有一组! 第一行包含两个整数n m,分别代表字典中数字的个数和要查询的数字的个数. 接着n行代表字典中的n个数字. 最后m表示要查询的数字. 输出 如果某个数字存在,则输出YES,否则输出NO 示例输入