1. 查找分类
1.1 比较式查找法
1.1.1 线性表查找法
1.1.1.1 顺序查找法
1.1.1.2 折半查找法
1.1.1.3 分块查找法
1.1.2 基于树的查找法
1.1.2.1 二叉排序树
1.1.2.2 平衡二叉树
1.2 计算式查找法
1.2.1 哈希查找法
2. 算法实例
2.1 顺序查找法
思想:在表的一端设置监视哨(存放要查找的关键字),在表的另一段开始查找
代码实现 sequence.c(完整代码)
/* 查找 key 键 */
int seq_search (RecordList l, int key)
{
/* 将键值设置在链的末端 */
l.r[l.length].key = key;
int i;
/* 顺序查找 */
for (i = 0; l.r[i].key != key; i++) ;
return i;
}
平均查找长度:ASL = (n+1)/2
2.2 折半查找法(序列必须排序)
思想:比较中间键值,如果小于则把左边当作新序列比较中间键值,如果大于则把右边当作新序列比较中间键值。
代码实现 binary.c(完整代码)
/* 查找 key 键, l 中的 r 数组必须按照key值的字典顺序排序 */
int binary_search (RecordList l, int key)
{
int low = 0;
int high = l.length-1;
while (low < high) {
int mid = (low + high)/2;
if (key == l.r[mid].key)
return mid;
else if (key < l.r[mid].key)
high = mid - 1;
else
low = mid + 1;
}
return l.length;
}
平均查找长度:ASL = log 2 (n+1) - 1
2.3 分块查找法
思想:首先将列表分成若干个块(子列表,块间有序,快内无序),构造一个索引表,索引表按键值有序排列
代码实现 block.c(完整代码)
int block_search (RecordList l, int key)
{
BlockList (BLOCK_SIZE, l.length, 1);
int i;
for (i = 0; i < block_list1.length; i++) {
block_list1.r[i].addr = i * block_list1.block_length;
block_list1.r[i].max_key = l.r[i*5].key;
}
for (i = 0; i < l.length; i++)
if (block_list1.r[i/5].max_key < l.r[i].key)
block_list1.r[i/5].max_key = l.r[i].key;
for (i = 0; i < block_list1.length; i++) {
if (key < block_list1.r[i].max_key) {
l.list_s = block_list1.r[i].addr;
l.list_e = (i == block_list1.length-1 ?
l.length : block_list1.r[i+1].addr-1);
return seq_search (l, key);
}
}
return l.length;
}
平均查找长度:ASL =
log 2 (n/s+1) + s/2 n 表示表的长度,s表示每块中的
2.4 二叉排序树的查找法
思想:key 和跟结点 t.key 比较 ,如果相等则返回根,小于进一步查左子树,大于进一步查右子树
代码实现 binary_tree.c(完整代码)
/* 二叉排序树的查找 */
BSTree BST_search (const BSTree root, int key)
{
if (!root) return NULL;
else if (root->data.key == key)
return root;
else if (key < root->data.key)
return BST_search (root->LChild, key);
else
return BST_search (root->RChild, key);
}
2.5 平衡二叉树(AVL树)
思想:对失衡节点进行顺时针或逆时针旋转
有四种形式:LL、LR、RR、RL
假设失衡节点为 A、它的孩子节点中的某个为B 、他的孩子的孩子节点中的某个节点为C,
则:LL:(B为A的左孩子)对A做一次顺时针旋转
RR:(B为A的右孩子)对A做一次顺时针旋转
LR:(B为A的左孩子,C为B的右孩子)对B做一次逆时针旋转,对A做一次顺时针旋转
RL:(B为A的右孩子,C为B的左孩子)对B做一次顺时针旋转,对A做一次、逆时针旋转
代码实现 AVLTree.c(完整代码)
/* 平衡二叉树插入节点 */
void ins_AVLTree (AVLTree *avlt, int key)
{
/* 初始化一个新节点 */
AVLTNode *S = (AVLTree)malloc (sizeof (AVLTNode));
S->data.key = key;
S->LChild = S->RChild = NULL;
S->bf = 0;
/* 插入 */
if (!*avlt)
*avlt = S;
else {
/* 首先查找S的插入位置fp,同时记录距S的插入位置最近且
* 平衡因子不等于0(等于-1或1)的节点A, A可能为失衡节点 */
AVLTNode *A = *avlt, *FA = NULL;
AVLTNode *p = *avlt, *fp = NULL;
while (p) {
if (p->bf) {
A = p;
FA = fp;
}
fp = p;
if (key < p->data.key)
p = p->LChild;
else
p = p->RChild;
}
/* 插入S */
if (key < fp->data.key)
fp->LChild = S;
else if (key > fp->data.key)
fp->RChild = S;
else {
free (S);
return;
}
/* 确定节点B,并修改A的平衡因子 */
AVLTNode *B;
if (key < A->data.key) {
B = A->LChild;
A->bf += 1;
}else {
B = A->RChild;
A->bf -= 1;
}
/* 修改B到S路径上各节点的平衡因子 */
p = B;
while (p != S) {
if (key < p->data.key) {
p->bf = 1;
p = p->LChild;
}else {
p->bf = -1;
p = p->RChild;
}
}
/* 判断失衡类型并做相应处理 */
/* LL型 */
if (2 == A->bf && 1 == B->bf) {
/* A做一次顺时针旋转 */
B = A->LChild;
A->LChild = B->RChild;
B->RChild = A;
A->bf = B->bf = 0;
if (!FA)
*avlt = B;
else if (A == FA->LChild)
FA->LChild = B;
else
FA->RChild = B;
} /* LR型 */
else if (2 == A->bf && -1 == B->bf) {
AVLTNode *C;
/* 先对B做一次逆时针旋转,再对A做一次顺时针旋转 */
B = A->LChild;
C = B->RChild;
B->RChild = C->LChild;
A->LChild = C->RChild;
C->LChild = B;
C->RChild = A;
if (S->data.key < C->data.key) {
A->bf = -1; B->bf = C->bf = 0;
}else if (S->data.key > C->data.key) {
B->bf = 1; A->bf = C->bf = 0;
}else
A->bf = B->bf = 0;
if (!FA)
*avlt = S;
else if (A == FA->LChild)
FA->LChild = C;
else
FA->RChild = C;
} /* RL型 */
else if (-2 == A->bf && 1 == B->bf) {
AVLTNode *C;
/* 先对B做一次顺时针旋转,再对A做一次逆时针旋转 */
B = A->RChild;
C = B->LChild;
B->LChild = C->RChild;
A->RChild = C->LChild;
C->LChild = A;
C->RChild = B;
if (S->data.key < C->data.key) {
B->bf = -1; A->bf = C->bf = 0;
}else if (S->data.key > C->data.key) {
A->bf = 1; B->bf = C->bf = 0;
}else
A->bf = B->bf = 0;
if (!FA)
*avlt = S;
else if (A == FA->LChild)
FA->LChild = C;
else
FA->RChild = C;
} /* RR 型 */
else if (-2 == A->bf && -1 == B->bf) {
/* 对A做一次逆时针旋转 */
B = A->RChild;
A->RChild = B->LChild;
B->LChild = A;
A->bf = B->bf = 0;
if (!FA)
*avlt = B;
else if (A == FA->LChild)
FA->LChild = B;
else
FA->RChild = B;
}
}
}
时间复杂度:O(log
2 n)