数据结构 | 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;
}

 

posted @ 2019-05-08 16:54  心碎人俱乐部  阅读(15)  评论(0)    收藏  举报