二叉搜索树的c++实现
#include<windows.h>
#include<iostream>
using namespace std;
typedef int DataType;
struct node{
public:
node() :key(0),
left(nullptr),
right(nullptr),
father(nullptr)
{}
node(int k, node* a, node* b, node* c)
:key(k),
left(a),
right(b),
father(c)
{}
DataType key;
struct node* left;
struct node* right;
struct node* father;
};
typedef struct node node;
typedef struct node* pnode;
插入操作
class BST{
//typedef struct node node;
// typedef struct node* pnode;
public:
BST() :root(nullptr)
{}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
node* insert_bstree(int key){
node *z; // 新建结点
// 如果新建结点失败,则返回。
if ((z = new node(key, NULL, NULL, NULL)) == NULL)
return root;
insert(root, z);
}
void insert(pnode& root, pnode z){ //测试形参能不能用 pnode root
pnode y = NULL;
pnode x = root;
// 查找z的插入位置
while (x != NULL)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->father = y;
if (y == NULL)
{
root = z; //这里对 因为root 进行了操作
}
else if (z->key < y->key)
y->left = z;
else
y->right = z;
}
遍历操作
void preOrder()
{
preOrder(root);
}
void inOrder()
{
inOrder(root);
}
void postOrder()
{
postOrder(root);
}
void preOrder(pnode root)
{
if (root != NULL)
{
cout << root->key << " ";
preOrder(root->left);
preOrder(root->right);
}
}
void inOrder(pnode root) const
{
if (root != NULL)
{
inOrder(root->left);
cout << root->key << " ";
inOrder(root->right);
}
}
void postOrder(pnode root) const
{
if (root != NULL)
{
postOrder(root->left);
postOrder(root->right);
cout << root->key << " ";
}
}
查找操作
pnode BST_search(pnode root, int key)const{
if (root == NULL || root->key == key)
return root;
if (key < root->key)
return BST_search(root->left, key);
else
return BST_search(root->right, key);
}
//查找指定key的节点
pnode search(int key) const {
return BST_search(root, key);
}
//查找最大节点值
int max_search(){
pnode node= _max(root);
return node->key;
}
pnode _max(pnode root){
if (root == nullptr)
return root;
while (root->right != NULL)
root = root->right;
return root;
}
//查找最小节点值
int min_search(){
pnode node = _min(root);
return node->key;
}
pnode _min(pnode root){
if (root == nullptr)
return root;
while (root->left != NULL)
root = root->left;
return root;
}
//查找节点的前驱节点
pnode pre_node(pnode x){
// 如果x存在左孩子,则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
if (x->left != NULL)
return _max(x->left);
// 如果x没有左孩子。则x有以下两种可能:
// (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
// (01) x是"一个左孩子",则查找"x的最低的父结点,并且该父结点要具有右孩子",找到的这个"最低的父结点"就是"x的前驱结点"。
pnode y = x->father;
while ((y != NULL) && (x == y->left))
{
x = y;
y = y->father;
}
return y;
}
//查找节点的后继节点
pnode post_node(pnode x){
// 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
if (x->right != NULL)
return _min(x->right);
// 如果x没有右孩子。则x有以下两种可能:
// (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
// (02) x是"一个右孩子",则查找"x的最低的父结点,并且该父结点要具有左孩子",找到的这个"最低的父结点"就是"x的后继结点"。
pnode y = x->father;
while ((y != NULL) && (x == y->right))
{
x = y;
y = y->father;
}
return y;
}
删除操作
思路:
找到需要删除的节点之后,关于节点删除的规则如下:
1. 如果该节点是叶子节点,直接删除该节点即可。
2. 如果该节点不是叶子节点,但是只有左孩子或者右孩子的话,先交换该节点与其左孩子或者右孩子的值,然后删除其左孩子或者右孩子。
3. 如果该节点既有左孩子,又有右孩子的话,可以采用如下方式进行调整(这里对该节点的右子树进行调整,左子树调整同理)
(1)先新建一个指针,指向要删除节点的右孩子。
(2)由于右孩子可能本身存在左孩子,即delNode->right->left != NULL,而delNode->right->left->val是小于delNode->right->val的,所以直接向delNode->right->val赋值给要删除的节点是不可取的,因此要先要找到删除节点的右子树中的最小节点,即递归判断删除节点的右孩子的左孩子是否存在。
(3)找到删除节点右子树的最小节点minRNode,将其与要删除的节点delNode交换取值,然后删除minRNode
```c
TreeNode* deleteNode(TreeNode* root, int key) {
if(root == NULL)
return NULL;
if(root->val == key){
if(root->left != NULL && root->right != NULL){
TreeNode* minRNode = root->right;
while(minRNode->left != NULL)
minRNode = minRNode->left;
root->val = minRNode->val;
root->right = deleteNode(root->right, minRNode->val);
}
else{
if(root->left != NULL){ //仅有左孩子
root->val = root->left->val;
delete(root->left);
}
else if(root->right != NULL){ //仅有右孩子
root->val = root->right->val;
delete(root->right);
}
else{ //无孩子
delete(root);
}
}
return root;
}
if(key > root->val)
root->right = deleteNode(root->right, key);
else if(key < root->val)
root->left = deleteNode(root->left, key);
return root;
}
## 销毁操作
```c
void destroy(pnode*& root){
if(!root)
return;
if(!root->left)
destroy(root->left);
if(!root->right)
destroy(root->right);
delete root;
root=NULL;
}
void destroy(){
destroy(root);
}
打印操作
//二叉树的打印
void print(){
if (root != nullptr)
{
print(root,root->key,0);
}
}
void print(pnode root, int key, int direction){
if (root != NULL)
{
if (direction == 0) // tree是根节点
cout << root->key << " is root" << endl;
else // tree是分支节点
cout << root->key << " is " << key << "'s " << (direction == 1 ? "right child" : "left child") << endl;
print(root->left, root->key, -1);
print(root->right, root->key, 1);
}
}
/////////////
private:
pnode root;
};
测试代码
int main(){
//1.测试形参能不能用 ? pnode(&) root
//2.c++版本遍历的参数写法?
BST* tree=new BST();
int arr[] = { 1, 5, 4, 3, 2, 6 };
for (int i = 0; i<6; i++)
{
cout << arr[i] << " ";
tree->insert_bstree(arr[i]);
}
cout << "\n== 前序遍历: ";
tree->preOrder();
cout << "\n== 中序遍历: ";
tree->inOrder();
cout << "\n== 后序遍历: ";
tree->postOrder();
cout << endl;
//查找指定值
tree->search(5);
//查找最大值和最小值
cout << tree->max_search() << endl;;
cout << tree->min_search() << endl;
//查找前驱和后继
//节点的前驱:是该节点的左子树中的最大节点。
//节点的后继:是该节点的右子树中的最小节点。
//删除节点
//打印节点
tree->print();
//销毁节点
system("pause");
return 0;
}
结果:
建造好的树的结构就是这个样子: