#include<iostream>
#include<assert.h>
#include"mystack.h"
using namespace std;
#define isLess(a,b) (a<b)
#define isEqual(a,b) (a== b)
//typedef struct _Tnode
//{
// struct _Tnode* lchild;
// struct _Tnode* rchild;
// DataTypeTreeTree data;
//}BNode,BTree;//放到Stack.h了
//插入元素-构建树
//为什么要传二级指针(指针引用)?因为根据大小排布,根节点是会发生变化的。
//传1级指针(引用),修改对应东西里面的内容
//传2级指针(指针+ 引用),修改这个东西
bool insertBtree(BTree*& root, BNode* node)
{
BNode* tmp = NULL;
BNode* parent = NULL;
if (!node)
{
return false;
}
else//置空新结点的左右子树
{
node->lchild = NULL;
node->rchild = NULL;
}
if (root)//存在根节点,那就准备对比大小为新的结点寻找合适的插入位置
{
tmp = root;//拿到根结点
}
else//如果第一次构建树,没有根结点,那就创建一个
{
root = node;
return true;
}
while (tmp)
{
parent = tmp;//保存一个父结点
if (isLess(node->data, tmp->data))//如果当前插入结点数值小于父结点数值
{
tmp = tmp->lchild;
}
else//大于等于
{
tmp = tmp->rchild;
}
}
if (isLess(node->data, parent->data))//小于
{
parent->lchild = node;
}
else
{
parent->rchild = node;
}
return true;
}
//找到当前结点中左子树中最大的值
int findMax(BTree* root)
{
assert(root);
//方式一,使用递归
//只要当前结点有右子树就进去,直到没有右子树,当前结点的data就是最大的
if (root->rchild == NULL)
{
return root->data;
}
return findMax(root->rchild);
//方式二,使用循环方式
/*
因为传进来的不是二级指针,我们能对root的值进行成功修改
但是不能改变root指向的地址,也就是说root = root->rchild
没有改变原来传进来的root指向
也就是说,指针存的是地址,要修改指针的地址,需要指针的指针。(传参时)
*/
/*while (root->rchild)
{
root = root->rchild;
}
return root->data;*/
}
//删除结点
//将该值与root进行大小比较,小的就往左,大的就往右
/*
多种情况
1.要删除的结点为叶子结点,直接删除即可
2.要删除的结点存在左子结点不存在右子结点,用左子结点代替删除结点即可
3.要删除的结点存在右子结点,不存在左子结点,直接用右子结点代替删除结点即可
4.要删除的结点左右子树都有,则取左子树上最大结点或右子树上最小结点代替删除结点
*/
//使用递归不断的去找这个key值对应的结点
//成功找到,根据情况进行删除操作,然后逐层返回
BTree* deleteNode(BTree* root, int key, BNode*& DeleteNode)
{
//为空
if (!root)
{
return NULL;
}
//下面这两个if确定key的位置,找到它这个结点
if (root->data > key)
{
root->lchild = deleteNode(root->lchild, key, DeleteNode);
return root;
}
if (root->data < key)
{
root->rchild = deleteNode(root->rchild, key, DeleteNode);
return root;
}
//找到要删除的结点,存进DeleteNode(指针的引用 or 二级指针 可以改变地址)
DeleteNode = root;
//成功找到,根据条件进行返回
if ((!root->lchild) && (!root->rchild))//要删除的结点为root结点
{
delete root;
return NULL;
}
if ((root->lchild) && (!root->rchild))//要删除的结点有左孩子,没有右孩子
{
return root->lchild;
}
if ((!root->lchild) && (root->rchild))//要删除的结点有右孩子,没有左孩子
{
return root->rchild;
}
//要删除的结点左右孩子都有
//先找到当前要删除的结点左子树中最大的值(右子树最小的值同理)
int val = findMax(root->lchild);
root->data = val;//代替要删除的key值
//将找到的ket = val的那个结点删除
root->lchild = deleteNode(root->lchild, val, DeleteNode);
//这里最后delete的那个结点就并不是和具有val值的那个结点,而是要删除结点中左子树中最大data的那个。
//将最大data覆盖上val值对应结点的那个data
//删除的方式不同是因为对应的父子结点情况不同
return root;
}
//前序遍历(中左右)——递归实现
void FrontPrint(BTree* root)
{
//到哪个结点, 哪个结点就是中,因为都可以有自己的子结点
if (!root)
{
return;
}
cout << root->data << " ";
FrontPrint(root->lchild);
FrontPrint(root->rchild);
}
//注意返回调用的位置,从哪调用return回哪,多层中的语句执行结束也会返回到调用处
//中序遍历(左中右)——递归实现
void MidPrint(BTree* root)
{
if (!root)
{
return;
}
MidPrint(root->lchild);
cout << root->data << " ";
MidPrint(root->rchild);
}
//后序遍历(左右中)——递归实现
void BehindPrint(BTree* root)
{
if (!root)
{
return;
}
BehindPrint(root->lchild);
BehindPrint(root->rchild);
cout << root->data << " ";
}
//递归方式查找
//注意返回指针类型
//找到返回的就是指向那个结点的一个指针
//没找到返回的就是NULL
BNode* Find1(BTree* root, int key)
{
//由此我们可以知道 || 运算符是从左往有进行执行的,左边一旦成立,那么根本就不看后面的运算结果
//这里的root为空,说明没查到,为空执行root->data越界访问,所以要把!root条件放到前面
if (!root || isEqual(root->data, key))
{
return root;
}
else if (isLess(key, root->data))
{
return Find1(root->lchild, key);
}
else
{
return Find1(root->rchild, key);
}
}
//非递归方式查找1
void Find2(BTree* root, int key)
{
while (root)
{
if (isLess(root->data, key))
{
root = root->rchild;
}
else if (isLess(key, root->data))
{
root = root->lchild;
}
else
{
cout << "找到了" << endl;
break;
}
}
if (!root)
{
cout << "没找到" << endl;
}
}
//非递归方式查找2
BNode* Find3(BTree* root, int key)
{
while (root && !isEqual(root->data, key))
{
if (isLess(root->data, key))
{
root = root->rchild;
}
else
{
root = root->lchild;
}
}
return root;
}
//借助栈实现前序遍历
//谁的优先级最低谁就先被压进栈
void PrintFrontWithStack(BTree* root)
{
BNode cur;
if (!root)
{
return;
}
Stack Tstack;
initStack(Tstack);
pushStack(Tstack, *root);
while (!isEmpty(Tstack))
{
popStack(Tstack, cur);
cout << cur.data << " ";
//按照中左右的顺序,右边的最后再打印,所以先把rchild压进栈
if (cur.rchild)
{
pushStack(Tstack,*(cur.rchild));
}
if (cur.lchild)
{
pushStack(Tstack, *(cur.lchild));
}
}
cout << endl;
destoryStack(Tstack);
}
int main(void)
{
int arr[8] = { 11,18,9,35,6,17,4,15 };
BTree* root = NULL;//根结点
BNode* node = NULL;
for (int i = 0; i < 8; i++)
{
node = new BNode;
node->data = arr[i];
insertBtree(root, node);
}
BNode* DeleteNode = NULL;//存储要删除结点
FrontPrint(root);
//MidPrint(root);
cout << endl;
/*deleteNode(root, 18, DeleteNode);
if (DeleteNode)
{
cout << "删除成功" << endl;
}
else
{
cout << "删除失败" << endl;
}
delete DeleteNode;*/
//FrontPrint(root);
//BNode* temp = NULL;
temp = Find1(root, 11);
//temp = Find3(root, 11);
//if (!temp)
//{
// cout << "没找到" << endl;
//}
//else
//{
// cout << "找到了" << endl;
//}
//Find2(root, 35);
PrintFrontWithStack(root);
BehindPrint(root);
return 0;
}