树的基本结构,以及利用链表实现树的各项操作(创建、添加/删除/打印树节点、销毁等等)

树:

n个结点的有限集合,n = 0时称为空树。在非空树中,有且仅有一个根结点(root),根的子树互不相交。

单个树节点的度:其所拥有的子结点的数目。

树的度:其内所有子结点的度的最大值。

内部结点:除了根结点之外的分支结构。

叶结点:度为0的结点。



结点间的关系:

孩子(儿子):一个结点的直接后继称为该结点的孩子结点。该结点称为孩子结点的双亲结点。

子孙(孙子):一个结点的孩子的孩子。给结点称为子孙的祖先。

兄弟:同一个双亲的孩子结点之前互称兄弟。

堂兄弟: 双亲在同一层的结点互为堂兄弟。


结点的层次:

根结点:第一层。

根结点的孩子:第二层。

依次往下延伸


树的深度:树中结点的最大层次称为树的深度。



树的实例代码

树的头文件
#ifndef __TREE_H__
#define __TREE_H__

#include "error.h"

struct _treeNode;//为下面孩子结点类型直接用树结点指针做声明


//孩子结点链表的类型(存放孩子地址的结构体)
typedef struct _childNode
{
	struct _treeNode *childNode;//指向孩子
	struct _childNode *next;//指向下一个存放孩子结点地址的结构体
}ChildNode;



//树节点类型
typedef char TreeData;
typedef struct _treeNode
{
	TreeData data;//具体数据
	struct _treeNode *parent;//指向父亲
	struct _treeNode *next;  //指向下个树节点(PS:树内的所有结点都是用链表连起来)
	struct _childNode *childList;//指向孩子链表的头结点
	int degree;//结点的度
}TreeNode;


//树
typedef struct _tree
{
	struct _treeNode *head;//指向树链表的头结点(头结点指向树中的结点)
	int len;//树的结点个数
}Tree;

//定义一个函数指针类型
typedef void (*TreePrint)(TreeNode* node);

Tree* Create_Tree();

//添加树节点
int Insert_Tree(Tree*tree, TreeData data, int pos);
/*
pos代表要插入结点父亲结点的位置
约定:
1 新插入的结点插入在当前父亲结点所有孩子的右边
2 根结点的位置是 0
*/

//打印树节点
void Display(Tree*tree, TreePrint pFunc);

//删除树节点
int Delete(Tree*tree, int pos, TreeData *x);

//获取树节点数据
int Tree_Get(Tree*tree, int pos, TreeData *x);

//清空树节点
int Tree_Clear(Tree*tree);

//销毁树
void Tree_Destory(Tree*tree);

//获取树的根结点地址
TreeNode* Tree_Root(Tree* tree);

//树结点总数
int Tree_Count(Tree* tree);

//树高
int Tree_Height(Tree* tree);

//树的度(最大的度)
int Tree_Degree(Tree* tree);

#endif// __TREE_H__

编程实现对树的操作

#include "tree.h"
#include <stdlib.h>

Tree* Create_Tree()
{
	//创建树
	Tree* tree = (Tree*)malloc(sizeof(Tree)/sizeof(char));
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return NULL;
	}
	
	//给树节点链表创建头结点(不在树内)
	tree->head = (TreeNode*)malloc(sizeof(TreeNode)/sizeof(char));
	if (NULL == tree->head)
	{
		errno = MALLOC_ERROR;
		free(tree);//防止内存泄漏,头结点创建失败不能使用树需要释放之前创建的树
		return NULL;
	}
	//tree->head为树的头结点指针,指向类型为树节点的类型
	tree->head->parent    = NULL;//无需使用头结点内的parent,置空
	tree->head->childList = NULL;//无需使用头结点内的childList,置空
	tree->head->next      = NULL;//表示树内没有结点
	
	tree->len = 0;//空树情况下,树节点为0
	//printf("ok");
	return tree;
}



//添加树节点
int Insert_Tree(Tree*tree, TreeData data, int pos)
{
	if (NULL == tree || pos < 0 || pos > tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	
	if (pos != 0 && tree->len == pos)
	{
		errno = ERROR;
		return FALSE;
	}
	//一 创建新的树节点(结点内有5要素)
	TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)/sizeof(char));
	if (NULL == node)
	{
		errno = MALLOC_ERROR;
		return FALSE;
	}
	//1)新添结点的数据
	node->data = data;
	//2)新结点内next的指向
	node->next = NULL;//新结点放末尾;
	
	//3)创建新结点的孩子结点链表的头结点
	node->childList = (ChildNode*)malloc(sizeof(ChildNode)/sizeof(char));
	if (NULL == node->childList)
	{
		errno = MALLOC_ERROR;
		free(node);
		return FALSE;
	}
	node->childList->next = NULL;
	node->childList->childNode = NULL;//子链表头结点不需要用到孩子
	
	//4)度
	node->degree = 0;
	
	//5)/二 找父结点
	int i;
	TreeNode* parent = tree->head->next;//指向当前树内的第一个结点
	for (i = 0; i < pos; i++)
	{
		parent = parent->next;//parent->next指向紧跟着当前树节点(parent的指向结点)的结点
	}
	node->parent = parent;//parent存着父结点的地址
	
	//三 父结点的孩子链表中加入一个结点
	if (NULL != parent)
	{
		//新建一个孩子结点
		ChildNode* childnode = (ChildNode*)malloc(sizeof(ChildNode)/sizeof(char));
		if (NULL == childnode)
		{
			errno = MALLOC_ERROR;
			free(node->childList);//释放子链表头结点
			free(node);//释放新建的树节点
			return FALSE;
		}
		childnode->childNode = node;
		childnode->next = NULL;//新建子结点放子链表最后
		
		//插入到子链表中
		ChildNode* tmp = parent->childList;//子链表的头结点
		while (tmp->next)
		{
			tmp = tmp->next;
		}//最后指向原先最后一个子结点
		tmp->next = childnode;
		parent->degree += 1;//父的度加1
	}
	
	//四 新建树节点插到树链表的末尾
	TreeNode* tmp = tree->head;
	while (tmp->next)
	{
    	tmp = tmp->next;
	}
	
	tmp->next = node;
	tree->len += 1;
	
	return TRUE;
}


//递归打印结点
void r_display(TreeNode* node, int gap, TreePrint pFunc)//gap为父子结点之间的间距
{
	if (NULL == node)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	//打印距离前一个结点的距离
	int i;
	for (i = 0; i < gap; i++)
	{
		putchar('-');
	}
	
	//printf("%c\n", node->data);
	
	pFunc (node);
	
	ChildNode* child = node->childList->next;//指向子链表的第一个结点
	
	//打印该结点的孩子
	while(child)
	{
		r_display(child->childNode, gap+4, pFunc);
		child = child->next;
	}
	return;
}


//显示
void Display(Tree*tree, TreePrint pFunc)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	r_display(tree->head->next, 0, pFunc);//调用递归打印
}
 

 //递归删除结点
 void r_delete(Tree *tree, TreeNode *node)
 {
	 if (NULL == tree || NULL == node)
		 return;
	 //一 从树链表里移除这个结点,需找到该结点的前一个结点
	 TreeNode* tmp = tree->head;
	 while (tmp->next)
	 {
		 if (tmp->next == node)//tmp指向结点的下一个结点是要删的结点
		 {
			 tmp->next = node->next;//让tmp指向结点跳过要删结点,指向下下个结点
			 tree->len --;
			 break;
		 }
		 tmp = tmp->next;
	 }
	 
	 //二 将其兄弟链表中(其父亲的子链表)指向他的结点删除
	 TreeNode* parent = node->parent;//新建指针parent指向要删结点的父亲
	
     if (NULL != parent)//有父情况
	 {
		 ChildNode* tmp = parent->childList;//tmp指向兄弟链表的头结点
		 while (tmp->next)
		 {
			 if (tmp->next->childNode == node)//tmp->next->childNode为兄弟链表中指向孩子本身的指针
			 {
				 ChildNode* p = tmp->next;//将子链表中指代表要删结点的结点地址给p
				 tmp->next = p->next;//跳过子链表中指代表要删结点的结点,连接后面的
				 free(p);
				 parent->degree--;//父结点的度-1;
				 break;
			 }
			 tmp = tmp->next;
		 }
	 }
	 
	 //三 将要删结点的子节点删了
	 ChildNode* child = node->childList->next;//要删结点的子链表里的第一个结点
	 while (child)
	 {
		 ChildNode* pchild = child->next;//保存子链表的结点地址
		 r_delete(tree, child->childNode);
		 child = pchild;
	 }
	 
	 free (node->childList);//释放子链表头结点
	 free (node);//释放之前开辟要删结点的空间
 }
 
 
 
//删结点 
int Delete(Tree*tree, int pos, TreeData *x)
{
	if (NULL == tree || pos < 0 || pos > tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	
	if (pos != 0 && tree->len == pos)
	{
		errno = ERROR;
		return FALSE;
	}
	
	//找结点
	int i;
	TreeNode* current = tree->head->next;//指向当前树内的第一个结点
	for (i = 0; i < pos; i++)
	{
		current = current->next;//最后current指向要找结点
	}
	*x = current->data;
	
	r_delete(tree, current);
	
	return TRUE;
}



int Tree_Get(Tree*tree, int pos, TreeData *x)
{
	if (NULL == tree || pos < 0 || pos > tree->len)
	{
		errno = ERROR;
		return FALSE;
	}
	
	if (pos != 0 && tree->len == pos)
	{
		errno = ERROR;
		return FALSE;
	}
	
	//找结点
	int i;
	TreeNode* current = tree->head->next;//指向当前树内的第一个结点
	for (i = 0; i < pos; i++)
	{
		current = current->next;//最后current指向要找结点
	}
	*x = current->data;
	
	return TRUE;
}


//清空树节点
int Tree_Clear(Tree*tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	TreeData x;
	return Delete(tree, 0, &x);//删除根结点就完事了
}


//销毁树
void Tree_Destory(Tree*tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	Tree_Clear(tree);//清空树节点
	free (tree->head);//释放树的头结点
	free (tree);//释放树的结构体空间
}


//获取树的根结点地址
TreeNode* Tree_Root(Tree* tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	return tree->head->next;
}



//树结点总数
int Tree_Count(Tree* tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	return tree->len;
}


//算树高
int r_height(TreeNode* node)
{
	if (NULL == node)
		return 0;
	
	int subHeight = 0;
	int max = 0;
	//如果有子结点
	ChildNode* child = node->childList->next;
	while (child)
	{
		subHeight = r_height(child->childNode);
		if (subHeight > max)//选取最高的子结点长度
			max = subHeight;
		
		child = child->next;
	}
	
	return max + 1; //max从0开始需+1
}

//树高
int Tree_Height(Tree* tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	int height = r_height(tree->head->next);
	
	return height;
}



//递归算树的度
int r_degree(TreeNode* node)
{
	if (NULL == node)
		return 0;
	int max = node->degree;//先假设根结点的度为最大
	int subDegree = 0;
	//如果有子结点
	ChildNode* child = node->childList->next;
	while (child)
	{
		subDegree = r_height(child->childNode);
		if (subDegree > max)//选取度最大的子结点的度
			max = subDegree;
		
		child = child->next;
	}
	
	return max;
}



//树的度(最大的度)
int Tree_Degree(Tree* tree)
{
	if (NULL == tree)
	{
		errno = MALLOC_ERROR;
		return;
	}
	
	int degree = r_degree(tree->head->next);
	
	return degree;
}

主函数,实践调试操作

#include <stdio.h>
#include "tree.h"

void printA(TreeNode* node)
{
	printf("%c\n", node->data);
}

int main()
{
	Tree *tree = Create_Tree();
	if (tree == NULL)
	{
		myError("Create_Tree");
		return -1;
	}
	//printf("ok");
	Insert_Tree(tree, 'A', 0);
	Insert_Tree(tree, 'B', 0);
	Insert_Tree(tree, 'C', 0);
	Insert_Tree(tree, 'D', 0);
	Insert_Tree(tree, 'E', 1);
	Insert_Tree(tree, 'F', 1);
	Insert_Tree(tree, 'H', 3);
	Insert_Tree(tree, 'I', 3);
	Insert_Tree(tree, 'J', 3);
	Insert_Tree(tree, 'Z', 0);
	Insert_Tree(tree, 'O', 9);
	//Insert_Tree(tree, 'U', 8);加上后树高为4
	//printf("ok");
	
	Display(tree, printA);
	/*
	printf ("删除B\n");
	TreeData x;
	Delete(tree, 1, &x);
	Display(tree, printA);
    */
	
	TreeData x;
	printf ("height = %d\n", Tree_Height(tree));
	printf ("degree = %d\n", Tree_Degree(tree));

	return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值