本章问题
1.中序遍历的一般形式是什么?
void InOrder(BiTree T){
if(T){
InOrder(T->lchild);//访问左子树
cout<<T->data<<" ";//输出该节点的数据
InOrder(T->rchild);//访问右子树
}
}
先左儿子底部,然后父节点,然后右儿子的左子树底部,
先序遍历:GDAFEMHZ
中序遍历:ADEFGHMZ
后序遍历:AEFDHZMG
2.二叉搜索树的特点
特点: 任何一棵二叉树是二叉搜索树,当且仅当其中序遍历序列单调非降。
是一棵空树或具有以下几种性质的树:
1.若左子树不空,则左子树上所有结点的值均小于它的根结点的值
2.若右子树不空,则右子树上所有结点的值均大于它的根结点的值
3.左、右子树也分别为二叉排序树
4.没有权值相等的结点。
3.什么是等价二叉搜索树
条件:中序遍历相同
特点:“上下可变,左右不乱”,即等价二叉搜索树中各节点的垂直高度可能不同,但水平次序完全一致;
4.等价二叉搜索树的操作-旋转调整
操作 | 功能 |
---|---|
zig 旋转-顺时针旋转 | 实现等价前提下的局部拓扑调整 |
zag旋转-逆时针旋转 | 实现等价前提下的局部拓扑调整 |
在下列图片之中,圆圈表示的节点,矩形表示的子树
zig旋转 -顺时针
旋转过程描述:将x和v作为c的左子树和右孩子,y和z分别作为v的左右子树
zag旋转-逆时针
旋转过程描述:将v和z作为c的左孩子,右子树,x和y分别为作为v的左,右子树
5.中序遍历的直接前驱和直接后继怎么获得
找后继
1、如有右子女,后继是右子女的最左下节点;
2、若无右子女,且是父母的左子女,则后继就是父母;
3、若无右子女,且是父母的右子女,则一直上溯到第一个“左祖先”(定义如前
面)则后继就是这个祖先。若无这样的祖先,说明已经遍历完毕。
找前驱
1 、如有左子女,前驱是左子女的最右下节点;
2、若无左子女,且是父母的右子女,则前驱就是父母;
3、若无左子女,且是父母的左子女,则一直上溯到第一个“右祖先”(定义如前
面)则前驱就是这个祖先。若无这样的祖先,说明已经遍历完毕。
6.如何插入和删除二叉搜索树节点,才能仍然保持中序遍历单调非降
这里有一个简单的想法,删除节点后,该节点的之后的直接后继依次向前移动
最右下插入节点后,依次与其直接前驱比较,然后排序,但是这样是o(n)的复杂度,这样的复杂度即使是线性结构也可以做到
没有什么体现二叉搜索树的优势
那么有什么更优化的算法么?
是有的,那么具体的方法是什么呢
插入
1.查找插入的位置,并且判断是否唯一
2.在找到的位置插入节点
查找步骤具体的描述
从树根出发,逐步的缩小查找范围,直到发现目标(成功)或缩小至空树(失败)
删除
1.查找节点和后继
2.删除节点,将节点后继连接到被删除节点的父节点
查找步骤具体的描述
来自博客:https://blog.csdn.net/hansionz/article/details/81988752
首先要确定删除节点的种类
二叉搜索树的删除大致分为以下类:
1.左子树为空
2.右子树为空
3.左右子树都为空
4.左右子树都不为空
对于以上的四类要删除的结点,其实我们还可以在具体一些,将一二三类归在一起,第四类是一类。
下面是两类删除结点的方法
7.1.1 二叉搜索树(BST)
特点: 任何一棵二叉树是二叉搜索树,当且仅当其中序遍历序列单调非降。
7.1.1.1 接口列表
操作 | 功能 | 对象 |
---|---|---|
search(const T& e) | 查找指定元素,返回命中节点,并返回其父亲节点 | 二叉搜索树 |
insert(const T& e) | 按照二叉搜索树的结构要求插入指定元素 | 二叉搜索树 |
remove(const T& e) | 按照二叉搜索树的结构要求删除元素 | 二叉搜索树 |
7.1.1.2 二叉搜索树-类模板
#include"binTree.h"
//二叉搜索树模板类
template<typename T> class bst :public binTree<T>
{
public:
binNode<T>* _hot; //所命中的节点的parent
binNode<T>* connect34( //按照3+4结构,联接3个节点及4颗树
binNode<T>*, binNode<T>*, binNode<T>*,
binNode<T>*, binNode<T>*, binNode<T>*, binNode<T>*
);
binNode<T>* rotateAt(binNode<T>* v); //对x及父亲、祖父做统一旋转调整
public:
static binNode<T>* & searchIn(binNode<T>* &v, const T& e, binNode<T>* &hot); //在以v为根的子树中查找关键码e,并将命中节点的parent返回给hot
virtual binNode<T>* & search(const T& e); //查找
virtual binNode<T>* insert(const T& e); //插入
virtual bool remove(const T& e); //删除
static binNode<T>* removeAt(binNode<T>* &x, binNode<T>* &hot); //删除位置x所指的节点(以判断存在),返回值指向实际被删除者的接替者,hot指向被实际删除者的父亲
};
7.1.1.3 searchIn算法和search接口
template<typename T> binNode<T>* & bst<T>::searchIn(binNode<T>* &v, const T& e, binNode<T>* &hot)
{
if (!v || (v->data == e)) //若v本身不存在或则直接命中,则返回v
return v;
hot = v;
return searchIn((e < (v->data)) ? v->lc : v->rc, e, hot);
}
template<typename T> binNode<T>* & bst<T>::search(const T& e)
{
return searchIn(_root, e, _hot = nullptr);
} //返回时,返回值指向命中节点或假想的哨兵节点,hot指向其parent,
7.1.1.4 insert接口
template<typename T> binNode<T>* bst<T>::insert(const T& e)
{
//首先search查询是否存在或待插入的位置
binNode<T>* &x = search(e);
if (x) //若已经存在则返回
return x;
//否则直接插在x上,设置好前后连接关系
x = new binNode<T>(e, _hot);
_size++;
updateHeightAbove(x);
return x;
}
7.1.1.5 remove和removeAt
template<typename T> bool bst<T>::remove(const T& e)
{
binNode<T>* succ=nullptr; //缓存替代者节点
//首先搜索是否存在
binNode<T>* &x = search(e); //缓存将要被删除的节点
binNode<T>* temp = x;
if (!x) //不存在则直接返回
return false;
//case 1 :命中节点至多只有一个孩子,则直接删除,孩子顶上
if (!(x->lc)) //左孩子为空,则右孩子顶上
{
succ = x = x->rc;
}
else if(!(x->rc))
{
succ = x = x->lc;
}
//case 2 :命中节点有两个孩子,则通过succ找直接后继节点
else
{
temp = temp->succ();
swap(x->data, temp->data); //交换数据后temp成为实际要删除的点
binNode<T>* u = temp->parent;
((u == x) ? u->rc : u->lc) = succ = temp->rc; //跨过节点succ(只有一种情况是左孩子)
}
_hot = temp->parent;
if (succ)
succ->parent = _hot;
delete temp;
_size--;
updateHeightAbove(_hot);
return true;
}
template<typename T> binNode<T>* bst<T>::removeAt(binNode<T>* &x, binNode<T>* &hot)
{
binNode<T>* w = x; //实际被摘除的节点
binNode<T>* succ = nullptr; //实际被删除的节点的接替者
if (!(x->lc)) //左孩子为空,则右孩子顶上
{
succ = x = x->rc;
}
else if (!(x->rc))//右孩子为空,则左孩子
{
succ = x = x->lc;
}
//case 2 :命中节点有两个孩子,则通过succ找直接后继节点
else
{
w = w->succ(); //中序遍历的直接后继
swap(x->data, w->data); //交换数据
binNode<T>* u = w->parent;//直接后继的父节点
((u == x) ? u->rc : u->lc) = succ = w->rc; //隔离实际删除点
//若直接后继的父节点为自身,则直接后继父节点的左孩子
}
hot = w->parent;
if (succ) succ->parent = hot;
delete w;
return succ;
}
7.1.1.6 connect34 3+4连接
template<typename T> binNode<T>* bst<T>::connect34( //按照3+4结构,联接3个节点及4颗树
binNode<T>* a, binNode<T>* b, binNode<T>* c,
binNode<T>* T0, binNode<T>* T1, binNode<T>* T2, binNode<T>* T3)
{
a->lc = T0; if (T0) T0->parent = a;
a->rc = T1; if (T1) T1->parent = a;
updateHeight(a); //更新a的高度
c->lc = T2; if (T2) T2->parent = c;
c->rc = T3; if (T3) T3->parent = c;
updateHeight(c);
b->lc = a; a- >parent = b;
b->rc = c; c->parent = b;
updateHeight(b);
return b;
}
7.1.1.7 rotateAt 3+4重平衡
template<typename T> binNode<T>* bst<T>::rotateAt(binNode<T>* v)
{
binNode<T>* p = v->parent; binNode<T>* g = p->parent; //首先根据v找到p和g节点
if (g->lc == p) //失衡是由节点删除导致的(p是g的左孩子)
{
if (p->lc == v) //进一步,v是p的左孩子
{
p->parent = g->parent;
return connect34(v, p, g, v->lc, v->rc, p->rc, g->rc);
}
else
{
v->parent = g->parent;
return connect34(p, v, g, p->lc, v->lc, v->rc, g->rc);
}
}
else //失衡是由节点插入造成的
{
if (p->rc == v)
{
p->parent = g->parent;
return connect34(g, p, v, g->lc, p->lc, v->lc, v->rc);
}
else
{
v->parent = g->parent;
return connect34(g, v, p, g->lc, v->lc, v->rc, p->rc);
}
}
}
7.1.2 BST.h
#pragma once
#include "bintree.h"
#include "release.h"
#include <iostream>
template<typename T> class BST:public BinTree<T>{
protected:
BinNodePosi(T) _hot;//“命中”节点的父亲
BinNodePosi(T) connect34(//3+4调整
BinNodePosi(T),BinNodePosi(T),BinNodePosi(T),
BinNodePosi(T),BinNodePosi(T),BinNodePosi(T),BinNodePosi(T));
BinNodePosi(T) rotateAt(BinNodePosi(T) x);//对x及父亲、祖父做统一的旋转调整
public:
virtual BinNodePosi(T) &search(const T& e);//查找
virtual BinNodePosi(T) insert(const T& e);//插入
virtual bool remove( const T& e);//删除
};
//查找调用的函数
template <typename T>
static BinNodePosi(T) & searchIn( BinNodePosi(T) & v, const T &e, BinNodePosi(T) & hot){
if( !v || (e == v->data)) return v;
hot = v;
return searchIn((( e < v->data ) ? v->lc : v->rc), e , hot );
}
//查找
template <typename T> BinNodePosi(T) & BST<T>::search (const T & e)
{ return searchIn( this->_root, e, _hot = nullptr);}
//插入
template <typename T> BinNodePosi(T) BST<T>::insert (const T & e){
BinNodePosi(T) & x = search( e ); if(x) return x;
x = new BinNode<T> ( e, _hot);
this->_size ++;
this->updateHeightAbove(x);
return x;
}
//删除
template <typename T> bool BST<T>::remove( const T& e){
BinNodePosi(T) & x = search(e); if( !x ) return false;
removeAt( x, _hot ); this->_size --;
this->updateHeightAbove( _hot );
return true;
}
//删除调用的函数
template <typename T>
static BinNodePosi(T) removeAt( BinNodePosi(T)& x , BinNodePosi(T) & hot ){
BinNodePosi(T) w = x;
BinNodePosi(T) succ = nullptr;
if( !HasLChild( *x ))
succ = x = x->rc;
else if ( !HasRChild( *x ))
succ = x = x->lc;
else{
w = w->succ();
T tmp = x->data;
x->data = w->data;
w->data = tmp;
//swap ( x->data, w->data);
BinNodePosi(T) u = w->parent;
((u == x) ? u->rc : u->lc) = succ = w->rc;
}
hot = w->parent;
if( succ ) succ->parent = hot;
dtl::release( w->data ); dtl::release( w ); return succ;
}
//3+4连接
template <typename T> BinNodePosi(T) BST<T> :: connect34(
BinNodePosi(T) a, BinNodePosi(T) b, BinNodePosi(T) c,
BinNodePosi(T) T0, BinNodePosi(T) T1, BinNodePosi(T) T2, BinNodePosi(T) T3
){
a->lc = T0; if( T0 ) T0->parent = a;
a->rc = T1; if( T1 ) T1->parent = a; BinTree<T>::updateHeight(a);
c->lc = T2; if( T2 ) T2->parent = c;
c->rc = T3; if( T3 ) T3->parent = c; BinTree<T>::updateHeight(c);
b->lc = a; a->parent = b;
b->rc = c; c->parent = b; BinTree<T>::updateHeight(b);
return b;
}
//3+4重平衡
template <typename T> BinNodePosi(T) BST<T>::rotateAt( BinNodePosi(T) v){
BinNodePosi(T) p = v->parent; BinNodePosi(T) g = p->parent;
if( p->data < g->data)/*zig*/
if( v->data < p->data){/*zig-zig*/
p->parent = g->parent;
std::cout << v->data << std::endl;
return connect34( v, p, g, v->lc, v->rc, p->rc, g->rc);
}else{/*zig-zag*/
v->parent = g->parent;
return connect34( p, v, g, p->lc, v->lc, v->rc, g->rc);
}
else/*zag*/
if( v->data >= p->data){/*zag-zag*/
p->parent = g->parent;
return connect34(g, p, v, g->lc, p->lc, v->lc, v->rc);
}else{/*zag-zig*/
v->parent = g->parent;
return connect34( g, v, p, g->lc, v->lc, v->rc, p->rc);
}
}
7.1.3 测试程序
#include "BST.h"
#include <iostream>
using namespace std;
template<typename T> void returnValue(T& a)
{
cout << "return_value: " << a << endl;
}
int main(int argc,char* argv[])
{
//构造树
BST<int> bt_test;
bt_test.insert(36);
bt_test.insert(27);
bt_test.insert(58);
bt_test.insert(53);
bt_test.insert(69);
bt_test.insert(50);
bt_test.insert(54);
//测试
cout << bt_test.search(53)->data << endl;//搜索
bt_test.insert(59);//插入
//bt_test.remove(50);//删除
bt_test.insert(51);
void (* visit)(int& ) = &returnValue;//中序遍历
bt_test.traverse(bt_test.root(),visit);
}
/*
53
return_value: 27
return_value: 36
return_value: 50
return_value: 51
return_value: 53
return_value: 54
return_value: 58
return_value: 59
return_value: 69
*/