基本概念
关键字:数据元素中唯一标识该元素的某个数据项的值,使用基于关键字的查找,查找结果应该是唯一的。例如,在由一个学生元素构成的数据集合中,学生元素中“学号”这一数据项的值唯一地标识一名学生。
查找表:同一类型的数据元素
平均查找长度:在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度,则是所有查找过程中进行关键字的比较次数的平均值,其数学定义为
顺序表查找
一、定义
顺序查找(Sequential Search) 又叫线性查找,若查找到某个元素的关键字满足给定条件,则查找成功,返回该元素在线性表中的位置;若已经查找到表的另一端,但还没有查找到符合给定条件的元素,则返回查找失败的信息。
二、算法
/*有哨兵顺序查找*/
int Sequential_Search(int *a, int n, int key){
int i;
a[0] = key; //设置a[0]为关键字,称之为“哨兵”
i = n; //循环从数组尾部开始
while(a[i] != key){
i--;
}
return i; //返回0则说明查找失败
}
有序表查找
一、折半查找
先决条件:表中结点按关键字有序,且顺序(一维数组)存储
二分法思想:
(1)求有序表的中间位置mid
(2) 若r[mid].key==k 查找成功(k是要找的元素)
r[mid].key>k 在左子表继续
r[mid].key<k 在右子表继续
算法:
int Binary_Search(SeqList L, ElemType key){
int low = 0, high = L.length - 1, mid;
while(low <= high){
mid = (low + hight)/2; //取中间位置
if(L.elem[mid] == key){
return mid; //查找成功返回所在位置
}else if(L.elem[mid] > key){
high = mid - 1; //从前半部分继续查找
}else{
low = mid + 1; //从后半部分继续查找
}
}
return -1; //查找失败,返回-1
}
二叉排序树与平衡二叉树
一、二叉排序树(Binary Sort Tree)
1、定义
二叉排序树(也称二叉查找树)或者是一棵空树,或者是具有下列特性的二叉树:
- 若左子树非空,则左子树上所有结点的值均小于根结点的值。
- 若右子树非空,则右子树上所有结点的值均大于根结点的值。
- 左、右子树也分别是一棵二叉排序树。
2、二叉排序树的常见操作
构造一个二叉树的结构:
/*二叉树的二叉链表结点结构定义*/
typedef struct BiTNode
{
int data; //结点数据
struct BiTNode *lchild, *rchild; //左右孩子指针
} BiTNode, *Bitree;
(1)查找操作
/*
递归查找二叉排序树T中是否存在key
指针f指向T的双亲,其初始调用值为NULL
若查找成功,则指针p指向该数据元素结点,并返回TRUE
否则指针p指向查找路径上访问的最后一个结点并返回FALSE
*/
bool SearchBST(BiTree T, int key, BiTree f, BiTree *p){
if(!T){
*p = f;
return FALSE;
}else if(key == T->data){
//查找成功
*p = T;
return TRUE;
}else if(key < T->data){
return SearchBST(T->lchild, key, T, p); //在左子树继续查找
}else{
return SearchBST(T->rchild, key, T, p); //在右子树继续查找
}
}
(2)插入操作
有了二叉排序树的查找函数,那么所谓的二叉排序树的插入,其实也就是将关键字放到树中的合适位置而已。
/*
当二叉排序树T中不存在关键字等于key的数据元素时
插入key并返回TRUE,否则返回FALSE
*/
bool InsertBST(BiTree *T, int key){
BiTree p, s;
if(!SearchBST(*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; //树种已有关键字相同的结点,不再插入
}
}
有了二叉排序树的插入代码,我们要实现二叉排序树的构建就非常容易了,几个例子:
int i;
int a[10] = {62, 88, 58, 47, 35, 73, 51, 99, 37, 93};
BiTree T = NULL;
for(i = 0; i<10; i++){
InsertBST(&T, a[i]);
}
(3)删除操作
二叉排序树的查找和插入都很简单,但是删除操作就要复杂一些,此时要删除的结点有三种情况:
- 叶子结点;
- 仅有左或右子树的结点;
- 左右子树都有的结点;
前两种情况都很简单,第一种只需删除该结点不需要做其他操作;第二种删除后需让被删除结点的直接后继接替它的位置;复杂就复杂在第三种,此时我们需要遍历得到被删除结点的直接前驱或者直接后继来接替它的位置,然后再删除。