目录
1、静态搜索表
顺序搜索
一般的顺序搜索可见要点总结(2),在此介绍一种使用“监视哨”的顺序搜索方法。
监视哨
设在数据表 dataList 中顺序搜索关键码与 给定值 x 相等的数据元素,要求数据元素在表中从下标 0 开始存放, 下标为 CurrentSize 的元素作为控制搜索过程自动结束的“监视哨”使用。
若搜索成功,则函数返回该元素在表中序号 Location(比下标大 1), 若搜索失败,则函数返回 CurrentSize+1。
template <class E, class K>
int dataList<E, K>::SeqSearch (const K x) const {
Element[CurrentSize].key = x;
int i = 0; //将x设置为监视哨
while (Element[i].key != x) i++; //从前向后顺序搜索
return i+1;
};
const int Size = 10;
main () {
dataList<int> L1 (Size); //定义int型搜索表L1
int Target; int Loc;
cin >> L1; cout << L1; //输入L1
cout << “Search for a integer : ”;
cin >> Target; //输入要搜索的数据
if ( (Loc = L1.Seqsearch(Target)) <=
L1.Length() )
cout << “找到待查元素位置在:” << Loc+1
<< endl; //搜索成功
else cout << “ 没有找到待查元素\n”;
//搜索不成功
};
顺序搜索的平均搜索长度
折半搜索
为了加速搜索,在有序顺序表的情形,可以采用折半搜索,它也称二分搜索,时间代价可减到
折半搜索具体内容可见要点总结(6)中的字典部分
2、二叉搜索树
二叉搜索树的中序遍历
如果对一棵二叉搜索树进行中序遍历,可以按从小到大的顺序,将各结点关键码排列起来,所以也称二叉搜索树为二叉排序树。
二叉搜索树上的搜索
在二叉搜索树上进行搜索,是一个从根结点开始,沿某一个分支逐层向下进行比较判等的过程。它可以是一个递归的过程。
- 假设想要在二叉搜索树中搜索关键码为 x 的元素,搜索过程从根结点开始。
- 如果根指针为NULL,则搜索不成功;否则用给定值 x 与根结点的关键码进行比较:
- 若给定值等于根结点关键码,则搜索成功,返回搜索成功信息并报告搜索到结点地址。
- 若给定值小于根结点的关键码,则继续递归搜索根结点的左子树;
- 否则。递归搜索根结点的右子树。
非递归的写法也比较容易:
template<class E, class K>
BSTNode<E, K>* BST<E, K>::
Search (const K x, BSTNode<E, K> *ptr) {
//非递归函数:作为对比,在当前以ptr为根的二
//叉搜索树中搜索含x的结点。若找到,则函数返
//回该结点的地址,否则函数返回NULL值。
if (ptr == NULL) return NULL;
BSTNode<E, K>* temp = ptr;
while (temp != NULL) {
if (x == temp->data.key) return temp;
if (x < temp->data.key) temp = temp->left;
else temp = temp->right;
}
return NULL;
};
设树的高度为h,最多比较次数不超过h。
二叉搜索树的插入算法
要注意如果待插入的值已经在树中,则插入失败。
template <class E, class K>
bool BST<E, K>::Insert (const E& e1,
BSTNode<E, K> *& ptr) {
//私有函数:在以ptr为根的二叉搜索树中插入值为
//e1的结点。若在树中已有含e1的结点则不插入
if (ptr == NULL) { //新结点作为叶结点插入
ptr = new BstNode<E, K>(e1); //创建新结点
if (ptr == NULL)
{ cerr << "Out of space" << endl; exit(1); }
return true;
}
else if (e1 < ptr->data.key) Insert (e1, ptr->left); //左子树插入
else if (e1 > ptr->data.key) Insert (e1, ptr->right); //右子树插入
else return false; //x已在树中,不再插入
};
笔试模拟建树过程:
二叉搜索树的删除
最复杂的是左右子树都不为空的情况,需要找在中序下的前驱或后继进行填补,然后转换为删除前驱或后继的那个节点。(所找的前驱或后继至多只有一个子女,情况简单)
中序下某节点前驱的找法:该节点的左子树的最右边的节点
中序下某节点后继的找法:该节点的右子树的最左边的节点
具体分三种情况,见图片
3、AVL树
即高度平衡的二叉搜索树
定义:
一棵 AVL 树或者是空树,或者是具有下列性质的二叉搜索树:它的左子树和右子树都是 AVL 树,且左子树和右子树的高度之差的绝对值不超过1。
平衡因子:
注意:不同教材的平衡因子定义不同,在此:平衡因子定义为右子树高度减左子树高度。
平衡化旋转
如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
平衡化旋转有两类:
- 单旋转 (左旋和右旋)
- 双旋转 (左平衡和右平衡)
平衡化旋转的具体内容较为复杂,建议自行阅读相关资料进行理解,配合如下图片可以辅助记忆。
同时,这篇文章是为了笔试做准备,前置知识的介绍较少,待后续有空再进行补充。因此,将更多地着眼于用笔来“模拟”的过程。
AVL树的删除和插入操作都可以看成两个部分:先插入or先删除,再调整。
AVL树的插入
推荐这个动画视频,很清晰,但是注意视频中的平衡因子的定义与上下文不同。
模拟建树过程:
如果正在期末冲刺,这个视频可能能帮到你!
关键在于回溯,以及遇到不平衡时的平衡化操作选择。
AVL树的删除
同二叉搜索树一样,仍然是分情况:
调整过程较为复杂,给出例题辅助理解:
可以看看这个视频:AVL树的删除