-
查找基本概念
- 静态查找表:仅作查询检索的操作
- 动态查找表:在查找过程中对表进行动态修改
- 查找算法评价指标: 关键字的平均比较次数(平均查找长度),ASL
-
线性表的查找
-
顺序查找(线性查找)
-
应用:顺序表或线性链表
-
数据元素类型定义:
typedef struct { KeyType key;//关键字域 InfoType otherinfo;//其他域 } NodeType; typedef struct { NodeType *R; int length; } SSTable;
-
算法描述:
int Search_Seq(SSTable ST, KeyType key) { for (int i = ST.length; i >0; --i) {//0号位置不存储东西 if (ST.R[i].key == key) { return i; } } return 0; }
其他形式:
int Search_Seq(SSTable ST, KeyType key) { for(i=S.length; i>0 && ST.R[i].key != key; --i) { return i; } return 0; }
以上算法每一次循环都要进行两次比较,比较值是否相等且是否越界
改进算法:把待查关键字存入表头
int Search_Seq(SSTable ST, KeyType key) { ST.R[0].key = key; for (int i = ST.length; ST.R[i].key != key; --i) { return i; } }
性能分析:
- 时间复杂度:O(n)
- 空间复杂度:O(1)
- ASL=(1+n)/2
-
-
折半查找(二分或对分查找)
算法描述:int Search_Bin(SSTable ST, KeyType key) { int low = 1, high = ST.length; while (low <= high) { int mid = (low + high) / 2; if (ST.R[mid].key == key) { return mid; } else if (ST.R[mid].key > key) { high = mid - 1; } else { low = mid + 1; } } return 0; }
递归方法:
int Search_Bin(SSTable ST, KeyType key, int low, int high) { if (low > high) { return 0; } int mid = (low + high) / 2; if (ST.R[mid].key == key) { return mid; } else if (ST.R[mid].key > key) { return Search_Bin(ST, key, low, mid - 1); } else { return Search_Bin(ST, key, mid + 1, high); } }
性能分析:
- 时间复杂度:O(log2n)
- 空间复杂度:O(1)
- ASL=log2(n+1)-1
- 适用条件:顺序存储,有序表
-
分块查找
三种方法比较:
-
-
树表的查找
-
二叉排序树
- 定义:左子树结点值<根结点值<右子树结点值,进过中序遍历后为从小到大排序
- 二叉排序树的存储结构
typedef struct{ KeyType key; infoType otherinfo; }ElemType; typedef struct BSTNode{ ElemType data; struct BSTNode *lchild, *rchild; }BSTNode, *BSTree;
-
二叉排序树的查找
递归查找:BSTNode *SearchBST(BSTree T, KeyType key) { if (!T || T->data.key == key) { return T; } if (key < T->data.key) { return SearchBST(T->lchild, key); } else { return SearchBST(T->rchild, key); } }
-
二叉排序树的操作
-
插入
void InsertBST(BSTree &T, ElemType e) { if (!T) { T = (BSTree)malloc(sizeof(BSTNode)); T->data = e; T->lchild = T->rchild = NULL; } else if (e.key < T->data.key) { InsertBST(T->lchild, e); } else if (e.key > T->data.key) { InsertBST(T->rchild, e); } }
-
删除
- 被删除的是叶子结点则直接删除
- 被删除的结点只有左子树或者右子树,直接替换
- 被删除的结点既有左子树也有右子树,则在左子树中找到最大值替换,也可以是右子树最小的结点替换
void DeleteBST(BSTree &T, KeyType key) { if (!T) { return; } else if (key < T->data.key) { DeleteBST(T->lchild, key); } else if (key > T->data.key) { DeleteBST(T->rchild, key); } else { if (T->lchild && T->rchild) { BSTree q = T; BSTree s = T->rchild; while (s->lchild) { q = s; s = s->lchild; } T->data = s->data; if (q != T) { q->lchild = s->rchild; } else { q->rchild = s->rchild; } free(s); } else { BSTree q = T; if (!T->lchild) { T = T->rchild; } else { T = T->lchild; } free(q); } } }
性能分析:
-
-
-
平衡二叉树(AVL树)
-
平衡二叉树的定义
- 左子树和右子树的高度差小于等于1
- 左右子树都是平衡二叉树
-
平衡二叉树的调整
-
LL型
-
-
-
+ RR型
+ LR型
+ RL型
- 哈希表(散列表)的查找
- 构造散列函数考虑的因素:
- 执行速度
- 关键字长度
- 散列表大小
- 关键字分布情况
- 查找频率
- 哈希函数的构造方法
- 直接定址法:H(key)=a*key+b
- 除留余数法:H(key)=key mod p,设表长为m,取p<=m且为质数
- 数字分析法:取关键字的若干位作为散列地址
- 平方取中法:取关键字的平方的中间几位作为散列地址
- 折叠法:将关键字分割成位数相同的几部分,然后取这几部分的叠加和(舍去进位)作为散列地址
- 处理冲突的方法
- 开放定址法
- 线性探测法:H(key)=(H(key)+d) mod m,d=1,2,3,…
- 二次探测法:H(key)=(H(key)+d^2) mod m,d=1,2,3,…
- 随机探测法:H(key)=(H(key)+d) mod m,d为随机数
- 链地址法(拉链法)
基本思想:将所有散列地址相同的记录存储在一个线性链表中
- 构造散列函数考虑的因素: