树的基本结构,以及利用链表实现树的各项操作(创建、添加/删除/打印树节点、销毁等等)
2018-01-26 20:04
1096 查看
树:
n个结点的有限集合,n = 0时称为空树。在非空树中,有且仅有一个根结点(root),根的子树互不相交。
单个树节点的度:其所拥有的子结点的数目。
树的度:其内所有子结点的度的最大值。
内部结点:除了根结点之外的分支结构。
叶结点:度为0的结点。
结点间的关系:
孩子(儿子):一个结点的直接后继称为该结点的孩子结点。该结点称为孩子结点的双亲结点。
子孙(孙子):一个结点的孩子的孩子。给结点称为子孙的祖先。
兄弟:同一个双亲的孩子结点之前互称兄弟。
堂兄弟: 双亲在同一层的结点互为堂兄弟。
结点的层次:
根结点:第一层。
根结点的孩子:第二层。
依次往下延伸
树的深度:树中结点的最大层次称为树的深度。
树的实例代码
#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_ERRO
4000
R;
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;
}
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_ERRO
4000
R;
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; }
相关文章推荐
- c++之链表篇1:单向链表的创建,打印,删除,插入,销毁等基本操作
- java实现创建链表以及插入节点,查找结点,删除节点等操作
- Zookeeper客户端基本操作java实现——创建连接、创建节点、添加修改节点内容、获取子节点、获取节点数据、删除节点
- C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表)
- 关于链表结构的基本操作 c 实现 (创建,插入删除,反转,合并链表,查找,是否有环,链表相交情况)
- 带头节点链表的操作(链表的创建、删除、查找、逆转、打印等等)
- 数据结构(第二天)单链表的基本操作,创建单链表,头插法,尾插法,删除节点,查询节点
- 链表(1)基本操作:创建,插入,删除,销毁等(模板类实现)
- C语言实现单链表(带头结点)的基本操作(创建,头插法,尾插法,删除结点,打印链表)
- 设计一个整型链表类list,能够实现链表节点的插入、删除、以及链表数据的输出操作。
- 线性表的链式存储格式基本操作:创建链表、插入、删除、查找、求表长、打印链表
- c语言链表基本操作(带有创建链表 删除 打印 插入)
- 这是一个关于XML文档的操作管理器XMLHelper类,类中包括XML文档的创建,文档节点和属性的读取,添加,修改,删除的方法功能的实现
- 链表的基本操作(创建,查找指定位置元素,删除指定元素,插入,倒置,去重,求集合的差,分别交换结点与交换结点值实现的冒泡排序,将两个有序链表合并成一个有序链表)c语言实现
- 学习笔记——C语言实现单链表的基本操作:创建、输出、插入结点、删除结点、逆序链表
- 数据结构——单链表的创建、删除、遍历以及节点的插入、删除等操作
- C语言实现链表的创建、增加、删除、查询、逆序、清空等基本操作
- java语言编写链表的基本操作(链表的创建,插入,删除,打印,排序)
- 链表的java实现以及基本的增加,删除,排序操作
- 链表(二)——单向链表的基本操作(创建、删除、打印、结点个数统计)