目录
利用代码对二叉树进行实现
一.二叉树的声明
#include<iostream>
using namespace std;
#define FALSE 0
#define TRUE 1
#define Type int
//二叉树的节点类
class btNode
{
public:
//值
Type date;
//左节点指针
btNode* Left_link;
//右节点指针
btNode* Right_link;
//父母节点指针
btNode* Parent_link;
};
//二叉树类
class binaryTree
{
public:
//根节点
btNode* root;
};
我们需要声明两个类,一个类用来存放具体的二叉树属性,一个类用来表示一棵具体的二叉树,由根节点进行连接
二.初始化
//初始化
void Initialize(btNode& bt)
{
bt.date = 0;
bt.Left_link = NULL;
bt.Right_link = NULL;
bt.Parent_link = NULL;
}
三.创建二叉树
//创建
int Create(binaryTree&tree)
{
tree.root = new (btNode);
if (tree.root == NULL)
{
return FALSE;
}
return TRUE;
}
四.插入
//插入
void Insert(btNode* root, btNode* z)
{
btNode* new_parent=NULL;//插入节点的父节点
//将要插入的节点的值与根节点的值比较,寻找合适的根节点成为插入节点的父节点
while (root != NULL)
{
new_parent = root;
//若根的值小于插入节点的值,则将根的左孩子成为新的根节点
if (root->date < z->date)
{
root = root->Left_link;
}
//反之则将根的右孩子成为新的根节点
else
{
root = root->Right_link;
}
}
z->Parent_link = new_parent;
if (new_parent == NULL)
{
root = z;//二叉树没有根,所以插入节点为根
}
//判断插入节点为左孩子还是右孩子
else
if (z->date < new_parent->date)
{
z = new_parent->Left_link;//值小于父节点时为左孩子
}
else
{
z = new_parent->Right_link;//值大于父节点时为右孩子
}
}
五.查找
//查找
btNode* Search(binaryTree&tree,int in_put)
{
//先判断根节点是否为查找的值
if (tree.root->date == in_put)
{
return tree.root;
}
//判断根的左右孩子是否为查找的值
if (tree.root->Left_link->date == in_put)
{
return tree.root->Left_link;
}
if (tree.root->Right_link->date == in_put)
{
return tree.root->Right_link;
}
//若都不是则进入函数进行递归继续查找
else
{
btNode*x=Search(tree.root->Left_link,in_put);
btNode*y=Search(tree.root->Right_link,in_put);
btNode* w = NULL;//用来表示找不到的情况
if (x != NULL)
{
return x;
}
if (y != NULL)
{
return y;
}
else
{
return w;//找不到则返回空指针
}
}
}
btNode* Search(btNode* z,int _input)
{
//传进来的节点的左孩子
if (z->Left_link->date == _input)
{
return z->Left_link;
}
//传进来的节点的右孩子
if (z->Right_link->date == _input)
{
return z->Right_link;
}
//递归出口,查找到叶子节点就停止
if (z->Left_link == NULL||z->Right_link ==NULL)
{
return;
}
//递归入口
else
{
Search(z->Left_link->Left_link, _input);
Search(z->Left_link->Right_link, _input);
Search(z->Right_link->Left_link, _input);
Search(z->Right_link->Right_link, _input);
}
}
设计两个查找函数,一个进行主体查找,一个用来实现递归,但递归的查找函数不够高效,没有利用到二叉树的性质,即左孩子比右孩子值小,利用这个性质可以更高效
//优化代码,同样是递归但利用左孩子比根节点和右孩子小,右孩子比根节点和左孩子大的性质可更高效
btNode*Search1(btNode* x, int _input)
{
if (x == NULL || _input == x->date)
{
return x;
}
if (_input < x->date)
{
return Search1(x->Left_link, _input);
}
else
{
return Search1(x->Right_link, _input);
}
}
同样是递归函数,第二个代码量比第一个减少很多
六.删除
二叉树的删除分为三种情况
1.删除的节点为叶子节点
2.删除的节点为单孩子节点
3.删除的节点为双孩子节点
同样设计两个函数来实现删除,一个功能为删除(根据输入的值),一个功能为实现删除节点的父节点和孩子节点的交接,并讨论是哪种删除情况
//删除入口(根据值来找到要删除的节点)
btNode* Delete(binaryTree &tree,int in_put)
{
btNode* x = Search(tree, in_put);//找到删除的节点
btNode* y = Delete(tree.root, x);//对删除节点操作后回传进行删除
if (y != NULL)
{
delete y;
y = NULL;
}
}
//删除
btNode* Delete(btNode* root, btNode* z)
{
btNode* a = NULL;
//先判断想要删除的节点是叶子节点还是普通节点(即是否有左右孩子)
if (z->Left_link == NULL && z->Right_link == NULL)
{
return z;
}
//普通节点
else
{
//判断是否为只有右孩子节点
if (z->Left_link == NULL)
{
a=z->Right_link->Parent_link;//将右孩子看为a
}
//判断是否为只有左孩子节点
if (z->Right_link == NULL)
{
a=z->Left_link->Parent_link;//将左孩子看为a
}
//两个孩子都有
else
{
//可以采用后继节点的方法和前驱节点
//后继节点比被删节点大,是被删节点的右子树的最小节点,即右子树的最左节点,将后继节点代替成为被删节点
//由于后继节点比被删节点大,又是右子树的最小节点,所以肯定比被删节点的右孩子小,比被删节点的左孩子大
//且由于是最左节点,所以该节点只能是叶子节点或单右孩子节点,不会造成同样有两个孩子
//前驱节点也是同样的原理,是左子树的最大节点,即最右孩子
btNode* x = NULL;
//后继方法
//若被删节点的右孩子为叶子节点,直接替代
if (z->Right_link->Left_link == NULL && z->Right_link->Right_link == NULL)
{
//将被删节点的父节点给其右孩子
z->Right_link->Parent_link = z->Parent_link;
z->Right_link->Left_link = z->Left_link;
}
x = z->Right_link->Left_link;
while (x!=NULL)
{
if (x->Left_link ==NULL&x->Right_link ==NULL||x->Left_link ==NULL&&x->Right_link ->Left_link ==NULL)
{
//使x代替被删节点
x->Parent_link = z->Parent_link;
x->Left_link = z->Left_link;
x->Right_link = z->Right_link;
}
x = x->Left_link;
}
}
//将删除节点的父节点移交给其孩子节点
a->Parent_link = z->Parent_link;
//判断删除节点是左孩子还是右孩子
if (z->date == z->Parent_link->Left_link->date)
{
z->Parent_link->Left_link = a;//将a作为新的左孩子
}
if (z->date == z->Parent_link->Right_link->date)
{
z->Parent_link->Right_link = a;//将a作为新的右孩子
}
return z;
}
}
7.二叉树的遍历
1.遍历入口
//遍历树
void OrderTree(binaryTree&tree)
{
PreOrder(tree.root);
InOrder(tree.root);
PostOrder(tree.root);
}
2.先序遍历
先序遍历是先将根节点进行输出,先遍历左子树再遍历右子树
//先序遍历
void PreOrder(btNode* z)
{
//递归出口
if (z == NULL)
{
return;
}
cout << z->date << endl;
//左在右上面在递归中会先把左子树都遍历完毕再遍历右子树
PreOrder(z->Left_link);//先序遍历左子树
PreOrder(z->Right_link);//先序遍历右子树
}
3.中序遍历
//中序遍历
void InOrder(btNode* z)
{
//递归出口
if (z == NULL)
{
return;
}
//递归回退的过程中先打印根节点
InOrder(z->Left_link);
cout << z->date << endl;
InOrder(z->Right_link);
}
4.后序遍历
//后序遍历
void PostOrder(btNode* z)
{
if (z == NULL)
{
return;
}
//递归回退的过程中先打印孩子节点
PostOrder(z->Left_link);
PostOrder(z->Right_link);
cout << z->date << endl;
}
可见用递归实现三种遍历代码都很简洁,可根据输出元素的位置来体会实现三种遍历的区别
8.完整代码
#include<iostream>
using namespace std;
#define FALSE 0
#define TRUE 1
#define Type int
//二叉树的节点类
class btNode
{
public:
//值
Type date;
//左节点指针
btNode* Left_link;
//右节点指针
btNode* Right_link;
//父母节点指针
btNode* Parent_link;
};
//二叉树类
class binaryTree
{
public:
//根节点
btNode* root;
};
//初始化
void Initialize(btNode& bt)
{
bt.date = 0;
bt.Left_link = NULL;
bt.Right_link = NULL;
bt.Parent_link = NULL;
}
//创建
int Create(binaryTree&tree)
{
tree.root = new (btNode);
if (tree.root == NULL)
{
return FALSE;
}
return TRUE;
}
//插入
void Insert(btNode* root, btNode* z)
{
btNode* new_parent=NULL;//插入节点的父节点
//将要插入的节点的值与根节点的值比较,寻找合适的根节点成为插入节点的父节点
while (root != NULL)
{
new_parent = root;
//若根的值小于插入节点的值,则将根的左孩子成为新的根节点
if (root->date < z->date)
{
root = root->Left_link;
}
//反之则将根的右孩子成为新的根节点
else
{
root = root->Right_link;
}
}
z->Parent_link = new_parent;
if (new_parent == NULL)
{
root = z;//二叉树没有根,所以插入节点为根
}
//判断插入节点为左孩子还是右孩子
else
if (z->date < new_parent->date)
{
z = new_parent->Left_link;//值小于父节点时为左孩子
}
else
{
z = new_parent->Right_link;//值大于父节点时为右孩子
}
}
//查找
btNode* Search(binaryTree&tree,int in_put)
{
//先判断根节点是否为查找的值
if (tree.root->date == in_put)
{
return tree.root;
}
//判断根的左右孩子是否为查找的值
if (tree.root->Left_link->date == in_put)
{
return tree.root->Left_link;
}
if (tree.root->Right_link->date == in_put)
{
return tree.root->Right_link;
}
//若都不是则进入函数进行递归继续查找
else
{
btNode*x=Search(tree.root->Left_link,in_put);
btNode*y=Search(tree.root->Right_link,in_put);
btNode* w = NULL;//用来表示找不到的情况
if (x != NULL)
{
return x;
}
if (y != NULL)
{
return y;
}
else
{
return w;//找不到则返回空指针
}
}
}
btNode* Search(btNode* z,int _input)
{
//传进来的节点的左孩子
if (z->Left_link->date == _input)
{
return z->Left_link;
}
//传进来的节点的右孩子
if (z->Right_link->date == _input)
{
return z->Right_link;
}
//递归出口,查找到叶子节点就停止
if (z->Left_link == NULL||z->Right_link ==NULL)
{
return;
}
//递归入口
else
{
Search(z->Left_link->Left_link, _input);
Search(z->Left_link->Right_link, _input);
Search(z->Right_link->Left_link, _input);
Search(z->Right_link->Right_link, _input);
}
}
//优化代码,同样是递归但利用左孩子比根节点和右孩子小,右孩子比根节点和左孩子大的性质可更高效
btNode*Search1(btNode* x, int _input)
{
if (x == NULL || _input == x->date)
{
return x;
}
if (_input < x->date)
{
return Search1(x->Left_link, _input);
}
else
{
return Search1(x->Right_link, _input);
}
}
//删除
btNode* Delete(btNode* root, btNode* z)
{
btNode* a = NULL;
//先判断想要删除的节点是叶子节点还是普通节点(即是否有左右孩子)
if (z->Left_link == NULL && z->Right_link == NULL)
{
return z;
}
//普通节点
else
{
//判断是否为只有右孩子节点
if (z->Left_link == NULL)
{
a=z->Right_link->Parent_link;//将右孩子看为a
}
//判断是否为只有左孩子节点
if (z->Right_link == NULL)
{
a=z->Left_link->Parent_link;//将左孩子看为a
}
//两个孩子都有
else
{
//可以采用后继节点的方法和前驱节点
//后继节点比被删节点大,是被删节点的右子树的最小节点,即右子树的最左节点,将后继节点代替成为被删节点
//由于后继节点比被删节点大,又是右子树的最小节点,所以肯定比被删节点的右孩子小,比被删节点的左孩子大
//且由于是最左节点,所以该节点只能是叶子节点或单右孩子节点,不会造成同样有两个孩子
//前驱节点也是同样的原理,是左子树的最大节点,即最右孩子
btNode* x = NULL;
//后继方法
//若被删节点的右孩子为叶子节点,直接替代
if (z->Right_link->Left_link == NULL && z->Right_link->Right_link == NULL)
{
//将被删节点的父节点给其右孩子
z->Right_link->Parent_link = z->Parent_link;
z->Right_link->Left_link = z->Left_link;
}
x = z->Right_link->Left_link;
while (x!=NULL)
{
if (x->Left_link ==NULL&x->Right_link ==NULL||x->Left_link ==NULL&&x->Right_link ->Left_link ==NULL)
{
//使x代替被删节点
x->Parent_link = z->Parent_link;
x->Left_link = z->Left_link;
x->Right_link = z->Right_link;
}
x = x->Left_link;
}
}
//将删除节点的父节点移交给其孩子节点
a->Parent_link = z->Parent_link;
//判断删除节点是左孩子还是右孩子
if (z->date == z->Parent_link->Left_link->date)
{
z->Parent_link->Left_link = a;//将a作为新的左孩子
}
if (z->date == z->Parent_link->Right_link->date)
{
z->Parent_link->Right_link = a;//将a作为新的右孩子
}
return z;
}
}
//删除入口(根据值来找到要删除的节点)
btNode* Delete(binaryTree &tree,int in_put)
{
btNode* x = Search(tree, in_put);//找到删除的节点
btNode* y = Delete(tree.root, x);//对删除节点操作后回传进行删除
if (y != NULL)
{
delete y;
y = NULL;
}
}