虽是读书笔记,可是如转载请注明出处 http://segmentfault.com/blog/exploring/
.. 拒绝伸手复制党算法
想更一进步的支持我,请扫描下方的二维码,你懂的~segmentfault
根据给定的关键字值,在一组数据中肯定一个其关键字值等于给定关键字值的数据元素。
若存在这样的数据元素,则称查找是成功的;不然称查找不成功。一组待查数据元素的集合又称为查找表。函数
关于查找,通常要明确下述两个问题。
(1)查找的方法
按照数据元素的组织方式决定采用的查找方法;为了提升查找方法的效率,又要求数据元素采用某些特殊的组织方式。所以,在研究各类查找方法时,必须弄清各类方法所适用的组织方式。
(2)查找算法的评价
标准有两个:时间复杂度和空间复杂度。在查找算法中,基本运算是给定值与关键字值的比较,因此,咱们引出一个成为平均查找长度(ASL)的概念,做为评价查找算法好坏的依据。spa
对于含有 n 个数据元素的查找表,查找成功时的平均查找长度为:
n
ASL = ∑ Pi* Ci
i=1
其中:Pi 为查找表中第 i 个数据元素的几率,Ci 为查找第 i 个数据元素时需比较的次数。.net
顺序表的几种查找算法:
顺序查找、折半查找和分块查找指针
从第一个元素开始,逐个把元素的关键字值和给定值比较,若某个元素的关键字值和给定值相等,则查找成功;不然,若直至第 n 国记录都不相等,说明不存在知足条件的数据元素,查找失败。code
查找表的存储结构:
既适用于顺序存储结构,也适用于链式存储结构。对象
平均查找长度 ASL 在等几率的状况下
n n
ASL = ∑ Pi*Ci =(∑(n-i+1) )/n =n+1/2
i=1 i=1
平均查找长度 ASL 在等几率的状况下
ASL ≤n/2
优势:
-对结点的逻辑次序 (没必要有序) 和存储结构 ( 顺序、链表都可)无要求;
-当序列中的记录 “基本有序” 或 N 值较小时,是较好的算法;
缺点:
-ASL 较长
顺序表查找算法的特色是简单、容易实现.但其缺点也是不容忽视的,那就是要预先分配最大存储空间、频繁地插入、删除操做效率不好。blog
先将欲查找的数值和该组数据的中间位置上的数值比较,当小于中间值时,再向前查询,大于中间值时向后查询,继续取前面(或后面)一半数据的中间值进行比较,若是小于再向前查询,大于就向后查询,一直到找到或查询完毕为止。排序
折半查找的过程看,以有序表的中间记录做为比较对象,并以中间记录将表分割为两个子表,对子表继续上述操做。因此,对表中每一个记录的查找过程,可用二叉树来描述,二叉树中的每一个结点对应有序表中的一个记录,结点中的值为该记录在表中的位置。一般称这个描述折半查找过程的二叉树为折半查找断定树。
(1)折半查找断定树是一颗BST,即每一个节点的值均大于其左子树上全部节点的值,小鱼右子树上全部节点的值;
(2)折半查找断定树中的结点都是查找成功的状况,将每一个结点的空指针指向一个实际上并不存在的结点——称为外结点,全部外结点便是查找不成功的状况,如图(e)所示。若是有序表的长度为n,则外结点必定有n+1个。
(3)在折半查找断定树中,某结点所在的层数便是查找该结点的比较次数,整个断定树表明的有序表的平均查找长度即为查找每一个结点的比较次数之和除以有序表的长度。
例如,长度为10的有序表的平均查找长度为: ASL = (1×1+2×2+3×4+4×3)/10=29/10
在折半查找断定树中,查找不成功的过程就是走了一条从根节点到外部节点的路径,和给定值进行比较的关键字个数等于该路径上内部结点个数
。整个断定树表明的有序表在查找失败时的平均查找长度即为查找每一个外结点的比较次数之和除之外结点的个数。例如,长度为10的有序表在查找失败时的平均查找长度为: ASL=(3×5+4×6)/11=39/11
总结说来:
折半查找成功的ASL与序列中的具体元素无关
,只取决于序列中元素的数目
。因此,折半查找断定树只与查找表中元素的数目有关
。
采用二分查找方法查找长度为n的线性表时,每一个元素的平均查找长度为O(logn)
1.顺序查找法适合于存储结构为_______的线性表。 A. 散列存储 B. 顺序存储或连接存储 C. 压缩存储 D. 索引存储 2.使用二分查找法时,要求查找表中各元素的键值必须是_______排列的。 A.递增或递减 B.递增 C. 递减 D.无序 3.采用二分查找方法查找长度为n的线性表时,每一个元素的平均查找长度为_______。 A. O(n2) B. O(nlog2n) C.O(n) D. O(log2n) 4. 有一个长度为12的有序表,按二分查找法对该表进行查找,在表内各元素等几率状况下,查找成功所需的平均比较次数为________。 A. 35/12 B. 37/12 C. 39/12 D, 43/12 5.用n个键值构造一棵二排序树,该二叉排序树的最低高度为______。 A. n/2 B. n C. [log2n] D.[log2+1] 1.B 2. A 3. D 4. B 5. D
BST(最基本),红黑树(更平衡查找效率更高的BST)
⑴ 当二叉排序树不空时,首先将给定值 k 与根结点的关键字进行比较,若相等则查找成功;
⑵ 若给定值 k 小于根结点的关键字,则下一次与左子树的根结点的关键字进行比较,若给定值 k 大于根结点的关键字,则与右子树的根接到的关键字进行比较。
如此递归的进行下去直到某一次比较相等,查找成功。若是一直比较到树叶都不等,则查找失败。
总结说来:
二叉排序树查找成功的平均查找长度取决于二叉排序树的形状,而二叉排序树的形状既与结点数目有关,更取决于创建二叉排序树时结点的插入顺序。
也叫散列查找,different from above methods,它的查找并不创建在比较基础上。哈希查找则是经过计算存储地址的方法进行查找的。
哈希查找是创建在哈希表的基础上,它是线性表的一种重要存储方式和检索方法。在哈希表中能够实现对数据元素的快速检索
若已知哈希函数及冲突处理方法,哈希表的创建步骤以下:
Step1.取出一个数据元素的关键字 key,计算其则哈希表中的存储地址 D=H(key)。若存储地址为 D 的存储空间尚未被占用,则将该数据元素存入;不然发生冲突,执行 Step2。
Step2. 根据规定的冲突处理方法,计算关键字为 key 的数据元素之下一个存储地址。若该存储地址的存储空间没有被占用,则存入;不然继续执行 Step2,直到找出一个存储空间没有被占用的存储地址为止。
解决碰撞的方法:
1. 拉链法
:
2. 开放寻址法
$$hash_i =( hash(key) + di ) mod m$$
其中hash(key)为散列函数,m为散列表长,d_i为增量序列,i为已发生碰撞的次数。
增量序列可有下列取法:线性探测
平方探测
伪随机数探测
3. 双重散列 h(k,i) = (h1(k) + i * h2(k)) mod n
4 再散列
⑴线性探测再散列 { D = H(key); ND = (D+di)%m; di 取 1,2,3,……,m-1 线性探测再散列处理冲突的基本思想: 若数据元素在存储地址 D 发生冲突,则放到存储地址(D+1)%m;若又发生冲突则放到存储地址(D+2)%m;若再发生冲突则放到存储地址(D+3)%m;……;直到碰到第一个为空的存储地址(D+i)%m,则将数据元素存放在该存储空间。 ⑵二次探测再散列 { D = H(key); ND = (D+di)%m; di 取 1*1,-1*1,2*2,-2*2,……,K*K,-K*K (K≤m/2) 值得提醒的是,对利用开放地址法查了冲突所产生的哈希表中删除一个元素,不能简单地直接删除,由于这样将截断其它具备相同哈希地址的元素的查找地址,因此应设定一个特殊的标志以代表该元素已被删除。
散列表的查找过程和造表过程一致。
查找过程为:对于待查值,计算散列地址,若散列地址内为空标记,则查找失败;若待查值与该地址内记录关键字相等,则查找成功。 不然,求下一地址,直至散列地址为空标记,或已搜索了表中的全部单元(查找不成功),或待查值与该地址内记录关键字相等(查找成功)为止。 决定散列表平均查找长度的因素主要有散列函数、处理冲突的方法和查找表记录数
作到一道求 哈希表查找成功与查找不成功 状况下平均查找长度的计算问题,迷惑了好一会,在这里总结下来: 首先,你要明白的是平均查找长度求的是指望,那么你就按照求指望的方法来求平均查找长度吧,千万记着指望怎么求平均查找长度就怎么求啊。 题目: 在地址空间为 0~16 的散列区中,对如下关键字序列构造两个哈希表: {Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec} (1) 用线性探测开放地址法处理冲突; (2) 用链地址法(开散列存储)处理冲突 并分别求这两个哈希表在等几率状况下查找成功和查找不成功时的平均查找长度。设哈希函数为 H(key) = i/2, 其中 i 为关键字中第一个字母在字母表中的序号, 以下: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 解决以下: (1) 线性探测进入散列区的次序以下,X 表明冲突,要找下一个空格 Jan -> 5 Feb -> 3 Mar -> 6 Apr -> 0 May -> 6X -> 7 June -> 5X -> 6X -> 7X -> 8 July -> 5X -> 6X -> 7X -> 8X -> 9 Aug -> 0X -> 1 Sep -> 9X -> 10 Oct -> 7X -> 8X -> 9X -> 10X -> 11 Nov -> 7X -> 8X -> 9X -> 10X -> 11X -> 12 Dec -> 2
很明显,查找成功时,查找 Jan、Feb、Mar 等仅须要一次,其他的也能够由上面看出来 因此查找成功时平均查找长度 (ASL) = (1 + 1 + 1 + 1 + 2 + 4 + 5 + 2 + 2 + 5 + 6 + 1) / 12 = 31/12 = 2.58 为何是除以 12 呢?由于查找成功的状况总共有 12 种啊 查找不成功时呢?什么是查找不成功呢?查找不成功就是从查找位置开始直到一个位置为空须要比较的次数。 首先,26/2=13,也就是说查找不成功的状况也只能出如今 0~13 之间,只有这 14 种状况。 举个例子来讲,查找 Aay 吧,根据 hash 表,与 Apr 比较不匹配,接着与 Aug 比较又是不匹配,接着与 Dec 比较又是不匹配,又与 Feb 比较又是不匹配,到了 4 位置的时候为空了,即 4 上内容与 nullkey 比较,结果为空,因此查找 Aay 失败,查找长度为 5。同理也能计算其余的。 最终平均查找失败时平均查找长度为(5+4+3+2+1+9+8+7+6+5+4+3+2+1)/14=60/14。注意啊,这里是除以 14 啊。(这是求指望的方法啊) (2) 链地址法 0 之下有 Apr, Aug 2 之下有 Dec 3 之下有 Feb 5 之下有 Jan, June, July 6 之下有 Mar, May 7 之下有 Oct, Nov 9 之下有 Sep 查找成功时候,查 Apr, Dec, Feb, Jan, Mar, Oct, Sep 各需 1 次,查 Aug, June, May, Nov 各需 2 次,查 July 需 3 次。 因此查找成功时平均查找长度 (ASL) = (1 * 7 + 2 * 4 + 3 * 1) / 12 = 18/12 = 1.5 查找失败时平均查找长度:举个例子吧,查找 Boy,2/2=1,而 1 的地方的指针为空,就不用比较就能够知道不存在,查找产度为 0。查找 Aay,与 Apr 比较不匹配,与 Aug 比较不匹配,同时,Aug 指向下一个节点的指针为空,就能够知道查找失败,查找长度为 2。 因此查找失败的平均查找长度:(2+1+1+3+2+2+1)/14=12/14。