目录
文件概述
基本概念
文件的存储介质
文件的基本操作
顺序查找
代码实现
折半查找
判定树的构造
代码实现
散列文件
散列表的构造
散列函数的构造
散列冲突
散列表的查找
平均查找长度的运算
文件概述
基本概念
物理记录
属性
逻辑记录
文件
关键字
-
文件的属性或属性组; -
用以标识(区分)文件的不同记录;
-
可唯一标识 —— 主关键字 -
标识若干记录 —— 次关键字
-
当记录中只有一个属性时,其关键字即为该记录的值;
文件的逻辑结构
文件的物理(存储)结构
-
文件的逻辑记录在存储介质上的组织方式; -
基本的组织方式:
-
一个线性逻辑结构在存储介质中可以有多种物理结构;
文件的存储介质
文件的基本操作
文件的查找
-
根据用户需求在文件中确定相应记录的操作过程 -
3种方式
-
查找下一个记录 -
查找第i 个记录 -
按关键字值查找
-
简单条件匹配 —— 查找关键字值等于给定值的记录 -
区域匹配 —— 查找某关键字值属于某个范围内的记录 -
函数匹配 —— 给定关键字的某个函数,查找符合条件的记录 -
组合条件匹配 —— 给出多个条件,用布尔运算组合起来进行查找
-
查找结果
-
查找操作不会改变文件
记录的插入
记录的删除
-
删除文件中指定的记录或者满足条件的记录; -
通常有以下两种情况:
记录的修改
文件的排序
顺序查找
代码实现
// 顺序查找
int sequenceSearch(int a[], int value, int n) {
? ?int i;
? ?for(i = 0; i < n; i++)
? ? ? ?if(a[i] == value)
? ? ? ? ? ?return i;
? ?return -1;
}
折半查找
-
元素必须是有序的,如果是无序的则要先进行排序操作。 -
仅适用于排序连续文件 -
基本思想:属于有序查找算法。将给定值k 先与中间结点的关键字值比较,中间结点把线形表分成两个子表,若相等则查找成功;若不相等,再根据k 与该中间结点关键字的比较结果确定下一步查找哪个子表,这样递归进行,直到查找到或查找结束发现表中没有这样的结点。 -
复杂度分析:最坏情况下,关键词比较次数为log_2 (n+1),且平均时间复杂度为 O(log_2 n);
判定树的构造
-
折半查找过程可以借助于一颗二叉树来描述; -
判定树不一定为二叉树,而折半查找中的判定树必为二叉树; -
查找任意一个记录的过程 —— 经过一条从根结点到与该记录对应结点的路径; -
与关键字的比较次数 —— 该节点在判定树中所在的层次数(深度); -
因此,查找成功所进行的比较次数一定不超过判定树的深度;深度即为最大查找次数;
?
代码实现
// 折半查找
// 1. 非递归
int binSearch(int a[], int value, int n) {
? ?int low, high, mid;
? ?low = 0;
? ?high = n - 1;
? ?while(low <= high) {
? ? ? ?mid = (low + high) / 2;
? ? ? ?if(a[mid] == value)
? ? ? ? ? ?return mid;
? ? ? ?else if(a[mid] > value)
? ? ? ? ? ?high = mid - 1;
? ? ? ?if(a[mid] < value)
? ? ? ? ? ?low = mid + 1;
? }
? ?return -1;
}
?
// 2. 递归
int binSearch_rec(int a[], int low, int high, int value) {
? ?int mid;
? ?if(low <= high)
? ? ? ?return -1;
? ?else {
? ? ? ?mid = (low + high) / 2;
? ? ? ?if(a[mid] == value)
? ? ? ? ? ?return mid;
? ? ? ?else if(a[mid] > value)
? ? ? ? ? ?return binSearch_rec(a, low, high - 1, value);
? ? ? ?else
? ? ? ? ? ?return binSearch_rec(a, low + 1, high, value);
? }
}
散列文件
散列表的构造
-
散列表
-
设计的3 个内容
-
确定散列表的地址空间范围,即确定散列函数值域; -
构造合适的散列函数,该散列函数要保证所有可能元素的散列函数值均在指定的值域内,并且使得冲突发生的可能性尽可能小; -
选择处理冲突的有效方法;
散列函数的构造
-
直接定址法
-
数字分析法
-
平方取中法
-
叠加法
-
基数转换法
-
除留余数法
-
随机数法
-
散列函数构造的原则
-
计算散列函数所需时间; -
关键字的长度; -
散列表的大小; -
关键字的分布情况; -
记录的查找概率;
散列冲突
基本概念
处理冲突的方法
-
开放定址法
-
线性探测再散列
-
容易造成元素的“聚集”(clustering); -
只能对散列表进行逻辑删除;
?
-
再散列法
-
链地址法(按桶散列方法)
-
建立一个公共溢出区
散列表的查找
平均查找长度的运算
例一
现有长度为11 且初始为空的散列表 HT ,散列函数H(key) = key % 7 ,采用线性探查法解决冲突。将关键字序列87,40,30,6,11,22,98,20 依次插入HT后,HT的查找失败的平均长度是多少呢? 查找成功的平均查找长度又是多少呢? ① 首先,通过散列函数并且利用线性探测法给他们每个字划分好自己的位置; ② 记录每个字冲突的次数,后面在计算查找成功的平均长度会用到; ③ 查找失败计算每个查找失败对应地址的查找次数,即从所查位置开始往后查直至查到空位置位置; ④ 其实,后面熟悉过程之后,在列出下面的每个关键字对应地址的表格之后就可以得到结果;
查找失败时对应的地址在这个题目,只能是 7 即 0 ~ 6 ;
ASL 查找失败 = (9 + 8 + 7 + 6 + 5 + 4 + 3 ) / 7 = 6
ASL 查找成功 = (1 + 1 + 1 + 1 + 1 + 1 + 1 + 2) / 8 = 9 / 8
散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|
关键字 | 98 | 22 | 30 | 87 | 11 | 40 | 6 | 20 | | | | 冲突次数 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | | | |
例二
将关键字序列(7,8,30,11,18,9,14) 散列存储到散列表中。散列表的存储空间是从0开始的一维数组,散列函数为H(key) =(3 * key)mod 7 ,处理冲突采用线性探测法,要求装填因子为0.7 。 (1)画出所构造的散列表。 (2)分别计算等概率情况下的查找成功和不成功的平均查找长度。
(1)数组大小 = 7 / 0.7 = 10
散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
关键字 | 7 | 14 | | 8 | | 11 | 30 | 18 | 9 | |
(2) ①查找成功时
散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
关键字 | 7 | 14 | | 8 | | 11 | 30 | 18 | 9 | | 冲突次数 | 0 | 1 | | 0 | | 0 | 0 | 2 | 2 | | 比较次数 | 1 | 2 | | 1 | | 1 | 1 | 3 | 3 | |
ASL 查找成功= (1 + 2 + 1 + 1 + 1 + 3 + 3 )/ 7 = 12 / 7
②查找失败时
散列地址 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|
关键字 | 7 | 14 | | 8 | | 11 | 30 | 18 | 9 | | 比较次数 | 3 | 2 | 1 | 2 | 1 | 5 | 4 | | | |
ASL 查找失败= (3 + 2 + 1 + 2 + 5 + 4)/ 7 = 18 / 7
例题借自 此处
|