首页 > 编程语言 >树的双亲表示法与孩子表示法(C++源码)

树的双亲表示法与孩子表示法(C++源码)

时间:2024-11-26 13:58:11浏览次数:8  
标签:arr MyTree int void C++ 表示法 源码 data 节点

目录

一、双亲表示法:

二、孩子表示法:


一、双亲表示法:

#include<iostream>
using namespace std;
#define MAX_TREE_SIZE 100
template <typename DataType>
struct PNode
{
	DataType data;
	int parent;
};






//树的存储结构:双亲表示法

template <typename DataType>
class MyTree
{
	public:
		MyTree();
		~MyTree();
		PNode<DataType>* AddTreeNode(DataType data,int parent);
		void Insert(DataType data,int parent);
		void GetDepth();
		void PrintTree();
		
    private:
	    PNode<DataType> *arr[MAX_TREE_SIZE];
	    int num;//记录节点个数 
	    int depth;//记录深度 
};



template <typename DataType>
MyTree<DataType>::MyTree()
{
	num=0,depth=0;
	for(int i=0;i<MAX_TREE_SIZE;i++)
	{
		arr[i]=nullptr; 
	}
}

template <typename DataType>  
MyTree<DataType>::~MyTree()  
{  
    for (int i = 0; i < num; i++)  
    {  
        delete arr[i];  
    }  
}  


template <typename DataType>//创建节点 
PNode<DataType>* MyTree<DataType>::AddTreeNode(DataType data,int parent)
{
	PNode<DataType> *s=new PNode<DataType>;
	s->data=data;
	s->parent=parent;
	return s;
}

template <typename DataType>
void MyTree<DataType>::Insert(DataType data,int parent)
{
	arr[num]=AddTreeNode(data,parent);
	num++;
}



template <typename DataType>
void MyTree<DataType>::GetDepth()
{
    int dep;
    for (int i = 0; i <num; i++) 
	{
        dep = 0;
        for (int j = i; j >= 0; j = arr[j]->parent)
        {
        	dep++;
		}
        if (dep >depth)
		depth = dep;
    }
 } 


template <typename DataType>
void MyTree<DataType>::PrintTree()
{
//	int num1=num;//结点个数控制输出完所有结点 
//	int i=0;//顺序打印 
//	int count=1;//记录外层循环次数 
//	while(num1--)
//	{
//		printf("第%d层:",count);
//		cout<<arr[i]->data <<","<<arr[i]->parent<<"  " ;
//		while(arr[i+1]!=nullptr&&arr[i]->parent==arr[i+1]->parent)//同父母兄弟同行打印输出 
//		{
//			i++;
//			cout<<arr[i]->data <<","<<arr[i]->parent<<"  " ;
//			num1--;
//		}
//		i++;
//		count++;
//		cout<<endl;
//	}
	GetDepth();
	cout<<"树的深度为:" <<depth<<endl;
	
	
	
	
	
	
	
//第二种打印法 
		for(int i=0;i<num;i++)
		{
			printf("第%d个结点:",i+1);
			cout<<arr[i]->data <<"	"<<"父亲结点为:"<<arr[i]->parent<<endl;
		 } 
}


int main()
{
	MyTree<char> tree1;
	tree1.Insert('A',-1) ;
	tree1.Insert('B',0) ;
	tree1.Insert('C',0) ;
	tree1.Insert('D',1) ;
	tree1.Insert('E',1) ;
	tree1.Insert('F',2) ;
	tree1.PrintTree(); 
	return 0;
}

伪代码说明:

伪代码:
//创建模板类,在私有变量中设置结构体数组,结点个数和深度
//构造函数初始化结构体数组 
//析构函数释放结构体数组
//AddTreeNode函数创建结点,将结点地址返回给Insert函数
//Insert函数接收结点地址并插入至结构体数组,结点数num++
//GetDepth()函数计算树的深度,原理是遍历结点,得出每个结点深度,将最大深度记作树的深度
//最后打印树 

二、孩子表示法:

#include<iostream>
using namespace std;
#define MAX_TREE_SIZE 10




//树的存储结构:孩子表示法 

struct CTNode//孩子结点 
{
	int child;//孩子结点下标 
	CTNode*next;
}; 

template <typename DataType>
struct CBNode//表头结点 
{
	DataType data;
	CTNode*firstchild;//指向孩子链表的头指针 
};



template <typename DataType>
class MyTree
{
	public:
		MyTree();
		~MyTree();
		CBNode<DataType>* AddTreeNode(DataType data);
		void Insert(DataType data,int n);
		void PrintTree();
		void PreOrderTree(int root);
		void BackOrderTree(int root) ;
		void LevelOrderTree();
    private:
	    CBNode<DataType> *arr[MAX_TREE_SIZE];
	    int num;//记录节点个数 
	    int depth;//记录深度 
	    int c;//记录孩子位置 
};

template <typename DataType>
MyTree<DataType>::MyTree()
{
	num=0,depth=1,c=1;
	for(int i=0;i<MAX_TREE_SIZE;i++)
	{
		arr[i]=nullptr; 
	}
}


template <typename DataType>  
MyTree<DataType>::~MyTree()  
{  
    for (int i = 0; i < num; i++)  
    {  
        while(arr[i]->firstchild!=NULL) 
        {
        	CTNode*s =arr[i]->firstchild->next;
        	delete arr[i]->firstchild;
        	arr[i]->firstchild=s;
		}
        delete arr[i];  
    }  
}  


template <typename DataType> 
CBNode<DataType>* MyTree<DataType>::AddTreeNode(DataType data)
{
	CBNode<DataType>*s=new CBNode<DataType>;
	s->data=data;
	s->firstchild=NULL;
	return s;
}



template <typename DataType> 
void MyTree<DataType>::Insert(DataType data,int n)
{
	arr[num]=AddTreeNode(data);
    if(n!=0)
    {
    	
    	CTNode*ptr=arr[num]->firstchild;//移动指针 
    	    CTNode*newnode=new CTNode;
            newnode->child=c;
            c++;
            newnode->next=NULL;//创建孩子结点 
            ptr=arr[num]->firstchild=newnode;//链接到表头结点上 
            n--;

 	    while(n--)
	    {
            CTNode*newnode=new CTNode;
            newnode->child=c;
            c++;
            newnode->next=NULL;//创建孩子结点 
            
            ptr->next=newnode;
            ptr=ptr->next;
     	}
  	depth++; 
	}

	num++;
}



template <typename DataType> 
void MyTree<DataType>::PrintTree()
{
	cout<<"树的深度为:"<<depth<<endl; 
//	int i=1;//下一层结点数
//	int index=0; //记录下标位置 
//	for(int m=0;m<num;m++)
//	{
//		for(int n=0;n<i;n++)//打印层结点数 
//		{
//			cout<<arr[index]->data<<" ";
//			index++;
//		 } 
//		 cout<<endl;
//		 
//		 
//		int c=m;
//		int count=0;
//		int b=i;//上一层结点数 
//		for(int n=0;n<i;n++)//计算下一层结点数 
//		{
//		CTNode*ptr=arr[c]->firstchild;
//        c++;
//		while(ptr!=NULL)
//		{
//			count++;//记录一个结点有几个孩子 
//			ptr=ptr->next;
//		}
//
//		}
//		i+=count; 
//		i=i-b;;//把上一层循环的次数即上一层结点数减去,使i为下一层结点数 	
//	}

	
	
//第二种打印法 
	
	for(int i=0;i<num;i++)
	{
		printf("第%d个结点:",i+1);
		cout<<arr[i]->data <<"	"<<"孩子结点为:";
		CTNode*ptr=arr[i]->firstchild;
		if(ptr==NULL)
		cout<<"NULL"; 
		while(ptr!=NULL)
		{
			cout<<arr[ptr->child]->data<<" "; 
			ptr=ptr->next;
		}
		cout<<endl;
	 } 

}

template <typename DataType> 
void MyTree<DataType>::PreOrderTree(int root)      //递归算法,以Tree[root]为根的子树
{

 if(root>=0 && root<num)
 {
 	//存在该结点
    cout<<arr[root]->data <<" ";


 }   
   CTNode* p=arr[root]->firstchild; //Tree[root]->firstChild
 while(p!=NULL)
 {
 	//依次前序遍历root结点的每一棵子树
    PreOrderTree(p->child); 
   p=p->next;
 } 

}





template <typename DataType> 
void MyTree<DataType>::BackOrderTree(int root) 
{
	CTNode* p=arr[root]->firstchild;
 while(p!=NULL)
 {
    BackOrderTree(p->child); 
         if(p->child>=0 && p->child<num)
  {
 	//存在该结点
    cout<<arr[p->child]->data <<" ";
  }  
   p=p->next;

 } 
 if(root==0)
 {
 	cout<<arr[root]->data <<" ";
 }

}


template <typename DataType> 
void MyTree<DataType>::LevelOrderTree()
{
	cout<<arr[0]->data <<" ";
 for(int i=0;i<num;i++)
 {
 
 	CTNode*ptr=arr[i]->firstchild;
 	while(ptr!=NULL)
 	{
 		cout<<arr[ptr->child]->data<<" ";
 		ptr=ptr->next;
	 }
 }

}


int main()
{
	MyTree<char> Tree2;
	Tree2.Insert('A',2) ;
	Tree2.Insert('B',3) ;
	Tree2.Insert('C',0) ;
	Tree2.Insert('D',1) ;
	Tree2.Insert('E',0) ;
	Tree2.Insert('F',0) ;
	Tree2.Insert('G',0) ;
    //Tree2.PreOrderTree(0);
    //Tree2.BackOrderTree(0);
    //Tree2.LevelOrderTree();
	Tree2.PrintTree() ;
	return 0;
}

伪代码说明:

伪代码:
//定义树的最大节点数 MAX_TREE_SIZE 为 10  
//  
//定义孩子节点结构 CTNode:  
//    包含整数 child,表示孩子节点的下标  
//    包含指向下一个 CTNode 的指针 next  
//  
//定义表头节点结构 CBNode<DataType>:  
//    包含数据类型 DataType 的数据  
//    包含指向孩子链表头指针的 CTNode* firstchild  
//  
//定义模板类 MyTree<DataType>:  
//    包含以下成员变量:  
//        CBNode<DataType>* 数组 arr[MAX_TREE_SIZE],用于存储树的节点  
//        整数 num,记录当前节点数  
//        整数 depth,记录树的深度  
//        整数 c,用于记录孩子节点的位置(下标)  
//  
//    包含以下成员函数:  
//        构造函数 MyTree()  
//            初始化 num, depth, c,并将 arr 数组的所有元素设置为 nullptr  
//  
//        析构函数 ~MyTree()  
//            遍历 arr 数组,释放每个节点及其孩子链表所占用的内存  
//  
//        CBNode<DataType>* AddTreeNode(DataType data)  
//            创建一个新的 CBNode<DataType> 节点,设置其数据为 data,firstchild 设置为 nullptr,并返回该节点  
//  
//        void Insert(DataType data, int n)  
//            在树中添加一个新节点,数据为 data,n 表示该节点的父节点下标(若为 0 则表示该节点为根节点)  
//            创建新节点并添加到 arr 数组中  
//            若 n 不为 0,则创建孩子链表,并将新节点链接到其父节点的 firstchild 链表上  
//            增加 num 和 depth(若添加了新层级的节点)  
//  
//        void PrintTree()  
//            打印树的结构,包括每个节点的数据和孩子节点  
//            遍历 arr 数组,对于每个节点,打印其数据,然后遍历其孩子链表,打印孩子节点的数据  
//  
//        void PreOrderTree(int root)  
//            递归地前序遍历以 root 为根的子树  
//            若 root 节点存在,则先打印 root 节点,然后遍历其孩子链表,对每个孩子节点递归调用 PreOrderTree  
//  
//        void BackOrderTree(int root)  
//            递归地后序遍历以 root 为根的子树  
//            遍历 root 节点的孩子链表,对每个孩子节点递归调用 BackOrderTree,然后打印 root 节点  
//            注意:这里的后序遍历实现有误,因为打印 root 节点的逻辑应该放在递归调用之后,并且应该在确认孩子节点存在时才递归  
//  
//        void LevelOrderTree()  
//            按层级顺序打印树的所有节点  
//            首先打印根节点,然后遍历 arr 数组,对每个节点的孩子链表进行遍历,打印孩子节点的数据  
//			
//		int main() 
//			调用函数调试 

标签:arr,MyTree,int,void,C++,表示法,源码,data,节点
From: https://blog.csdn.net/2301_79139273/article/details/144057197

相关文章

  • 2025最新在线客服源码-即时通讯实时消息-企业级源码-可私有部署定制开发
    本系统采用GolangGin框架+GORM+MySQL+Vue+ElementUI开发的独立高性能在线客服系统。客服系统访客端支持PC端、移动端、小程序、公众号中接入客服,利用超链接、网页内嵌、二维码、定制对接等方式让网上所有通道都可以快速通过本系统联系到商家。服务端可编译为二进制程序包,无需搭......
  • 【计算机毕业设计选题推荐】基于SpringBoot的口腔诊所系统的设计与实现 【附源码+数据
    ✍✍计算机编程指导师⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java实战|SpringBoot/SSMPython实战项目|Django微信小程......
  • SpringBoot在线教育系统a1q7y 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:学生,教师,课程信息,在线咨询开题报告内容项目名称:基于SpringBoot的在线教育系统项目编码:a1q7y一、项目背景与意义随着互联网技术的不断发展,在线教......
  • SpringBoot云笔记设计00530 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,文件类型,笔记类型,文件信息,日常笔记开题报告内容题目:基于SpringBoot的云笔记系统设计一、研究背景与意义随着信息技术的飞速发展,个人及企业......
  • 打卡信奥刷题(309)用C++信奥P2614[普及组/提高] 计算器弹琴
    计算器弹琴题目描述总所周知,计算器可以拿来干很多它本不应该干的事情,比如写作文。(参看洛谷P2549)小A发现了一个计算器的另一个隐藏功能——弹琴。http://www.bilibili.com/video/av2205500/如果按上一个键,比如说1,就会发出中音“Do”。这边给出按键音高表+低音Fa<低......
  • SpringBoot园区入住管理系统企业端61zfn 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:企业,项目信息,股东信息,申请入园,答辩ppt,企业信息,政策通知,企业员工,专利证书,软件著作权,商标权,安全生产,展厅信息,展厅预约,月报年报开题报告内容......
  • SpringBoot游戏玩家服务平台94g73 程序+源码+数据库+调试部署+开发环境
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表系统内容:用户,商家,游戏陪玩,陪玩预约,游戏装备,订单信息,账号买卖,账号订单,退订单,评价信息开题报告内容项目名称:SpringBoot游戏玩家服务平台(94g73)一、项目......
  • SpringBoot源码解析(五):准备应用环境
    SpringBoot源码系列文章SpringBoot源码解析(一):SpringApplication构造方法SpringBoot源码解析(二):引导上下文DefaultBootstrapContextSpringBoot源码解析(三):启动开始阶段SpringBoot源码解析(四):解析应用参数argsSpringBoot源码解析(五):准备应用环境目录前言一、......
  • 【人人都能看懂 - 大模型架构篇】旋转位置编码(RoPE)形象理解+源码解析
    【人人都能看懂-大模型架构篇】旋转位置编码(RoPE)形象理解+源码解析重要性:★★★......
  • UINAPP全开源圈子源码分享,二开打造属于自己的圈子系统
    获取免费的圈子源码需要谨慎选择,确保源码的质量、合法性和安全性。在使用前,建议进行详细的代码审查和测试,并根据实际需求进行定制开发。同时,注意遵守开源项目的许可证要求,并确保用户数据的安全性。适用领域:一、行业圈子:让本行业的有交流和联系的圈子。二、地方圈子:在本地区,......