#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include"MyBST.h"
using namespace std;
int main()
{
cout<<"Please enter the numbers:"<<endl;//提示用户输入
MyBST *mybst = new MyBST( );//构造类MyBST的对象 mybst,指针类型
while(cin.peek()!='\n')//peek 相当于偷看一眼,再放回去
{ //当下一个读入的不是回车时
int temp;
cin>>temp;//读入数值
mybst->insertNode(temp);//插入树中
}
mybst->output();//打印二叉树图形
cout<<"Please enter the number to delete:"<<endl;//提示用户输入要删除的数值
int deletex;
while(scanf("%d",&deletex)!=EOF)//读入以文件结尾为止。控制台下使用ctrl+z+回车
{
Node *temp=mybst->findByKey(deletex);//创建值为deletex的节点temp
if(temp==nullptr)
cout<<"无 "<<deletex<<endl;//没有该节点,无法删除
else
mybst->deleteNode(temp);//删除该节点temp
mybst->output();//打印
}
}
主函数注释很全了。。。
题目要求:输入数字,以回车结束,建立二叉搜索树,并打印树形。
输入要删除的数字,重新打印树形。
二叉树的定义和基本函数 搬砖:https://www.cnblogs.com/coffeeSS/p/5452719.html
打印树形那里,其实是一个中序遍历,根在左,叶子在右。深度每增加一层,前面打印的空格就越多。
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<cstdlib>
using namespace std;
//节点结构
struct Node{
Node(int k=0):key(k){}//初始化
Node* parent = nullptr;//父节点
Node* left = nullptr;//左孩子
Node* right = nullptr;//右孩子
int key;//对应的数值
};
class MyBST{
private:
Node* root=nullptr;//根节点
Node* findSuccessor(Node* n);//寻找后继节点
Node* findPredecessor(Node* n);//寻找前驱节点
void insertNode(Node* n);//插入节点
void output_impl(Node* n, bool left, string indent);//输出函数需要调用的函数,方便打印树形
void output(Node* root);//遍历输出所有节点
public:
MyBST(){};//构造函数
Node* getRoot(){ return root; }//返回根节点
Node* findByKey(int k);//寻找数值为k的节点
void insertNode(int k);//插入数值为k的节点
void output()//输出树形
{
output(root);
}
void deleteNode(Node* n);//删除节点
};
Node* MyBST::findByKey(int k){
Node* temp = root;//获取根节点
while (temp != nullptr){
if (k == temp->key)//当key相等的时候返回匹配节点
{
return temp;
}
temp = k < temp->key ? temp->left : temp->right;//通过比较key的值来决定搜索向哪一棵子树进行
}
return nullptr;
}
Node* MyBST::findPredecessor(Node* n)//寻找前驱节点
{
if (n->left != nullptr){//若x的左子树不为空,
n = n->left; //则x前驱是x节点左子树里最靠右的那个节点
while (n->right != nullptr)
n = n->right;
return n;
}
while (n->parent != nullptr&&n->parent->left == n)//如果x的左子树为空,
n = n->parent;
return n->parent;//那么我们就要向上找x的第一个有右孩子且左子树里没有x节点的祖先
}
Node* MyBST::findSuccessor(Node* n)//寻找后继节点
{
if (n->right != nullptr)
{
//若n的右子树不为空,则n后继是x节点右子树里最靠左的那个节点
n = n->right;
while (n->left != nullptr)
n = n->left;
return n;
}
while (n->parent != nullptr&&n->parent->right == n)//如果n的左子树为空
n = n->parent;//那么我们就要向上找x的第一个有右孩子且左子树里没有x节点的祖先
return n->parent;
}
void MyBST::output_impl(Node* n, bool left, string indent)//输出树形
{
if (n->right)
{
output_impl(n->right, false, indent + " " );//右孩子则将left置为false,进入下一层时字符串增加空格
}
cout << indent;//输出字符串
cout << (left ? '\\' : '/');//打印“树枝”的方向
cout << "-----";//打印树枝
cout << n->key << endl;//打印数值
if (n->left)
{
output_impl(n->left, true, indent + " " );//左孩子则将left置为true,进入下一层时字符串增加空格
}
}
void MyBST::output(Node* n)//中序遍历
{
if (n->right)
{
output_impl(n->right, false, "");
}
cout << n->key << endl;
if (n->left)
{
output_impl(n->left, true, "");
}
}
void MyBST::insertNode(int k)//公有函数中的插入数值为k的节点
{
Node* n = new Node(k);//生成节点
insertNode(n);//调用私有函数,插入节点
}
void MyBST::insertNode(Node* n)//私有函数中,插入节点
{
Node* temp = root;
if (temp==nullptr){//树为空就设置根节点
root = n;
return;
}
while (true){//这个循环里有一个大的if-else结构,用来决定插入到左子树还是右子树
if (temp->key > n->key){//进入左子树
if (temp->left != nullptr)//if-else结构判断是否已经到达要插入的地方
temp = temp->left;//到达则替换,没有则深入
else{
temp->left = n;
n->parent = temp;
return;
}
}
else{
if (temp->right != nullptr)//进入右子树
temp = temp->right;
else{
temp->right = n;
n->parent = temp;
return;
}
}
}
}
void MyBST::deleteNode(Node* n)//删除节点
{
Node* temp;//用来存取代n节点位置的节点,下面的if分三种情况确定取代n节点位置的节点temp的取值
if (n->left == nullptr&&n->right == nullptr)//情况一:n没有孩子节点
temp = nullptr;
else if (n->left == nullptr || n->right == nullptr)
{
//情况二:n有一个孩子节点
temp = (n->left == nullptr) ? n->right : n->left;//我们用这个孩子节点当做取代n的节点
temp->parent = n->parent;//因为temp要取代n,所以要用temp复制n的属性,因为temp就是n的孩子节点之一,
} //且另一个孩子节点是nullptr,所以n的孩子节点的信息不用复制
else
{
//情况三:n有两个孩子节点,双支节点 y--temp
temp = findSuccessor(n);//我们用n节点的后继y当做取代n的节点
Node* successor_right;//y只可能有一个右孩子或者没有孩子,我们先要让y的右孩子取代y,再让y取代n
if (temp->right == nullptr)//如果y没有孩子,则用nullptr取代y
successor_right = nullptr;
else{
successor_right = temp->right;
successor_right->parent = temp->parent;//y有右孩子的时候要处理右孩子的父节点
}
if (temp->parent->left == temp)//这个if用来让y的父节点指向取代y的节点
temp->parent->left = successor_right;
else
temp->parent->right = successor_right;
//接下来要让y取代n了,其实我们只需要把y的key值给n就行了,然后直接退出,不需要再修改其他的部分了
n->key = temp->key;
delete temp;
return;
}
//情况一和情况二到此为止取代n节点的temp已经确定,而且当temp不是nullptr的时候,
//temp也已经复制了必要的n的属性,剩下的就是让n的父节点指向temp了
//注意被删除的节点有可能是根节点,所以当我们发现被删除的是根节点时,不需要让n的父节点指向temp,
//因为n没有父节点了,但是这个时候必须修改root指针的指向
if (n->parent != nullptr){
if (n->parent->left == n)
n->parent->left = temp;
else
n->parent->right = temp;
}
else
root = temp;//修改root指针的指向
delete n;
}
实验周的代码。
反正排名很低,没人看哈哈哈。
结果大概酱紫:
成绩出来了才敢放出来