二叉排序树(BST)的定义为:二叉排序树或者是空树,或者是满足下列性质的二叉树:
(1) :若左子树不为空,则左子树上所有结点的值(关键字)都小于根结点的值;
(2) :若右子树不为空,则右子树上所有结点的值(关键字)都大于根结点的值;
(3) :左、右子树都分别是二叉排序树。
结论:若按中序遍历一棵二叉排序树,所得到的结点序列是一个递增序列。
BST可以用二叉链表来存储:
BST查找思想:
首先将给定的K值与二叉排序树的根结点的关键字进行比较:若相等: 则查找成功;
① 给定的K值小于BST的根结点的关键字:继续在该结点的左子树上进行查找;
② 给定的K值大于BST的根结点的关键字:继续在该结点的右子树上进行查找。
索引技术是组织大型数据库的重要技术,索引结构的基本组成是索引表和数据表两部分:
◆ 数据表:存储实际的数据记录;
◆索引表:存储记录的关键字和记录(存储)地址之间的对照表,每个元素称为一个索引项。
通过索引表可实现对数据表中记录的快速查找。索引表的组织有线性结构和树形结构两种。
顺序索引表是将索引项按顺序结构组织的线性索引表,而表中索引项一般是按关键字排序的,其特点是:
优点:
◆ 可以用折半查找方法快速找到关键字,进而找到数据记录的物理地址,实现数据记录的快速查找;
◆ 提供对变长数据记录的便捷访问;
◆ 插入或删除数据记录时不需要移动记录,但需要对索引表进行维护。
缺点:
◆ 索引表中索引项的数目与数据表中记录数相同,当索引表很大时,检索记录需多次访问外存;
◆ 对索引表的维护代价较高,涉及到大量索引项的移动,不适合于插入和删除操作。
树形索引表:
平衡二叉排序树便于动态查找,因此用平衡二叉排序树来组织索引表是一种可行的选择。 R.Bayer和E.Mc Creight在1972年提出了一种多路平衡查找树,称为B_树(其变形体是B+树) 。
B_树设计时主要用于文件系统中,在B_树中,每个结点的大小为一个磁盘页,结点中所包含的关键字及其孩子的数目取决于页的大小。
在实际的文件系统中,基本上不使用B_树,而是使用B_树的一种变体,称为m阶B+树。 它与B_树的主要不同是叶子结点中存储记录。在B+树中,所有的非叶子结点可以看成是索引,而其中的关键字是作为“分界关键字”,用来界定某一关键字的记录所在的子树。一棵m阶B+树与m阶B_树的主要差异是:
⑴ 若一个结点有n棵子树,则必含有n个关键字;
⑵ 所有叶子结点中包含了全部记录的关键字信息以及这些关键字记录的指针,而且叶子结点按关键字的大小从小到大顺序链接;
⑶ 所有的非叶子结点可以看成是索引的部分,结点中只含有其子树的根结点中的最大(或最小)关键字。
代码:
#include <stdio.h>
#include <stdlib.h>
/*#define EQ(a,b) ((a)==(b)) //对数值型关键字比较
#define LT(a,b) ((a)<(b))
#define LQ(a,b) ((a)>(b))*/
typedef int KeyType;
//块内结构
typedef struct RecType{
KeyType key;
}RecType;
//索引表结构
typedef struct index{
KeyType maxkey; //块中最大的关键字
int startpos; //块的起始位置指针
}Index;
//二叉排序树的结点定义
typedef struct Node{
KeyType key;
struct Node *Lchild, *Rchild;
}BSTNode;
//二叉排序树的递归查找
BSTNode *BST_Search(BSTNode *T, KeyType key){
if(T == NULL){
printf("查找失败");
return NULL;
}
if(T->key == key){
return T;
}
else if(T->key < key)
return (BST_Search(T->Rchild, key));
else
return (BST_Search(T->Lchild, key));
}
//非递归
BSTNode *BST_Search1(BSTNode *T, KeyType key){
// BSTNode *p; p = T;
while(T != NULL && T->key != key){
if(key > T->key)
T= T->Rchild;
else
T = T->Lchild;
}
if(T->key == key)
return T;
else
return NULL;
}
//索引顺序查找(分块查找)
int Block_search(RecType ST[], Index ind[], KeyType key, int n, int b){
//在分块索引表中查找关键字为key的记录
//表长为N, 块数为b
int i = 1, j;
//找块
while((i <= b) && ind[i].maxkey < key){
i++;
}
// printf("\n i = %d ", i);
if(i > b){
printf("没找见1\n");
return 0;
}
//块内找
j = ind[i].startpos;
// printf("\nj = %d", j);
while((j <= n) && ST[j].key < ind[i].maxkey){
if(ST[j].key == key)
break;
j++;
}
if(j > n||ST[j].key != key){
j = 0;
printf("没找见2\n");
}
return j;
}
//建立ercha排序树
BSTNode *Create_BST(){
int ch;
BSTNode *b;
// printf("先序输入二叉排序树:\n");
scanf(" %d", &ch);
if(ch == 0){
b = NULL;
}else{
b = (BSTNode *)malloc(sizeof(BSTNode));
b->key = ch;
b->Lchild = Create_BST();
b->Rchild = Create_BST();
}
return b;
}/*
void PerOrderTraverse(BSTNode *bt)
{
if(bt!=NULL)
{ printf("%d",bt->key);
PerOrderTraverse(bt->Lchild);
PerOrderTraverse(bt->Rchild);
}
}*/
int main()
{
int b, n, i, m, j;
/* printf("-----------索引顺序表查找----------\n");
printf("输入索引表的长度:");
scanf("%d", &b);
printf("输入块的大小:");
scanf("%d", &n);
RecType ST[n*b];
Index ind[b];
printf("建立索引表:\n");
for(i = 1; i <= b; i++){
printf("输入索引表的第%d块的最大值:", i);
scanf("%d", &m);
ind[i].maxkey = m;
}
int a = 1;
printf("建立块:\n");
for(i = 1; i <= b; i++){
ind[i].startpos = a;
for(j = 0; j < n; j++){
printf("输入第%d块的第%d个值:", i, j+1);
scanf("%d", &m);
ST[a].key = m;
a++;
}
}
printf("打印索引表:\n");
for(i = 1; i <= b; i++){
printf("%d ", ind[i].maxkey);
printf("%d \n", ind[i].startpos);
}
printf("打印顺序表\n");
for(i = 1; i <= n*b; i++){
printf("%d ", ST[i].key);
}
printf("\n");
printf("输入要查找的值:\n");
scanf("%d", &m);
printf("地址为:%d", Block_search(ST, ind, m, n*b, b));*/
printf("\n\n---------二叉排序树的查找----------\n");
BSTNode *T;
BSTNode *p;
T = Create_BST();
printf("以%d为根的树创建成功!\n",T->key);
//PerOrderTraverse(T);
printf("输入要查找的值:\n");
scanf("%d", &m);
printf("递归查找:");
p = BST_Search(T, m);
printf("找到了 它的值为%d",p->key);
if(p->Lchild != NULL)
printf("左孩子为%d",p->Lchild->key);
else
printf("左孩子为空");
if(p->Rchild != NULL)
printf("右孩子为%d\n",p->Rchild->key);
else
printf("右孩子为空\n");
// printf("%d \n", p->key);
printf("非递归查找:");
p =BST_Search1(T, m);
printf("找到了 它的值为%d",p->key);
if(p->Lchild != NULL)
printf("左孩子为%d",p->Lchild->key);
else
printf("左孩子为空");
if(p->Rchild != NULL)
printf("右孩子为%d",p->Rchild->key);
else
printf("右孩子为空");
return 0;
}
结果展示: