数据结构 | C++ |二叉树的链式操作
算法理解
前序中序和后序的区别在于:
前序(根-左-右)
中序(左-根-右)
后序(左-右-根)
两种序列构造二叉树的算法
划分集合->找根节点->划分集合......不停循环
注意,划分集合时,至少有一个集合仅包含一个元素做根节点
例:
先序序列 :A B H F D E C K G(根-左-右)
中序序列 :H B D F A E K C G(左-根-右)
①由甲可知 A为根节点
②-①A的左子树集合为{ B H F D}(前),右子树集合为{E C K G}(前)
②-②A的左子树集合为{ H B D F}(中),右子树集合为{E K C G}(中)
③由②可知,A的左子树根节点是B
B的左子树根节点是H,右子树集合为{F D}前序遍历{根 左}
{D F}中序遍历{左 根}
唯一确定:B的右子树根为F,F的左子树叶为D.
④由②可知,{E C K G}前序遍历 {根 右}
{E K C G}中序遍历 {根 右} PS:左集合仅含一个元素E,右集合有三个元素.左集合{E}必定为根
可知A的右子树根节点是E,E的右子树集合为{C K G}前序遍历
{K C G}中序遍历
⑤划分④中E的右子树集合
{C K G}前序遍历(根 左 右)
{K C G}中序遍历(左 根 右)
唯一确定:E的右子树根为C,C的左子树叶为K,右子树叶为G
代码实现
0.BiTree.h 头文件
//节点类
//C++中的class和struct最大的区别是:class默认private继承,struct默认public继承,用struct可少写
//一行"public:"
struct BiNode
{
int data;
BiNode *Lchild;//左子树
BiNode *Rchild;//右子树
};
class BiTree
{
public:
BiTree() { root = NULL; } //无参构造函数
BiTree(vector<int>&pre); //先序序列构造二叉树
BiTree(vector<int>&pre, vector<int>&Mid); //先序,中序构造二叉树
BiTree(BiTree &tree); //复制构造参数
~BiTree(); //析构函数,Free(BiNode *p)的套壳函数
void PreOrder(); //前序遍历的套壳函数
void InOrder();
void PostOrder();
int Count(); //计算结点数
int Height(); //求树高
int CountofLeaf(); //求叶节点个数
BiNode SearchByVal(int e); //按值查找
private:
BiNode *root;
void PreOrder(BiNode *p); //前序遍历
void InOrder(BiNode *p); //中序遍历
void PostOrder(BiNode *p); //后序遍历
void Free(BiNode *p);
BiNode *CreateByPre(vector<int> &pre, int &i); //容器装的是int数据
//先序,中序创建二叉树.不能用数组的引用
BiNode *CreateByPreMid(vector<int> &Pre, vector <int>&Mid, int ipre, int imid, int n);
BiNode *Copy(BiNode *p); //复制构造函数
int Count(BiNode *p); //求结点数
int Height(BiNode *p); //求树高
int CountofLeaf(BiNode *p); //求叶节点个数
BiNode *SearchByVal(BiNode *p, int e); //按值查找
};
1.头文件
//二叉树-链式实现
using namespace std;
#include <iostream>
#include<vector>
#include"BiTree.h"
2.析构函数
void BiTree::Free(BiNode *p)//第一次运行错误原因:忘加"BiTree::"
{
if (p != NULL) //第二次运行显示p是nullptr,修改:if语句从if(p==NULL)反转为if(p!=NULL)
{
Free(p->Lchild);
Free(p->Rchild);
delete p;
}
else
{
return; //void中可以有一个"return;"表示终止
}
}
BiTree::~BiTree()
{
Free(root);
}
3.三种遍历
void BiTree::PreOrder(BiNode *root)
{
if (root == NULL) { return; }
cout << root->data<<"\t"; //输出根的值
PreOrder(root->Lchild);
PreOrder(root->Rchild);
}
void BiTree::PreOrder()
{
PreOrder(root);
/*main()函数调用公有函数,公有函数调用私有数据成员*root和私有函数,私有函数完成操作*/
}
//中序遍历
void BiTree::InOrder(BiNode *root)
{
if (root == NULL) { return; }
InOrder(root->Lchild);
cout << root->data << "\t"; //输出根的值
InOrder(root->Rchild);
}
void BiTree::InOrder()
{
InOrder(root);
}
//后序遍历
void BiTree::PostOrder(BiNode *root)
{
if (root == NULL) { return; }
PostOrder(root->Lchild);
PostOrder(root->Rchild);
cout << root->data << "\t"; //输出根的值
}
void BiTree::PostOrder()
{
PostOrder(root);
}
4.独序构造(前)
BiNode *BiTree::CreateByPre(vector<int> &pre, int &i)
{
int e = pre[i]; i++;//e接收来自容器的每个值
if (e <0){return NULL;}//负数表示无子树
BiNode *p = new BiNode;
p->data = e;
p->Lchild = CreateByPre(pre, i);
p->Rchild = CreateByPre(pre, i);
return p;
}
BiTree::BiTree(vector<int>&pre)
{
int i = 0;
root = CreateByPre(pre, i);
}
5.双序构造(前,中)
BiNode *BiTree::CreateByPreMid(vector<int> &Pre, vector<int>&Mid,int ipre,int imid,int n)
{
int i;
if (n == 0) { return NULL; }//误写成n=0;低级错误
BiNode *p = new BiNode;
p->data = Pre[ipre];
for (i = 0; i < n; i++)
{
if (Pre[ipre] == Mid[imid + i])
break;
}
p->Lchild = CreateByPreMid(Pre, Mid, ipre + 1, imid, i);//每次递归先序序列后移一位
p->Rchild = CreateByPreMid(Pre, Mid, ipre + i + 1, imid + i + 1, n - i - 1);
return p;
/*两个向量形参是引用参数,这两个向量中是因递归而不断被分割的,形参n因递归而不断变短
比如:
前序:A B H F D E C K G(9个)
中序:H B D F A E K C G(9个)
第一层递归,寻找到root节点A
{
左子树:前序:B H F D(4个)
中序:H B D F(4个)
{
第二层递归,寻找到root节点B
{
左子树:前序:H(1个)
中序:H(1个)
第三层递归,寻找到root节点H
{
左子树:NULL
右子树:NULL
}
}
{
右子树:前序:F D(2个)
中序:D F(2个)
第三层递归,寻找到root节点F
{
左子树:D(1个)
右子树:NULL
}
}
}
{
右子树:前序:E C K G(4个)
中序:E K C G(4个)
第二层递归,找到root节点E
{
左子树:NULL
右子树:前序:C K G
中序:K C G
第三层递归,找到root节点C
{
左子树:前序:K
中序:K
右子树:前序:G
中序:G
}
}
}
*/
}
BiTree::BiTree(vector<int>&pre, vector<int>&mid)
{
int n = pre.size();
root = CreateByPreMid(pre, mid, 0, 0, n);
}
6.复制构造函数
BiNode *BiTree::Copy(BiNode *p)
{
if (p == NULL) { return NULL; }//形参p将会是待复制二叉树的root结点,如果原二叉树是空树,复制后也是空树
BiNode *q = new BiNode;
q->data = p->data;
q->Lchild = Copy(p->Lchild);
q->Rchild = Copy(p->Rchild);
return q;
}
BiTree::BiTree(BiTree &tree)
{
root = Copy(tree.root);
}
7.计算节点数
我现在不清楚I和r接收的值是怎么来的.
int BiTree::Count(BiNode *p)
{
if (p == NULL) { return 0; }
int l = Count(p->Lchild);
int r = Count(p->Rchild);
return l + r + 1;
}
int BiTree::Count()
{
return Count(root);
}
8.计算树高
int BiTree::Height(BiNode *p)
{
if (p == NULL) { return 0; }
int l =Height(p->Lchild);
int r = Height(p->Rchild);
return (l>r?l:r) + 1;
}
int BiTree::Height()
{
return Height(root);
}
9.计算叶节点
int BiTree::CountofLeaf(BiNode *p)
{
if (p==NULL) { return 0; }
if (p->Lchild == NULL && p->Rchild == NULL) { return 1;}
int l = CountofLeaf(p->Lchild);
int r = CountofLeaf(p->Rchild);
return l + r;
}
int BiTree::CountofLeaf()
{
return CountofLeaf(root);
10.按值查找结点
BiNode *BiTree::SearchByVal(BiNode *p,int e)
{
if (p == NULL) { return NULL; }//修改前:{cout<<"是空树";}错误:即使存在结点也会输出"是空树"
if (p->data == e) { cout << "找到该值"; return p; }//修改前:cout << "树中存在结点:" << p->data << endl;错误:显示出现了p是nullptr
BiNode *q = SearchByVal(p->Lchild, e);
if (q != NULL)
return q;
return SearchByVal(p->Rchild, e);//返回值类型是BiNode类的指针
}
BiNode BiTree::SearchByVal(int e)
{
return *SearchByVal(root, e); //返回值类型是BiNode类,所以在main()测试时要写成int e; cin >> e;
//cout << a1.SearchByVal(e).data << endl;
//cout不能直接打印一个类,但可以通过.引用符打印每个数据成员
}
11.main()函数
int main()
{
vector<int> a = { 1,2,-1,-1,3,-1,-1 };
//遍历测试
BiTree a1(a);
a1.PreOrder(); cout << endl;
a1.InOrder(); cout << endl;
a1.PostOrder(); cout << endl;
//树高函数测试
cout << "树高为:" << a1.Height() << endl;
//结点个数函数测试
cout << "该树结点个数为:" << a1.Count()<<endl;
//按值搜索函数测试
cout << "输入待搜索的值";
int e; cin >> e;
cout<<a1.SearchByVal(e).data<<endl;
//-------------------------------------------------------------------------------------------------
//双序构造测试
vector<int>pre = {1,2,3,4,5};
vector<int>mid = {3,2,4,1,5};
BiTree b1(pre, mid);
//遍历测试
b1.PreOrder(); cout << endl;
b1.InOrder(); cout << endl;
b1.PostOrder(); cout << endl;
//树高函数测试
cout << "树高为:" << b1.Height() << endl;
//结点个数函数测试
cout << "该树结点个数为:" << b1.Count()<<endl;
//按值搜索函数测试
cout << "输入待搜索的值";
int e; cin >> e;
cout<<b1.SearchByVal(e).data<<endl;
system("pause");
return 0;
}

浙公网安备 33010602011771号