线性索引查找
索引是为了加快查找速度而设计的一种数据结构。索引就是把一个关键字与它对应的记录相关联的过程。一个索引由若干个索引项构成,每个索引项至少应包含关键字和其对应的记录在存储器中的位置等信息。索引技术是组织大型数据库和磁盘文件的一种总要技术。
索引按照结构分为:线性索引,树形索引和多级索引。
线性索引就是将索引项集合组织为线性结构,也称之为索引表。
稠密索引
稠密索引指在线性索引中,将数据集中的每个记录对应一个索引项。
对于稠密索引的索引表来说,索引项一定是按照关键码有序的排列。
索引项有序意味着,可以查找关键字时,可以用折半,插值,斐波那契等有序算法提升效率。
但是,如果数据集非常大,意味着索引也同样的增长规模,对于内存有限的计算机则需要反复的去访问磁盘,查找速度大大下降。
分块索引
为了减少索引项的个数,我们可以将数据集进行分块,使其分块有序,然后对每一块建立一个索引项,从而减少索引项的个数:
分块有序,是把数据集的记录分成若干块,并且这些块需要满足如下两个条件:
快内无序:即每一块内的记录不要求有序。
块间无序: 块间无序才能在查找时带来效率的提升。
对于分块有序的数据集,将每块对应一个索引项,这种索引方法叫分块索引。
分块索引结构分为三个数据项:
1,最大关键码:他存储了每一块中最大关键字,这样好处是可以在它之后的下一块中的最小关键字也比这块最大关键字大
2,存储了块中的记录个数,便于循环时使用;
3,用于指向块首数据元素的指针,便于开始对这一块中记录进行遍历。
倒排索引
对于这章单词表就是索引表,索引项的通用结构是:
次关键码,上表中“英文单词”
记录号表,上表中“文章编号”
其中记录号表存储具有相同次关键字的所有记录号(可以是指向记录的指针,或者是该记录的关键字),这样的索引算法就是倒排索引。
倒排索引源于实际应用中需要的属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各个记录地址。
二叉排序树
二叉排序树(Binary Sort Tree),又称为二叉查找树。他或者是一棵空树,或者是具有如下性质的二叉树。
- 如它的左子树不为空,则左子树上的所有结点都小于他的根结构的值。
- 如它的右子树不为空,则右子树上的所有结点都大于他的根结构的值。
- 它的左右子树也分别为二叉排序树。
当我们对二叉排序树进行中序遍历的时候,我们就可以得到一个有序序列。
构造二叉排序树的目的,其实不是为了排序,而是为了提高查找和删除关键字的速度。
二叉排序树的查找操作
// 二叉树二叉链表结点的结构定义
typedef struct BiTNode
{
int data;
struct BiTNode *lchild,*rchild;
}BiTnode, *BiTree;
// 递归查找二叉排序树T中是否存在key
// 指针f指向T的双亲,其初始化为NULL
// 若查找成功,则指针p指向该节点,并返回TRUE
// 否则指针p指向查找路路径上访问的最后一个结点并返回FLASE
Status SearchBiTree(BiTree T, int key, BiTree f, BiTree *p)
{
if(!T) //查找不成功
{
*p = f;
return FLASE:
}
else if( key == T->data) //查找成功
{
*p =f;
return TRUE;
}
else if(key < T->data)
return SearchBiTree(T->lchild,key,T,p); //在左子树继续查找
else
reutrn SearchBiTree(T->rchild,key,T,p); //在右子树继续查找
}
二叉排序树的插入操作
有了二叉排序树的查找函数,那么所谓二叉排序的插入,其实也就是将关键字放到树中的合适位置而已
// 当二叉排序树T中不存在关键字等于key的数据元素时
// 插入key并返回TRUE,否则返回FALSE
Status InsertBiTree(BiTree *T,int key)
{
BiTree p,s;
if(!SearchBiTree(*T,key,NULL,&p)) //查找不成功
{
s = (BiTree)malloc(sizeof(BiTNode));
s->data = key;
s->lchild = s->rchild = NULL;
if(!p)
*T = s; //插入s为新的根结点
else if(key < p->data)
p->lchild = s; //插入s为左孩子
else
p->rchild = s; //插入s为右孩子
return TRUE;
}
else
return FALSE;
}
二叉排序树的删除操作
删除结点的三种情况:
- 叶子结点;
- 仅有左或右子树的结点;
- 左右子树都有结点。
// 若二叉排序树T中存在关键字等于key的数据元素时,则删除该元素结点
// 并返回TRUE,否则返回FALSE
Status DeleteBST(BiTree *T, int key)
{
if(!*T) //不存在关键字等于key的数据元素
return FALSE;
else
{
if( key == (*T)->data) // 找到关键字等于key的数据元素
return Delete(T);
else if(key < (*T)->data)
return DeleteBST(&(*T)->lchild,key);
else
return DeleteBST(&(*T)->rchild,key);
}
}
Status Delete(BiTree *p)
{
BiTree q,s; //q存待删结点,s存替换结点
if((*p)->rchild == NULL) //右子树为空,重接左子树
{
q = *p; *p = (*p)->lchild; free(q);
}
else((*p)->lchild == NULL) //左子树为空,重接右子树
{
q = *p; *p = (*p)->rchild; free(q);
}
else
{
q = *p;
s = (*p)->lchild;
while(s->rchild) //转左,然后向右到尽头,找到待删结点前驱
{
q=s;//q删除结点的前驱
s=s->rchild;//删除结点
}
(*p)->data = s->data; //s指向被删除结点的前驱
if(q != *p)
q->rchild = s->lchild; //重接q右子树
else
q->lchild = s->rchild; //重接q左子树
free(s);
}
return TRUE;
}
二叉排序树总结
二叉排序树是以链接方式存储,保持了连接存储结构在执行插入或删除操作时不用移动元素的有点,只要找到合适的插入和删除的位置后,仅仅修改指针即可。插入删除的时间性能比较好。
对于二叉排序树的查找,走的就是从根节点到要查找结点的路径,其比较次数等于给定值的结点在二叉树的层次。