前言:
本代码实现二叉树的基本操作(四种遍历,增删查,求节点数,求树高,求单层节点数,求叶子数,镜像反转,相似树,判断完全二叉树,冒泡排序…);如右错误和可优化之处,还请指点!
实现代码:
/*************************************************************************
> File Name: Btree.cpp
> Author: 念念
> Mail: 2845906049@qq.com
> Created Time: 2021年08月21日 星期六 17时42分40秒
> Function: 二叉树的基本操作(四种遍历,增删查,求节点数,求树高,
求单层节点数,求叶子数,镜像反转,相似树,判断完全二叉树,冒泡排序...)
************************************************************************/
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <queue>
using namespace std;
struct Node //树节点结构体
{
int data;
Node * left;
Node * right;
};
class Btree
{
public:
Btree(){root = NULL;}
~Btree(){freeTree(root);}
Node *getRoot() const {return root;}
//生成len个随机数并插入树
void setRandTree(int len);
//接口,二叉树的插入,小左大右,调用私有insert函数递归
void insert(int data);
//接口,找到对应值的位置,返回其指针
//这里有一个问题:如果没找到直接返回空,在外部程序调用了返回节点的内部元素会出现段错误。
//所以在外部调用要先判断返回值是否为空。
Node * search(int data) const {return search(root,data);}
//接口,按值删除
void delet(int data){delet(root,data);}
//三种递归遍历,前中后序,调用对应私有成员函数递归
void prePrint() const {cout << "前序遍历:";prePrint(root);cout << endl;}
void midPrint() const {cout << "中序遍历:";midPrint(root);cout << endl;}
void tailPrint() const {cout <<"后序遍历:";tailPrint(root);cout << endl;}
//层序遍历
void levelPrint();
//获取节点数
void showCount() const {cout << "节点数为:" << getCount(root);cout << endl;}
int getCount() const {return getCount(root);}
//获取树高
void showHigh() const {cout << "树 高 为:" << getHight(root);cout << endl;}
int getHight() const {return getHight(root);}
//求第level层节点数
void showLevelCount(unsigned int level) const
{cout << "第" << level << "层的节点数为:" << getLevelCount(root,level) << endl;}
int getLevelCount(unsigned int level) const {return getLevelCount(root,level);}
//求叶子节点数
void showLeafCount() const
{cout << "叶子数为:" << getLeafCount(root) << endl;}
int getLeafCount(){return getLeafCount(root);}
//镜像反转接口
void mirroTree(){mirroTree(root);}
//判断结构相似接口
void showStructCmp(Node *other) const
{isStructCmp(root,other) ? cout << "结构相似\n" : cout << "结构不同\n";}
bool isStructCmp(Node *root1,Node *root2) const ;
//判断是否为完全二叉树接口
void showCompleteTree()
{isCompleteTree() ? cout << "完全二叉树\n" : cout << "非完全二叉树\n";}
bool isCompleteTree();
//排序:中序遍历输出
void sortPrint() const {midPrint();}
private:
//创建新节点
Node *createNode(int data);
//递归插入函数,采用排序二叉树的方法插入(每个节点的左子树元素小于节点元素,右子树元素大于节点元素)
//这种创建方法的中序遍历就是排序后的结果。
void insert(Node *root,int value);
//查询函数
Node *search(Node *root,int data) const;
//删除函数
void delet(Node *root,int data);
//三种递归遍历函数
void prePrint(Node *root) const ;
void midPrint(Node *root) const ;
void tailPrint(Node *root) const ;
//递归获取节点数、树高、
int getCount(Node *root) const ;
int getHight(Node *root) const ;
//递归获取第k层树高
int getLevelCount(Node *root,unsigned int k) const ;
//求叶子数
int getLeafCount(Node *root) const ;
//镜像翻转函数
Node *mirroTree(Node *root);
//释放内存
void freeTree(Node *root);
Node * root;
queue<Node *> q;//此队列用于层序遍历和判断是否为完全二叉树
};
//释放内存
void Btree::freeTree(Node *root)
{
if(NULL == root)return;
freeTree(root->left);
freeTree(root->right);
delete root;
}
//新建节点
Node * Btree::createNode(int data)
{
Node *newnode = new(Node);
newnode->left = NULL;
newnode->right = NULL;
newnode->data = data;
return newnode;
}
//随机生成树
void Btree::setRandTree(int len)
{
cout << "插入随机数:";
srand((unsigned)time(NULL));
for(int i = 0;i < len; i++)
{
int num = rand()%99 + 1;
cout << num << " ";
insert(num);
}
cout << endl;
}
//插入接口
void Btree::insert(int data)
{
if(NULL == root) //空树插入在根节点
{
root = createNode(data);
return;
}
insert(root,data);
}
//递归插入
void Btree::insert(Node *root,int data)
{
if(NULL == root)
{
return;
}
if(NULL == root->left && data < root->data)
{
root->left = createNode(data);
root->left->data = data;
return;
}
if(NULL == root->right && data >= root->data)
{
root->right = createNode(data);
root->right->data = data;
return;
}
if(data < root->data)
{
insert(root->left,data);
}
else
{
insert(root->right,data);
}
}
//按值查找
Node *Btree::search(Node *root,int data) const
{
if(NULL == root)return NULL; //危险做法,如果在外部直接调用其返回结构体的内部成员会出现段错误
if(data == root->data) return root;
return data > root->data ? search(root->right,data) : search (root->left,data);
}
//按值删除
void Btree::delet(Node *root,int data)
{
Node *temp = search(root,data);
if(temp == NULL)
{
cout << "cannt find value!\n";
}
else
{
if(NULL == temp->left && NULL == temp->right)
{
delete temp;
}
if(NULL == temp->right) //右子树为空,左孩子替换根节点
{
Node *p = temp->left;
temp->data = p->data;
temp->left = p->left;
delete p;
}
else if(NULL == temp->left) //左子树为空,右孩子替换
{
Node *p = temp->right;
temp->data = p->data;
temp->right = p->right;
delete p;
}
else //左右子树都不为空,用右子树中最小的元素替换(也可以用左子树最大元素替换)
{
Node *min = temp->right;
while(min->left) //此插入法右子树最小元素一定是最左下方的一个
{
min = min->left;
}
temp->data = min->data; //将最小的元素数据赋给该节点
if(min == temp->right) //右子树最小为右孩子
{
temp->right = min->right;
}
else
{
if(NULL != min->right)
{
Node *p = min->right;
min = min->right; //由其右子树顶替最小位置
delete p;
}
}
delete min;
}
}
}
//前序遍历
void Btree::prePrint(Node *root) const
{
if(NULL == root)return;
cout << root->data << " ";
prePrint(root->left);
prePrint(root->right);
}
//中序遍历
void Btree::midPrint(Node *root) const
{
if(NULL == root)return;
midPrint(root->left);
cout << root->data << " ";
midPrint(root->right);
}
//后序遍历
void Btree::tailPrint(Node *root) const
{
if(NULL == root)return;
tailPrint(root->left);
tailPrint(root->right);
cout << root->data << " ";
}
//层序遍历
void Btree::levelPrint()
{
cout << "层序遍历:";
if(NULL == root)return;
q.push(root);
while(1)
{
int count = q.size();
if(count == 0)break;
while(count--)
{
Node * temp = q.front();
q.pop();
cout << temp->data << " ";
if(NULL != temp->left)q.push(temp->left);
if(NULL != temp->right)q.push(temp->right);
}
}
cout << endl;
}
//获取节点数
int Btree::getCount(Node *root) const
{
if(NULL == root)return 0;
return 1 + getCount(root->left) + getCount(root->right);
}
//获取层高
int Btree::getHight(Node *root) const
{
if(NULL == root)return 0; //空树0层
int lefthight = getHight(root->left);
int righthight = getHight(root->right);
return lefthight > righthight ? lefthight + 1 : righthight + 1;
}
//求level层节点数
int Btree::getLevelCount(Node *root,unsigned int level) const
{
if(NULL == root || level)return 0; //空树,level为0无节点
if(level == 1)return 1; //一层一个根节点
int leftcount = getLevelCount(root->left,level - 1); //递归遍历左右子树,直到其遍历到指定层,返回1
int rightcount = getLevelCount(root->right,level - 1);
return leftcount + rightcount;
}
//求叶子数
int Btree::getLeafCount(Node *root) const
{
if(NULL == root)return 0;//空树无叶
if(NULL == root->left && NULL == root->right)return 1;//叶子节点判断条件
int leftcount = getLeafCount(root->left); //非叶子节点递归求其左右子树叶子数
int rightcount = getLeafCount(root->right);
return leftcount + rightcount;
}
//镜像翻转
Node * Btree::mirroTree(Node *root)
{
if(NULL == root)return NULL;
Node *leftNode = mirroTree(root->left);
Node *rightNode = mirroTree(root->right);
root->left = rightNode;
root->right = leftNode;
return root;
}
//判断结构相似树
bool Btree::isStructCmp(Node *root1,Node *root2) const
{
if(root1 == NULL && root2 == NULL)
{
return 1;
}
else if(root1 == NULL || root2 == NULL)
{
return 0;
}
int leftcmp = isStructCmp(root1->left,root2->left);
int rightcmp = isStructCmp(root1->right,root2->right);
return leftcmp && rightcmp;
}
//判断是否为完全二叉树
bool Btree::isCompleteTree()
{
if(root == NULL)return 0;
q.push(root); //根节点入队列
int leaf = 0; //叶子结点标志位
while(q.size() != 0) //队列结束条件
{
Node *temp = q.front(); //弹出队列里的根节点
q.pop();
if(leaf == 0) //已经出现叶子结点
{
if(temp->left != NULL || temp->right != NULL)
{
return 0;
break;
}
if(temp->left != NULL && temp->right != NULL)
{
q.push(temp->left);
q.push(temp->right);
}
else if(temp->left != NULL && temp->right == NULL)
{
leaf = 1;
q.push(temp->left);
}
else if(temp->left == NULL && temp->right != NULL)
{
return 0;
break;
}
}
}
return 1;
}
int main()
{
Btree bt;
bt.setRandTree(10);
cout << "插入35~39\n";
for(int i = 35; i < 40; i++) bt.insert(i);
if(Node *node = bt.search(35))
{
cout << "search(6)返回指针读出的数据:" << node->data << endl;
}
bt.prePrint();
bt.midPrint();
bt.tailPrint();
bt.levelPrint();
cout << "删除37后:\n";
bt.delet(37);
bt.levelPrint();
#if 1
bt.showCount();
bt.showHigh();
bt.getLevelCount(3);
bt.mirroTree();
bt.levelPrint();
Btree bt1;
bt1.setRandTree(10);
//由于两个树随机生成,极大概率非完全二叉树和结构不同
bt.showStructCmp(bt1.getRoot());
bt.showStructCmp(bt.getRoot());//跟自己的结构比较结果相同
bt.showCompleteTree();
#endif
}
运行结果:
插入随机数:43 88 85 95 8 60 37 53 72 25
插入35~39
search(6)返回指针读出的数据:35
前序遍历:43 8 37 25 35 36 37 38 39 88 85 60 53 72 95
中序遍历:8 25 35 36 37 37 38 39 43 53 60 72 85 88 95
后序遍历:36 35 25 39 38 37 37 8 53 72 60 85 95 88 43
层序遍历:43 8 88 37 85 95 25 37 60 35 38 53 72 36 39
删除37后:
层序遍历:43 8 88 37 85 95 25 38 60 35 39 53 72 36
节点数为:14
树 高 为:6
层序遍历:43 88 8 95 85 37 60 38 25 72 53 39 35 36
插入随机数:43 88 85 95 8 60 37 53 72 25
结构不同
结构相似
非完全二叉树