自学内容网 自学内容网

【c++】二叉搜索树

1. 二叉搜索树概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
它的左右子树也分别为二叉搜索树
二叉树的中序遍历就相当于从小往大排序
在这里插入图片描述

2.二叉搜索树的基本操作

结构体的构建

template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{
}


};

使用初始化列表初始化变量

类封装搜索二叉树

template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:



private:
Node* _root = nullptr;

};

为了方便使用结构体,我们将搜索二叉树的结构体重定义为Node,对于一个搜索二叉树,我们需要定义一个变量存放二叉树根节点的地址,我们在这里相当于给初始化列表给缺省值了

二叉搜索树的插入

由于二叉搜索树是不能出现重复的,我们在遍历查找的时候,如果是第一个插入的话就申请节点,插入函数返回值表示该值是否能插入,如果是第一个节点,就能插入,return true;定义一个遍历指针,刚开始让这个指针指向头结点,然后如果指针指向的结点的值小于要插入的值,则让该指针去右子树寻找,因为右子树是比该节点的值大的。如果指针指向的结点的值大于要插入的值,则让该指针去右子树寻找.如果该指针指向的结点的值等于要插入的·值,直接返回fasle;因为二叉树不能出现重复的数,等到找到要插入值的位置,让他的父节点指向他,但是按照上述的做法,他的父节点根本没有记录到,所以我们在循环里面遍历指针在去下一个位置的时候,需要将当前位置保存在父节点里面。除此之外,需要考虑要插入的结点应该链接到父节点的左边,还是右边,我们必须判断如果要插入的结点值比父节点的值大,就链接到父节点的右边,如果比父节点小的话就链接到父亲节点的左边,然后返回true,表示可以插入

bool insert(const K& key)
    {
if (_root == nullptr)
{
_root = new Node(key);
return _root;
}
Node* parent = nullptr;
Node* cur =_root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;

}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;

}
else
{

return false;

}
}
cur = new Node(key);
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}

中序遍历

搜索二叉树的中序遍历就相当于从小到大排序,我们使用中序遍历来验证我们的插入.
因为我们的root是私有成员变量
在这里插入图片描述

所以我们采用一个共有的函数来调用私有的函数,这个私有的函数用来中序遍历
在这里插入图片描述

void _inorder()
{
return inorder(_root);


}
void inorder(Node* root)
{
if (root == nullptr)
return;
inorder(root->_left);
cout <<root->_key << " ";
inorder(root->_right);
}

二叉搜索树的查找

二叉树的查找和插入基本思路差不多,如果找到值一样的返回true;当遍历完没有一样的,就返回false;如果根节点是空的话就肯定没有要找的值返回false;

bool find(const K& key)
{
if (_root == nullptr)
{
return false;

}
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;

}
else if (cur->_key > key)
{
cur = cur->_left;
 
}
else
{

return true;
}



}
return false;





}

测试

void test()
{
bstree<int>st;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
st.insert(e);
}
int ret=st.find(3);
int ret1 =st.find(100);
   //st._inorder();
cout << ret << " ";
cout << ret1 << " ";

  

}

在这里插入图片描述

二叉搜索树的删除

情况1(叶子节点)
在这里插入图片描述
情况2(有一个孩子)
在这里插入图片描述
我们发现情况1可以归并到情况2中去.
在这里插入图片描述
情况3(有两个孩子)
在这里插入图片描述

bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;

while (cur)
{   
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;

}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;



}  //往上是在找值
else//找到了
{





if (cur->_left == nullptr)//处理情况2
{  

else
{
if (parent->_left == cur)
{
parent->_left = cur->_right;


}
else
{

parent->_right = cur->_right;


}
}



delete cur;





}
else if (cur->_right == nullptr)//处理情况2
{

else
{
if (parent->_left == cur)
{
parent->_left = cur->_left;


}
else
{

parent->_right = cur->_left;


}

}




delete cur;





}
else//处理情况3,这里和图中不同的是去右子树找最左
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;

}
cur->_key = nex->_key;


per->_left = nex->_right;

delete nex;

}










return true;


}









}

return false;




}

情况1测试
在这里插入图片描述
情况2测试
在这里插入图片描述
情况3测试
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里还有一个问题,就是如果8没有右节点的话,也会崩溃.
在这里插入图片描述
在这里插入图片描述
同理左节点也是.
代码修改如下:

bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;

while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;

}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;



}
else
{
                 if (cur->_left == nullptr)
{
 if (cur == _root)
 {
 _root = cur->_right;


 }
 else
 {
if (parent->_left == cur)
{
parent->_left = cur->_right;


}
else
{

parent->_right = cur->_right;


}
}



delete cur;





}

else if (cur->_right == nullptr)
{ if (cur == _root)
 {
 _root = cur->_left;
 }
 else
 {

if (parent->_left == cur)
{
parent->_left = cur->_left;


}
else
{

parent->_right = cur->_left;


}

}




delete cur;





}
else
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;

}
cur->_key = nex->_key;


if (per->_left == nullptr)
{
per->_left = nex->_right;
}
else
{
per->_right = nex->_right;
}
delete nex;


}










return true;


}









}













return false;




}

3.源代码

tree.h

#pragma once
#include<iostream>
using namespace std;
template<class K>
struct bstreenode
{
bstreenode <K>* _left;
bstreenode <K>* _right;
K _key;
bstreenode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{
}
};
template<class K>
class bstree
{
typedef bstreenode<K> Node;
public:
bool insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return _root;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;

}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;

}
else
{

return false;

}
}
cur = new Node(key);
if (parent->_key < key)
{
parent->_right = cur;
}
else
{
parent->_left = cur;
}
return true;
}
void _inorder()
{
return inorder(_root);


}

bool find(const K& key)
{
if (_root == nullptr)
{
return false;

}
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
cur = cur->_right;

}
else if (cur->_key > key)
{
cur = cur->_left;

}
else
{

return true;
}



}
return false;





}
bool earse(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parent = cur;

while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;

}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;



}
else
{
                 if (cur->_left == nullptr)
{
 if (cur == _root)
 {
 _root = cur->_right;


 }
 else
 {
if (parent->_left == cur)
{
parent->_left = cur->_right;


}
else
{

parent->_right = cur->_right;


}
}



delete cur;





}

else if (cur->_right == nullptr)
{ if (cur == _root)
 {
 _root = cur->_left;
 }
 else
 {

if (parent->_left == cur)
{
parent->_left = cur->_left;


}
else
{

parent->_right = cur->_left;


}

}




delete cur;





}
else
{
Node* per = cur;
Node* nex = cur->_right;
while (nex->_left)
{
per = nex;
nex = nex->_left;

}
cur->_key = nex->_key;


if (per->_left == nullptr)
{
per->_left = nex->_right;
}
else
{
per->_right = nex->_right;
}
delete nex;


}










return true;


}









}













return false;




}














private:
    Node* _root = nullptr;
void inorder(Node* root)
{
if (root == nullptr)
return;
inorder(root->_left);
cout <<root->_key << " ";
inorder(root->_right);
}
};
void test()
{
bstree<int>st;
int a[] = { 8,3,1,10,6,4,7,14,13 };
for (auto e : a)
{
st.insert(e);
}
st.earse(10);
st.earse(14);
st.earse(13);
    st.earse(8);


    st._inorder();


  

}

.cpp

#include"tree.h"
int main()
{
test();



}

原文地址:https://blog.csdn.net/yyqzjw/article/details/137180193

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!