目录
1.什么是二叉排序树?
二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。
性质:
一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
2.二叉排序树如何构建?
假设有8 4 2 5 10 9 13一系列数字,要求以8为根结底构造二叉排序树
要清楚构建二叉排序树就是一个一个插入节点的过程,要找到待插节点的前一个位置,用prev表示,若待插节点比prev大,则插到prev右边,否则插到prev左边;
问题进一步简化,变成了如何找prev节点?
Node*temp=root;
Node*prev=NULL;
while(temp!=NULL){
prev=temp;
if(key<temp->data){
temp=temp->left;
}
else if(key>temp->data){
temp=temp->right;
}
else return;//排除相等的存在
}
插入节点完整代码化
void Insert(int key){//插入每个节点时都是从根开始遍历一遍
Node*temp=root;
Node*prev=NULL;
while(temp!=NULL){
prev=temp;
if(key<temp->data){
temp=temp->left;
}
else if(key>temp->data){
temp=temp->right;
}
else return;//排除相等的存在
}
if(key<prev->data){
prev->left=(Node*)malloc(sizeof(Node));
prev->left->data=key;
prev->left->left=NULL;
prev->left->right=NULL;
}
if(key>prev->data){
prev->right=(Node*)malloc(sizeof(Node));
prev->right->data=key;
prev->right->left=NULL;
prev->right->right=NULL;
}
}
3.二叉排序树如何搜索?
二叉排序树的搜索过程有一点类似于二分查找,最好的情况下时间复杂度为O(logn)。查找其实很简单,从根节点root开始,如果关键字Key小于根节点的值,那么查找根的左子树;否则,查找根的右子树。
bool search(int key){
Node*temp=root;
while(temp!=NULL){
if(key==temp->data) return true;//找到
if(key<temp->data) temp=temp->left;//查找左子树
if(key>temp->data) temp=temp->right;//查找右子树
}
return false;
}
4.二叉排序树节点删除?
接下来要说说比较麻烦的删除操作:删除某个节点后,要保证剩下的节点仍然是一棵二叉排序树。
删除操作分为三种情况:
(1)假设待删除节点D只有右孩子,没有左孩子。那么只要将要删除结点D的右孩子赋值给节点D,然后删除右孩子节点。
(2)假设待删除节点D只有左孩子,没有右孩子。那么只要将要删除结点D的左孩子赋值给节点D,然后删除右孩子节点。
例如要删除节点10,操作如下
(3)假设待删除节点既有左孩子又有右孩子。
假设删除节点8,
我们的目标依然是要保证删除结点8后,再次中序遍历它,仍不改变其升序的排列方式。 那么我们需要用5替换原来的位置。
为什么需要用5替换8的位置?先对这棵树中序遍历看看 2 4 5 8 9 10 13 ,8前面的数是5,删除8后我们期望得到2 4 5 9 10 13的中序遍历序列,因此要用5覆盖掉8,再把原来5节点删除。
对代码的解释说明:
(1)在删除节点时,使用了指向指针的引用Node*&node,以便能够修改指向指针的值,避免了在函数中使用临时指针的情况。
(2)delete node; node = temp;这两句代码,将node空间释放了,为什么还能给nodes赋值?
delete node;
是用来释放待删除节点的内存空间的操作。然后node = temp;
是将左子树中值最大的节点(即temp)赋值给待删除节点(即node),以实现节点的替换。这里注意的是,释放内存空间并不会立即将指针变量的值置为NULL,而是保持原有的指向。在这种情况下,node = temp;
将node指向了左子树中的新节点,以确保树的结构仍然正确。
int del(Node*& node, int key) {
if (node == NULL) return -1;
if (key < node->data) {
return del(node->left, key);
}
else if (key > node->data) {
return del(node->right, key);
}
else {
if (node->left == NULL) {
Node* temp = node->right;
delete node;
node = temp;
}
else if (node->right == NULL) {
Node* temp = node->left;
delete node;
node = temp;
}
else {
Node* temp = node->left;
Node* prev = node;
while (temp->right != NULL) {
prev = temp;
temp = temp->right;
}
node->data = temp->data;
del(prev->right, temp->data);//递归删除用来覆盖待删除节点值的节点
}
}
return 0;
}
完整代码
#include <bits/types/struct_tm.h>
#include <cstdlib>
#include<iostream>
#include <memory>
#include <ostream>
#include <type_traits>
using namespace std;
typedef struct SortTree{
int data;
struct SortTree*left;
struct SortTree*right;
}Node,*Tree;
Tree root;
void Init(int key){//初始化根节点
root=(Node*)malloc(sizeof(Node));
root->data=key;
root->left=NULL;
root->right=NULL;
}
void Insert(int key){//插入每个节点时都是从根开始遍历一遍
Node*temp=root;
Node*prev=NULL;
while(temp!=NULL){
prev=temp;
if(key<temp->data){
temp=temp->left;
}
else if(key>temp->data){
temp=temp->right;
}
else return;//排除相等的存在
}
if(key<prev->data){
prev->left=(Node*)malloc(sizeof(Node));
prev->left->data=key;
prev->left->left=NULL;
prev->left->right=NULL;
}
if(key>prev->data){
prev->right=(Node*)malloc(sizeof(Node));
prev->right->data=key;
prev->right->left=NULL;
prev->right->right=NULL;
}
}
void show(Node *p){//中序遍历输出二叉排序树结果
if(p!=NULL){
show(p->left);
cout<<p->data<<" ";
show(p->right);
}
}
bool search(int key){
Node*temp=root;
while(temp!=NULL){
if(key==temp->data) return true;
if(key<temp->data) temp=temp->left;
if(key>temp->data) temp=temp->right;
}
return false;
}
int del(Node*& node, int key) {
if (node == NULL) return -1;
if (key < node->data) {
return del(node->left, key);
}
else if (key > node->data) {
return del(node->right, key);
}
else {
if (node->left == NULL) {
Node* temp = node->right;
delete node;
node = temp;
}
else if (node->right == NULL) {
Node* temp = node->left;
delete node;
node = temp;
}
else {
Node* temp = node->left;
Node* prev = node;
while (temp->right != NULL) {
prev = temp;
temp = temp->right;
}
node->data = temp->data;
del(prev->right, temp->data);
}
}
return 0;
}
int main(){
int r;
int q;
cout<<"请输入根节点的值:"<<endl;
cin>>r;
Init(r);
int x;
int y;
cout<<"请输入等待插入的节点的值(按-1结束)"<<endl;
cin>>x;
while(x!=-1){
Insert(x);
cin>>x;
}
cout<<"请输入要查询的值:"<<endl;
cin>>q;
if(search(q)) cout<<"存在"<<endl;
else cout<<"查询失败"<<endl;
show(root);
puts("");
cout<<"请输入待删除节点:"<<endl;
cin>>y;
if(del(root,y)==0) {
show(root);
}else{
cout<<"删除失败"<<endl;
}
return 0;
}
/*
请输入根节点的值:
8
请输入等待插入的节点的值:
4 2 5 10 9 13 -1
请输入要查询的值:
4
存在
2 4 5 8 9 10 13
请输入待删除节点:
8
2 4 5 9 10 13
*/