c语言折半查找法_专业课笔记 9 查找

真题分析

年份填空选择判断综合代码
1321120
1431520
1531220
1611322
1721341
18

静态查找表和动态查找表

动态查找表还可以进行插入和删除操作

折半查找

性质

要求线性表以顺序方式存储,且元素有序。

查找的判定树为一颗「平衡二叉树」

比较流程

最大查找长度

将二分查找的方式类比二叉树,可知时间复杂度和类似于树的深度,即,查找过程和给定值比较的关键字个数最多为,这种描述查找过程的二叉树为判定树。

如果给判定树的所有叶子结点加上外部结点,则查找不成功的时候就是从根结点走到了外部结点,比较的次数最大和最小相差一

有序表查找,判定树,平均查找长度,比较次数

计算平均查找长度时我们可以画出查找的二叉树,查找成功时,平均查找长度为每层的结点数乘以层数之和/结点数,也可以 1248 依次乘以每一层

比较次数就依次折半查找即可,偶数位的中位数选择左边的

(17)画出在有序表 A[1..15]中进行折半查找的判定树,并求出查找成功的平均查找长度

e3f401115fd86013673e619e628d39b2.png
折半查找判定树 (1)

查找成功平均查找长度(1+2x2+3x4+4x8)/15 = 49/15

关于折半查找判定树,可以通过中序填入有序序列,然后看取中是否符合要求来判断

索引顺序表查找(分块查找)

给顺序表分块,保证前一个块的所有数字都比后面一个块最小的要小,记录块的最大关键字和子表起始位置指针

先确定待查记录所在的块(子表),然后在块中顺序查找。

索引法平均查找长度

ASL 为上面两次查找方式之和(二分查找块和顺序查找块中关键字),取长度为 n,每块记录数为 s,块数 b = n/s 上取整,则 asl 为(b + 1)/2 + (s + 1)/2 = 。

易知平均查找长度和表长以及块中记录数 s 有关,当 s=时,asl 取最小值

二叉排序树 BST 的性质

二叉排序树「中序遍历」有序,不存在关键字的值相同

二叉排序树的插入和删除

(06)给定表(17,25,21,9,10,7,3,43),依次插入空的二叉排序树,画出二叉排序树

4042c426ecd0095a0f8da03c5dcd7732.png
画出二叉排序树

每次插入结点都是插入到叶子结点,不必移动其他结点

插入元素的平均复杂度为,比较的次数不会超过树的深度

二叉排序树删除结点要保留二叉排序树的特性

  1. 若删除的为叶子结点,直接删除即可
  2. 若删除的结点存在对应的单边子树,则直接让子树接到根结点
  3. 若删除的结点存在左右子树,则不能简单处理,有两种处理方法
99b346b5598c446b46c2079e10bab6ca.png
二叉排序树删除元素

平衡二叉树 AVL

一定是二叉排序树,插入操作会引起至少一个节点的平衡因子发生变化,左右子树高度差绝对值不超过 1

深度为 n 的平衡二叉树的最少结点数为 F(n + 2) - 1,其中 F 为斐波那契数列 1,1,2,3,5

建立平衡二叉树

先依次插入结点,直到平衡因子不符合要求,选取最下方不符合要求的定为 A,然后进行四种调整;注意每次插入结点的步骤要写好

325ccd84fde00eb6b7758f8ecdac87f8.png
平衡二叉树调整

(13)顺序输入关键字序列(70,80,90,50,40,65,68),画出构成的平衡二叉树,给出过程

5e3f56b55f3d020b7d0652cbeb6fb725.png
建立平衡二叉树

(14)顺序输入关键字序列(50,60,70,30,20,45),画出构成的平衡二叉树,给出过程 (15)顺序输入关键字序列(40,30,20,50,45,60),画出构成的平衡二叉树,给出过程 (16)已知一组关键字为(20,36,48,95,53,100,120,60,15,30,25),直接画出构成的二叉排序树和平衡二叉树

注意这里存在调整一次不满足要求的情况,需要多次调整

86522529728bbfa9d8eb3823c69ddbe3.png
平衡二叉树(多次调整)

(17)顺序输入关键字序列(70,80,90,50,40,65,68),画出构成的平衡二叉树,给出过程

平衡树查找的分析

深度为 n 时,最多查找次数是,在平衡树上查找的时间复杂度为 logn

b-树和 b+树

m 阶 b-树定义

  • 每个结点至多有 m 棵子树,m-1 个关键字个数
  • 若根结点不是叶子节点,则至少有 2 棵子树,1 个关键字
  • 「除根结点之外」的所有非终端节点至少有个子树,结点关键字最少
  • 所有的叶子结点都在同一层上,表示查找失败的结点,实际上不存在,指向这些结点的指针为 null

一些有关 b 树性质的计算:

高度为 h 的 m 阶 b 树的最少最多结点数,结点最少时形状类似于一棵满二叉树,结点最多时形状类似于一棵满 m 叉树

n 个非叶结点的 m 阶 b 树至少包含

高度为 2 的 5 阶 b 树,所含关键字个数至少是 5,根结点只有达到 5 个关键字时才能产生分裂

给出阶数和关键字数,最大高度公式 ,最小高度公式为

证明(17) m 阶 b- 树所具有的最少节点数

深度为 l + 1 的 m 阶 b- 树所具有的最少节点数 

证明如下,第一层至少有 1 个结点,第二层至少有 2 个结点,每个非终端结点至少有个结点,所以第 3 层至少有个结点,以此类推。

所以最坏的情况,查找涉及的结点数不超过

插入

首先在非终端结点尝试插入,若个数不超过 m-1 个则直接插入

否则结点需要分裂为 m-1 个节点,关键字与指针插入双亲结点

8db6040b65fc230a89271845b9f23e0d.png
b-树插入

删除

  • 非终端结点,替代再删
  • 终端结点
    • 相邻兄弟移到双亲
    • 双亲下移删除位置
    • 个数不少于 直接删
    • 等于 相邻大于 
  • 都等于
    • 剩余和双亲转为兄弟
    • 若导致双亲少于 就一直重复处理
e9e65499b8ed7307c8bb4ecd2023f82a.png
b-树删除

b+树

与 b-树的差异

  1. n 棵子树的结点中含有 n 个关键字
  2. 叶子结点包含全部关键字的信息,以及指向这些关键字记录的指针,叶子结点自身依照关键字的大小自小而大的排列
  3. 所有非终端结点可以看作索引,结点中只含有其子树中的最大或最小关键字

b+树可以支持顺序检索,b-树不可以

哈希表

哈希查找是一种「随机查找」方法

不同的哈希函数得到同一哈希地址,这种现象叫做冲突

如果两个关键字的值不等,但是哈希函数值相等,则称这两个关键字为同义词

为了有效的应用 hash 查找技术,需要解决的两个问题,设定一个好的 hash 函数和处理冲突的方法

堆积问题是由于同义词或非同义词之间产生冲突导致的

构造方法

  1. 直接定址法 所得集合和关键字集合的大小相同,所以不同的关键字不会发生冲突

  2. 数字分析法 关键字都是以 r 为基的数,可能出现的关键字都是事先知道的,取关键字的若干位组成哈希地址

  3. 平方取中法 关键字平方后取中间几位作为哈希地址

  4. 折叠法 分割成几部分,然后取这几部分的叠加和作为哈希地址

  5. 除数取余法 除数选择最接近存储空间的素数。

  6. 随机数法 关键字长度不等时选用

解决冲突方法

  1. 开放定址法

  • 线性探测再散列(每次往右移动)(处理同义词冲突时,添加了非同义词的冲突)(哈希表未满时保证可以找到不发生冲突的地址)
  • 二次探测再散列(+1,-1,+4,-4,+9)
  • 伪随机数再散列

链地址法

再哈希法,计算另一个哈希函数地址(不易产生聚集,但是增加了计算时间)

建立一个公共溢出区,只要发生冲突,就填入溢出表

注意再哈希法和开放定址法的组合考察,即设置两个 mod 函数,第一次冲突时,不进行探测

开放定址法处理冲突时,删除元素只能进行逻辑删除,不能物理删除

查找及其分析

三个因素

  1. 哈希函数
  2. 处理冲突的方法
  3. 哈希表的装填因子

采用开放定址法平均查找长度高于链地址法

负载因子(装填因子)α 定义为表中填入的记录数和哈希表的长度,反应哈希表的装满程度;越小,发生冲突的可能性就越小

哈希链地址法解决冲突的哈希表中,查找的平均查找长度直接与「装填因子」有关,而不直接依赖于记录数或者散列表长度

哈希表的平均查找长度是 α 的函数,而非 n 的函数。不管 n 多大,我们都能选择一个合适的 α 将平均查找长度限定在一个范围里

非链地址处理冲突的哈希表中,删除一个记录需要在该位置填入特殊符号,防止找不到同义词记录

画出哈希表,求等概率查找成功与不成功的平均查找长度

注意选择的处理冲突方式

(06)散列表的长度 m = 13,散列函数为 K mod m,给定关键码序列(19,14,23,01,68,20,84,27,55,11)线性探测再散列

可以在线性探测法解决冲突的同时标记下探测次数,方便计算

0123456789101112
1416827551920842311
1112113431

查找成功 ASL = 1.8

不成功情况就是对哈希函数对应的查找失败情况依次查找(注意并非对于哈希表中所有情况进行查找,可能容量大于哈希函数的取值),「分母是哈希表容量」

查找失败在空位置时为 1,其他位置则需要找到下一个空位置

查找失败 ASL = (1 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 3 + 2 + 1) / 13 = 4

(07)哈希函数 K mod 12,键值序列为(25,37,52,43,84,99,120,15,26,11,70,82),链地址法解决冲突

0970a22297ee7723c04f83b77f653d71.png
哈希表链地址

这里不限制横竖的方向,注意哈希表是连接在一起的,以及表尾的「空指针处理」

链地址解决冲突的话,空位置查找长度为 0,此时不成功平均查找长度的快速计算方法是,使用关键字个数 / 哈希表容量

查找成功 (1 x 8 + 2 x 4) / 12 = 4 / 3

(13)哈希函数 K mod 11,关键字序列(33,52,64,57,41,24,12,78),平方探测再散列解决冲突 (14)哈希函数 K mod 13,关键字序列(12,51,8,22,26,80,11,16,54,41),线性探测解决冲突 (15)哈希函数 K mod 13,关键字序列(12,51,8,22,26,80,11,16,79,55),链地址法解决冲突 (16)0-15 的散列区,对十二个月份关键构造哈希表,哈希函数为 i/2 下取整,i 为关键字中第一个字母在字母表中的序号,线性探测开放定址处理冲突 (17)关键字(9,01,23,14,55,20,84,27)采用哈希函数 k mod 7 表长为 10,用开放定址法的二次探测再散列的方法,Hi = (H(key)+di)mod 10 解决冲突

算法要求

算法名称对于书上位置算法编号真题
「二分查找」(递归)2209.207,16,17
结点在二叉排序树中的层数(227)
判断是否为二叉排序树
建立链式存储结构的二叉排序树
递减打印二叉排序树
「二叉排序树插入」2289.6
「二叉排序树查找」2289.5
「哈希表查找,插入」2599.17 9.1816

二分查找递归形式

int SearchBin(SSTable A, int low, int high, KeyType K) {
    if (low <= high) {
        int mid = (low + high) / 2;
        if (K == A[mid].key) return mid;
        else if (K return SearchBin(A, low, mid - 1, K);
        else return SearchBin(A, mid + 1, high, K);
    } else return -1;
}

哈希表的建立,查找,插入

typedef struct node {
    int key;
    struct node *next;
} CHAINH;

// 尾插法建立哈希表,链地址解决冲突
void Unkown1(CHAINH *HTC[]) {
    CHAINH *p;
    int i, j;
    i = 0;
    scanf("%d", &i);
    while (i != -99) {
        j = i % 7;
        p = (CHAINH *)malloc(sizeof(CHAINH));
        p->next = HTC[j];
        p->key = i;
        HTC[j] = p;
        scanf("%d", &i);
    }
}

// 查找哈希表中是否含有k,存在的话返回1,不存在的话返回0
int Unkown2(CHAINH *HTC[], int k) {
    CHAINH *p;
    int j;
    j = k % 7;
    p = HTC[j];
    if (p != NULL) {
        while ((p->key != k) && (p->next != NULL)) {
            p = p->next;
        }
        if (p->key == k)
            return 1;
        else
            return 0;
    }
    return 0;
}

// 将结点i插入哈希表HTC
void Unkown3(CHAINH *HTC[], int i) {
    CHAINH *p;
    int j;
    j = i % 7;
    p = (CHAINH *)malloc(sizeof(CHAINH));
    p->next = HTC[j];
    p->key = i;
    HTC[j] = p;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值