树:
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; }