不积跬步,无以至千里
反思
- 如何处理异常?
- 节点类型要不要继承?
- 做好单个函数功能的测试,越早越好。
- 如何找到边界值和负例?
- 一个函数不要做多余事,办好一件事就够了。
- 具体细节
讨论:二叉搜索树的删除
思路:用当前值的前驱代替自己,之后删除前驱
如果前驱不存在呢?
法一,找后继代替自己,然后删除后继【本文方案】
- 如何删除后继?利用后继没有左孩子的特性,找后继的父亲和右儿子相连
法二,没有前驱,说明没有左孩子,直接删除当前节点,再让父亲左(右需要判断)指针和右孩子连接
- 可以递归么?不断找前驱的前驱,直到没有前驱。但是会移动很多节点。
- 具体代码细节
T getMax(BPtr root, bool del = false, BPtr father = nullptr);//声明默认是不用删除,父指针在删除成立时有效
template
inline int BSTree::remove(const T target)
{
BPtr ptr = nullptr;
BPtr fptr = nullptr;
bool isleft = false;
if (find(this->m_root,target, ptr, fptr) != FAIL) {
isleft = (fptr->rChild->val != target);
if (isLeaf(ptr)) {//叶子直接删除
delete ptr;
if (isleft) {
fptr->lChild = nullptr;
}
else {
fptr->rChild = nullptr;
}
return OK;
}
if (ptr->lChild == nullptr) {
ptr->val = getMin(ptr->rChild, true, ptr);
//以当前节点ptr右孩子的最小值(后继)代替自己,同时删除后继
}
else {
ptr->val = getMax(ptr->lChild, true, ptr);
}
}
return OK;
}
template
inline T BSTree::getMin(BPtr root, bool del,BPtr father)
{
//非法输入
if (!root) return FAIL;
//开始,root是father的右孩子,即在右子树找最小值
bool isRight = true;
BPtr p = root;
while (p->lChild != nullptr) {
father = p;
p = p->lChild;
isRight = false;//现在成了左孩子
}
T ans = p->val;
if (del) {
if (isRight) {
father->rChild = p->rChild;
}
else {
father->lChild = p->rChild;
}
free(p);
p = nullptr;
}
return ans;
}
/* 可不可以把getMin()和delNext()分离出来呢?
* 如getmin()单纯返回now_ptr右子树的最小值next
* 可以用find(next,ptr,fptr)找到next父亲【相当于找了一趟next,但是函数分工明确,getMin不用干多余的活儿】
* 然后,判断isRight【next是他父亲的哪个孩子】
* 最后,连接他父亲和next的右孩子【后继没左孩子,有的话他就不会是左孩子了】
*/
讨论:平衡二叉搜索树的删除
思路:递归
* 如果是叶子直接删除,调整平衡
* 如果只有一个孩子,先连接父亲和孩子,再删除,最后调整平衡
* 如果两个孩子都有,找从左子树找前驱覆盖当前值
* 如果恰好是左孩子,先连接当前值和左孩子的右儿子
然后删除,这时一定平衡想想为什么?
* 否则,从左子树里递归删除前驱
还有更好的结构吗?
讨论:平衡二叉搜索树的调整平衡
- 保存头上部分【当前节点的父亲】,和当前的高度oldH
- 向上找第一个不平衡的结点ptr
- 判断ptr的不平衡类型并旋转
- 连接头部【调整后,下半部分的根结点有改变】,小心父节点是空
- 调整后的树高不变【等于oldH】调整完毕,否则递归调整父亲节点。
代码
- BTree.h
#pragma once
#include
#include
#include
#include
#include
using namespace std;
/*状态码*/
const int FAIL = -1;
const int OK = 0;
const int ERROR = -3;
//定义二叉树节点
template
struct BTNode
{
T val;
BTNode *lChild, *rChild;
BTNode() :val(0), lChild(nullptr), rChild(nullptr) {}
BTNode(T x, BTNode *l = nullptr, BTNode *r = nullptr)
: val(x), lChild(l), rChild(r) {}
};
//定义索引二叉树节点
template
struct indexBTNode
{
//帮助不大不需要继承
int val;
int leftSize;
indexBTNode *lChild, *rChild;
indexBTNode() :val(0), leftSize(0), lChild(nullptr), rChild(nullptr) {}
indexBTNode(T x, indexBTNode *l = nullptr, indexBTNode *r = nullptr)
: val(x),leftSize(0), lChild(l), rChild(r) {}
};
//定义平衡树节点
template
struct AVLNode :BTNode
{
int height;
AVLNode* lChild, *rChild,*fPtr;
AVLNode():height(0),lChild(nullptr), rChild(nullptr), fPtr(nullptr) {
this->val = 0;
}
AVLNode(const T data) :
height(0), lChild(nullptr), rChild(nullptr), fPtr(nullptr) {
this->val = data;
}
};
/*
这里保证继承的类之间都是同一种节点类型
子指针可以转化为父指针
*/
typedef int DATATYPE;
typedef indexBTNode* BPtr;
/*通用的一些函数*/
template
BPtr newNode(const T x) {
return new indexBTNode(x);
}
template
BPtr newNode(BPtr &father, T x) {
BPtr node = new AVLNode(x);
node->fPtr = father;//给父指针赋值
return node;
}
bool isLeaf(BPtr node) {
if (node == nullptr) return false;
return node->lChild == nullptr && node->rChild == nullptr;
}
void error(string str) {
cout <<"errr:" <
class BTree
{
public:
BTree(){
m_root = newNode(-1);
}
~BTree();
int show();
void preVisit(BPtr p);
protected:
//保证继承可以访问到根指针
BPtr m_root;
private:
void destroy(BPtr p);
};
template
inline int BTree::show()
{
if (m_root == nullptr) return FAIL;
cout << "list = [";
preVisit(m_root);
cout << "]" << endl;
return OK;
}
template
inline void BTree::preVisit(BPtr p)
{
if (p == nullptr) return;
cout << " " << p->val;
preVisit(p->lChild);
preVisit(p->rChild);
}
template
inline void BTree::destroy(BPtr p)
{
if (p == nullptr) return;
destroy(p->lChild);
destroy(p->rChild);
delete p;
}
template
inline BTree::~BTree()
{
destroy(m_root);
m_root = nullptr;
}
- BSTree.h
#pragma once
#include"BTree.h"
template
class BSTree : public BTree
{
public:
BSTree() {}
BSTree(const vector& arr);//不含重复元素
//在指定子树上查找
int find(BPtr root, const T target, BPtr &ptr, BPtr &fptr);
//默认在整棵树上找
int find(const T target);
//
T findMax() { return getMax(this->m_root); }
T findMin() { return getMin(this->m_root); }
//insert remove
int remove(const T target);
int insert(const T target);
private:
//找到前驱或后继并删除该节点
int findNextVal(BPtr ptr);
protected:
T getMax(BPtr root, bool del = false, BPtr father = nullptr);
T getMin(BPtr root, bool del = false, BPtr father = nullptr);
};
template
inline BSTree::BSTree(const vector& arr)
{
this->m_root =newNode(arr[0]);
int n = arr.size();
for (int i = 1; i < n; ++i) {
insert(arr[i]);
}
}
template
inline int BSTree::find(BPtr root, const T target, BPtr &ptr, BPtr &fptr)
{
if (root == nullptr) {
ptr = fptr = nullptr;
return FAIL;
}
ptr = fptr= root;
while (ptr != nullptr)
{
T data = ptr->val;
if (data == target) return OK;//细节:如果最后考虑相等会怎样?父指针?
fptr = ptr;
if (data < target) {
ptr = ptr->rChild;
}
else {
ptr = ptr->lChild;
}
}
return FAIL;
}
template
inline int BSTree::find(const T target)
{
if (this->m_root == nullptr) {
return FAIL;
}
BPtr ptr= this->m_root;
while (ptr != nullptr)
{
T data = ptr->val;
if (data == target)
return OK;
if (data < target) {
ptr = ptr->rChild;
}
else {
ptr = ptr->lChild;
}
}
return FAIL;
}
template
inline T BSTree::getMax(BPtr root, bool del,BPtr father)
{
//非法输入
if (!root) return FAIL;
//开始,root是father的左孩子,即在左子树找最大值
bool isLeft = true;
BPtr p = root;
while (p->rChild != nullptr) {
father = p;
p = p->rChild;
isLeft = false;//现在成了右孩子
}
T ans = p->val;
//这里的写法有点省劲,找最大值和删除揉在一起了
//否则需要返回最值(前驱)的父指针
if (del) {
if (isLeft) {
father->lChild = p->lChild;
}
else {
father->rChild = p->lChild;
}
free(p);
p = nullptr;
}
return ans;
}
template
inline T BSTree::getMin(BPtr root, bool del,BPtr father)
{
//非法输入
if (!root) return FAIL;
//开始,root是father的右孩子,即在右子树找最小值
bool isRight = true;
BPtr p = root;
while (p->lChild != nullptr) {
father = p;
p = p->lChild;
isRight = false;//现在成了左孩子
}
T ans = p->val;
if (del) {
if (isRight) {
father->rChild = p->rChild;
}
else {
father->lChild = p->rChild;
}
free(p);
p = nullptr;
}
return ans;
}
template
inline int BSTree::remove(const T target)
{
BPtr ptr = nullptr;
BPtr fptr = nullptr;
bool isleft = false;
if (find(this->m_root,target, ptr, fptr) != FAIL) {
isleft = (fptr->rChild->val != target);
if (isLeaf(ptr)) {
delete ptr;
if (isleft) {
fptr->lChild = nullptr;
}
else {
fptr->rChild = nullptr;
}
return OK;
}
//ptr->val = findNextVal(ptr);
//等价于下面一句,用前驱或后继替代
if (ptr->lChild == nullptr) {
ptr->val = getMin(ptr->rChild, true, ptr);
}
else {
ptr->val = getMax(ptr->lChild, true, ptr);
}
}
return OK;
}
template
inline int BSTree::insert(const T target)
{
BPtr ptr=nullptr;
BPtr fptr=nullptr;
if (find(this->m_root,target, ptr, fptr) == FAIL) {
//新值才插入,不含重复值
BPtr _node = newNode(target);
if (fptr->val > target) {
fptr->lChild = _node;
}
else {
fptr->rChild = _node;
}
}
return 0;
}
template
inline int BSTree::findNextVal(BPtr ptr)
{//返回当前值的前驱或后继,并删除前驱或后继,一个函数干的事太多,调了好久
int ans = 0;
BPtr p = nullptr;
BPtr f = nullptr;//前驱或后继的父亲
if (ptr->lChild == nullptr) {
p = ptr->rChild;
if (p->lChild == nullptr) {
ptr->rChild = p->rChild;
ans = p->val;
free(p);
return ans;
}
while (p->lChild) {
f = p;
p = p->lChild;
}
ans = p->val;
f->lChild = p->rChild;
free(p);
}
else {//这里相当于查找最大值并删除getMax
p = ptr->lChild;
if (p->rChild == nullptr) {
ptr->lChild = p->lChild;
ans = p->val;
free(p);
return ans;
}
while (p->rChild) {
f = p;
p = p->rChild;
}
ans = p->val;
f->rChild = p->lChild;
free(p);
}
return ans;
}
void test_bstree() {
vector a = { 9,5,4,6,15,10,16,14,13 };
BSTree Sbt(a);
Sbt.show();
Sbt.remove(9);
Sbt.show();
Sbt.insert(11);
Sbt.remove(14);
Sbt.show();
Sbt.remove(5);
Sbt.insert(12);
Sbt.show();
Sbt.remove(16);
Sbt.show();
}
- AVL.h
#pragma once
#include"BSTree.h"
template
class AVLTree:public BSTree
{
public:
AVLTree(){
this->m_root = newNode(10);
}
AVLTree(vector& vec);
//插入结点
void insert(BPtr &root, T x, BPtr fptr=nullptr);
//指定子树中删除结点
int remove(BPtr &t, T x);
//默认从整棵树找那个删除
int remove(T x) { return remove(this->m_root, x); }
private:
enum { LL, RR, LR, RL };
//指的是形状而非旋转方向
BPtr LLrotate(BPtr &t);
BPtr RRrotate(BPtr &t);
BPtr LRrotate(BPtr &t);
BPtr RLrotate(BPtr &t);
int getHeight(const BPtr &p);
void updateHeight(const BPtr &p);
void adjustTree(BPtr &p);
bool isBalanceTree(const BPtr &p);
int getBalanceFactor(const BPtr &p);
int get1thUnbalanceFather(BPtr p);
int getRotateType(const BPtr &p);
};
template
int AVLTree::getHeight(const BPtr &root)
{//叶子的高度是零,空指针是-1
if (root == nullptr)
return -1;
else
return root->height;
}
template
inline void AVLTree::updateHeight(const BPtr &p)
{
p->height= max(getHeight(p->lChild), getHeight(p->rChild)) + 1;
}
template
inline void AVLTree::adjustTree(BPtr & father)
{
//this->m_root->fPtr = nullptr;//旋转多次后,确保根的爸爸是空
BPtr up = father->fPtr;//头上的部分,先保存一波
bool isRoot = false;
bool is_r_son;
if (up == nullptr) {
up = this->m_root;
isRoot = true;
}
if (!isRoot) {
is_r_son = father == up->rChild;
}
int oldH = father->height;
if (get1thUnbalanceFather(father) == FAIL) {
return;//不用调整
}
else {
int type = getRotateType(father);
switch (type)
{
case LL:
father = LLrotate(father);
break;
case RR:
father = RRrotate(father);
break;
case LR:
father = LRrotate(father);
break;
case RL:
father = RLrotate(father);
break;
default:
break;
}
}
//收尾工作,把头接上
if (isRoot) {
this->m_root = father;
return;
}
else {
//不是头节点,在中间
if (is_r_son) {
up->rChild = father;
}
else {
up->lChild = father;
}
}
//是否需要继续调整
if (oldH != father->height) adjustTree(father->fPtr);
}
template
inline bool AVLTree::isBalanceTree(const BPtr &p)
{
return abs(getBalanceFactor(p)) <= 1;
}
template
inline int AVLTree::getBalanceFactor(const BPtr & p)
{
if (p == nullptr) {
error("pointer not null, if you want BalanceFactor.");
return ERROR;
}
return getHeight(p->lChild)-getHeight(p->rChild);
}
template
inline int AVLTree::get1thUnbalanceFather(BPtr p)
{//向上查找第一个不平衡的祖先,OK表示存在不平衡
while (p) {
if (!isBalanceTree(p)) break;
p = p->fPtr;
}
if (p == nullptr) return FAIL;
return OK;
}
template
inline int AVLTree::getRotateType(const BPtr & p)
{//调用的前提是p节点不平衡,即平衡因子是2或-2
int rootBF = getBalanceFactor(p);
int rightBF=(p->rChild) ? getBalanceFactor(p->rChild):5;
int leftBF = (p->lChild) ? getBalanceFactor(p->lChild):5;
if (rootBF > 0 && leftBF<2) {//2
if (leftBF >= 0) {//1,0
return LL;
}
else return LR;
}
else {//-2
if (rightBF > 2) return ERROR;
if (rightBF >= 0) {//1,0
return RL;
}
else {
return RR;
}
}
return ERROR;
}
template
inline AVLTree::AVLTree(vector& v)
{
this->m_root = newNode(v[0]);
int n = v.size();
for (int i = 1; i < n; ++i) {
insert(this->m_root,v[i]);
}
}
template
inline void AVLTree::insert(BPtr & root, T x, BPtr fptr)
{
if (root == nullptr) {
root = newNode(fptr,x);
return;
}
if (x < root->val) {
insert(root->lChild, x,root); updateHeight(root);
if (!isBalanceTree(root)) {
if (x < root->lChild->val) {
root = LLrotate(root);
}
else {
root = LRrotate(root);
}
}
}
else if (x > root->val) {
insert(root->rChild, x,root);
updateHeight(root);
if (!isBalanceTree(root)) {
if (x > root->rChild->val) {
root = RRrotate(root);
}else{
root = RLrotate(root);
}
}
}
else {
;//数据重复
}
}
template
inline int AVLTree::remove(BPtr & root, T x)
{
BPtr fptr = nullptr;
BPtr ptr = nullptr;
if (this->find(root,x, ptr, fptr) == FAIL) return OK;
bool is_r_son = fptr->rChild == ptr;
//x is leaf
if (isLeaf(ptr)) {
free(ptr);
ptr = nullptr;
if (is_r_son) {
fptr->rChild = nullptr;
}
else fptr->lChild = nullptr;
adjustTree(fptr);
}
else if (ptr->lChild && ptr->rChild==nullptr) {//只有左孩子
if (is_r_son) {
fptr->rChild = ptr->lChild;
}
else fptr->lChild = ptr->lChild;
free(ptr);
ptr = nullptr;
adjustTree(fptr);
}
else if (ptr->rChild && ptr->lChild == nullptr) {//只有右孩子
if (is_r_son) {
fptr->rChild = ptr->rChild;
}
else fptr->lChild = ptr->rChild;
free(ptr);
ptr = nullptr;
adjustTree(fptr);
}
else{
ptr->val = this->getMax(ptr->lChild);
if (ptr->val == ptr->lChild->val) {//刚好就是左孩子
BPtr t = ptr->lChild;
ptr->lChild = t->lChild;
free(t);
t = nullptr;
//这里一定平衡么?
}else remove(ptr->lChild, ptr->val);
}
return OK;
}
/*单旋转
左左插入导致的不平衡,这里是右旋
top
/
core
/ \
lchild r
*/
template
BPtr AVLTree::LLrotate(BPtr &top)
{
BPtr core = top->lChild;
BPtr temp = core->rChild;
//一旋二挤
core->rChild = top;
//三连
top->lChild = temp;
updateHeight(top);
//调整父指针
core->fPtr = top->fPtr;
top->fPtr = core;
updateHeight(core);
return core;
}
/*单旋转
右右插入导致的不平衡,这里是左旋
top
\
core
/ \
l rchild
*/
template
BPtr AVLTree::RRrotate(BPtr &top)
{
BPtr core = top->rChild;
BPtr temp = core->lChild;
//一旋二挤
core->lChild = top;
//三连
top->rChild = temp;
updateHeight(top);
//调整父指针
core->fPtr = top->fPtr;
top->fPtr = core;
updateHeight(core);
int b=core->height;
int a=core->val;
return core;
}
//插入点位于t的左儿子的右子树
template
BPtr AVLTree::LRrotate(BPtr &top)
{
//旋转后需要接上
top->lChild=RRrotate(top->lChild);
return LLrotate(top);
}
//插入点位于t的右儿子的左子树
template
BPtr AVLTree::RLrotate(BPtr &top)
{
top->rChild=LLrotate(top->rChild);
return RRrotate(top);
}
//6,11,5,12,4,1,14,17,2,3
void test_avltree() {
vector a = { 6,11,5,12,4,1,14,17,2,3 };
AVLTree Sbt(a);
Sbt.show();
Sbt.remove(6);
Sbt.show();
Sbt.remove(11);
Sbt.show();
Sbt.remove(14);
Sbt.show();
}
- 索引二叉搜索树
#pragma once
#include"BSTree.h"
template
class idxBTree:public BSTree
{
public:
idxBTree(){
this->m_root = newNode(-1);
}
idxBTree(const vector &arr);
void insert(const T target);
void erase(const T target);
T getKth(int nth);//升序的第K个,下标为K-1
private:
int TreeSize(BPtr root);
void insert(BPtr& root, const T target);
T getKth(BPtr root, int nth);
void erase(BPtr root,const T target);
};
template
inline idxBTree::idxBTree(const vector &arr)
{
int size = arr.size();
for (int i = 0; i < size; i++)
{
insert(arr[i]);
}
}
template
inline void idxBTree::insert(const T target)
{
if (this->find(target) == FAIL) {
insert(this->m_root, target);
}
}
template
inline void idxBTree::erase(const T target)
{
if (this->find(target) == FAIL) return;
if (isLeaf(this->m_root)) {
freeNode(this->m_root);
return;
}
erase(this->m_root, target);
}
template
inline void idxBTree::erase(BPtr root,const T target)
{//函数外保证一定存在target,且不是叶子节点
if (!root) return;
BPtr ptr = root;
BPtr father = ptr;
//修改root 到 target 之间的leftsize
while (ptr) {
T data = ptr->val;
if (data == target) break;
father = ptr;//注意到此时记录父亲才是有意义的
if (data < target) {
ptr = ptr->rChild;
}
else{
ptr->leftSize--;
ptr = ptr->lChild;
}
}
/*
while (ptr) {
T data = ptr->val;
if (data < target) {
father = ptr;
ptr = ptr->rChild;
}
else if(data>target) {
father = ptr;
ptr->leftSize--;
ptr = ptr->lChild;
}
else {
break;
}
}
*/
if (!ptr) return;
BPtr lson = ptr->lChild;
BPtr rson = ptr->rChild;
if (lson) {//取前一个值替代
ptr->leftSize--;
T pre = this->getMax(lson);
ptr->val = pre;
if (isLeaf(lson)) {
ptr->lChild = nullptr;
freeNode(lson);
}else erase(ptr->lChild, pre);
}
else if(rson) {//取后一个值替代
T next = this->getMin(rson);
ptr->val = next;
if (isLeaf(rson)) {
ptr->rChild = nullptr;
freeNode(rson);
}
else erase(ptr->rChild, next);
}
else {
if (father->lChild == ptr) {
father->lChild = nullptr;
}
else {
father->rChild = nullptr;
}
delete ptr;
ptr = nullptr;
return;
}
}
template
inline T idxBTree::getKth(int nth)
{
//第几个从一开始,序号从零开始
int idx = nth - 1;
if (idx<0 || this->m_root==nullptr || idx > TreeSize(this->m_root) - 1) {
error("tree not null and maxSize > nth > 0.");
return T(-1);
}
return getKth(this->m_root, idx);
}
template
inline int idxBTree::TreeSize(BPtr root)
{
if (root == nullptr) return 0;
return TreeSize(root->rChild) + root->leftSize + 1;
}
template
inline void idxBTree::insert(BPtr& root, const T target)
{//重复在函数外已经检查
if (root == nullptr) {
root = newNode(target);
return;//care
}
if (target < root->val) {//插入左树
root->leftSize++;
insert(root->lChild, target);
}
else {
insert(root->rChild, target);
}
}
template
inline T idxBTree::getKth(BPtr root, int idx)
{//函数外已经检查nth的合法性
int lsize = root->leftSize;
int val = 0;
if (idx == lsize ) return root->val;
if (idx < lsize) {
val=getKth(root->lChild, idx);
}
else {
val=getKth(root->rChild, idx - 1 - lsize);
}
return val;
}
void test_indexTree() {
vector arr = {
//20,15,25,12,18,30,22,19
30,12,50,14,40,60,13,15,35,38,18,16
};
idxBTree it(arr);
it.show();
/*test getKth()*/
//cout << "5th :" << it.getKth(5)<
- main.cpp
#include"idxBSTree.h"
int main() {
//test_avltree();
//test_bstree();
test_indexTree();
system("pause");
return 0;
}