【十九】树以及树的存储结构

来源:互联网 发布:lcd字库生成软件 编辑:程序博客网 时间:2024/06/05 20:42

1、树的定义

这里写图片描述

这里写图片描述

2、相关概念

  • 树的结点包含一个数据及若干指向子树的分支
  • 结点拥有的子树数称为结点的度
    • 度为0的结点称为叶结点
    • 度不为0的结点称为分支结点
  • 树的度定义为所有结点中的度的最大值

这里写图片描述

  • 结点的直接后继称为该结点的孩子
    • 相应的,该结点称为孩子的双亲
  • 结点的孩子的孩子的……称为该结点的子孙
    • 相应的,该结点称为子孙的祖先
  • 同一个双亲的孩子之间互称兄弟

这里写图片描述

  • 结点的层次
    • 根为第1层
    • 根的孩子为第2层
    • ……
  • 树中结点的最大层次称为树的深度或高度

这里写图片描述

  • 如果树中结点的各子树从左向右是有次序的,子树间不能互换位置,则称该树为有序树,否则为无序树。

这里写图片描述

  • 森林是由n (n ≥ 0 ) 棵互不相交的树组成的集合

这里写图片描述

3、小结

这里写图片描述

4、树的存储结构

  • 无法直接用数组表示树的逻辑结构
  • 但可以设计结构体数组对结点间的关系进行表述

例如:

这里写图片描述

5、实现方案

  • 利用链表组织树中的各个结点
  • 链表中的前后关系不代表结点间的逻辑关系
  • 结点的逻辑关系由child数据域描述
  • child数据域保存其他结点的存储地址

数据结构的定义:

对外的数据定义:

//gtree.h//对外的数据封装,增加程序的通用性typedef void GTree;typedef void GTreeData;

内部实现的数据定义:

//gtree.c//树结点定义typedef struct _struct_gtreenode GTreeNode;/*data: 指向树中保存的用户数据地址parent:指向该结点的父结点child:该结点的子结点组织链表*/struct _struct_gtreenode{  GTreeData *data;  GTreeNode *parent;  Linklist *child;};//组织链表结点定义typedef struct _struct_tlnode TLNode;/*listNode: 链表结点,包含指向下一个结点的指针node:保存树结点地址*/struct _struct_tlnode{  LinklistNode listNode;  GTreeNode *node;};

这里写图片描述

这里写图片描述

这里写图片描述

6、部分代码

/*  将结点node插入到GTree中的pos位置处  插入成功,返回1,失败,返回0*/int GTree_Insert(GTree* tree, GTreeData* data, int parentpos){  int iret = 1;  iret = iret && (tree != NULL) && (data != NULL) && (parentpos <= List_Length(tree));  if(iret)  {    GTreeNode *treeNode = (GTreeNode*)malloc(sizeof(GTreeNode));    //创建主组织结点,并插入主组织链表中    TLNode *tlNode = (TLNode*)malloc(sizeof(TLNode));    iret =(treeNode != NULL) && (tlNode != NULL);    if(iret)    {      treeNode->data = data;      treeNode->parent = NULL;//假设当前结点没有父结点也没有子结点      treeNode->child = NULL;      tlNode->node = treeNode;      iret = List_Insert(tree,(LinklistNode*)tlNode,List_Length(tree));      //如果未插入成功,则可释放内存      if(!iret)      {        free(tlNode);      }      //尝试获取当前结点的父结点      TLNode *parentNode = (TLNode*)List_Get(tree,parentpos);      if(parentNode != NULL)      {        //如果有父结点存在,将当前结点,插入父结点的子结点的组织结构链表中        treeNode->parent = parentNode->node;        //如果父结点的组织结构链表为空,则先创建它        if(parentNode->node->child == NULL)        {          parentNode->node->child = List_Create();        }        TLNode *pchildNode = (TLNode*)malloc(sizeof(TLNode));        //如果这里条件判断失败,也有可能是上面的插入操作失败造成的        iret = iret && (pchildNode != NULL) && (parentNode->node->child != NULL);        if(iret)        {          pchildNode->node = treeNode;          iret = List_Insert(parentNode->node->child,(LinklistNode*)pchildNode,          List_Length(parentNode->node->child));        }        //如果未插入成功,则可释放内存        if(!iret)        {          free(pchildNode);        }      }    }    else    {      free(tlNode);      free(treeNode);    }  }  return iret;}
/*  递归函数  核心思想是:要删除一个结点,递归删除它和它的所有子结点*/static void recursivr_delete(GTree *tree,GTreeNode *node){  if((tree != NULL) && (node != NULL))  {    //把它从主组织链表中删除    for(int i = 0; i < List_Length(tree); i++)    {      TLNode *tlNode = (TLNode*)List_Get(tree,i);      if ((tlNode != NULL) && (tlNode->node == node))      {        List_Delete(tree,i);        free(tlNode);        break;      }    }    //如果它有父结点,把它从它的父结点中的子结点组织链表中删除    GTreeNode *parentNode = node->parent;    if(parentNode != NULL)    {      for(int i = 0; i<List_Length(parentNode->child); i++)      {        TLNode *childNode = (TLNode*)List_Get(parentNode->child,i);        if(childNode->node == node)        {          List_Delete(parentNode->child,i);          free(childNode);          break;        }      }    }    //如果它有子结点,递归删除它所有的子结点    if(node->child != NULL)    {      for(int i = 0; i < List_Length(node->child); i++)      {        TLNode *childNode = (TLNode*)List_Get(node->child,i);        if(childNode != NULL)        {          recursivr_delete(node->child,childNode->node);        }      }    }    free(node);  }}/*  将GTree中pos位置的结点删除并返回其中的数据  删除成功,返回结点中的数据指针,失败,返回NULL*/GTreeData* GTree_Delete(GTree* tree, int pos){  GTreeData *ret = NULL;  TLNode *treeNode = (TLNode*)List_Get(tree,pos);  if(treeNode != NULL)  {    ret = treeNode->node->data;    recursivr_delete(tree,treeNode->node);  }  return ret;}
/*  递归函数  求树的高度,将问题转化为求一个结点的子结点高度,如此递归*/static int recursivr_height(GTree *tree,GTreeNode *node){  int iret = 0;  if((tree != NULL) && (node != NULL))  {    int subHeight = 0;    //获取当前结点的所有子节点    for(int i = 0; i < List_Length(node->child); i++)    {      TLNode *childNode = (TLNode*)List_Get(node->child,i);      if(childNode != NULL)      {        //递归,获取子节点的高度        subHeight = recursivr_height(tree,childNode->node);      }      if(iret < subHeight)      {        iret = subHeight;      }    }  //加上自己的高度1  iret = iret + 1;  }  return iret;}/*  返回GTree的高度  如果成功,返回非负值,否则返回-1*/int GTree_Height(GTree* tree){  int iret = -1;  TLNode *root = (TLNode*)List_Get(tree,0);  if(root != NULL)  {    iret = recursivr_height(tree,root->node);  }  return iret;}
/*  递归调用  求树的度,问题转化为求每个子节点的度,取最大值*/static int recursivr_degree(GTreeNode *node){  int iret = 0;  if(node != NULL)  {    int subDegree = 0;    //获取当前结点子结点数目    iret = List_Length(node->child);    //获取当前结点,所有子结点的度    for(int i = 0; i < List_Length(node->child); i++)    {      TLNode *childNode = (TLNode*)List_Get(node->child,i);      if(childNode != NULL)      {        subDegree = recursivr_degree(childNode->node);      }      //取最大值,最为当前结点的度      if(iret < subDegree)      {        iret = subDegree;      }    }  }  return iret;}/*  返回树的度数  如果成功,返回非负值,失败,返回-1*/int GTree_Degree(GTree* tree){  int iret = -1;  TLNode *root = (TLNode*)List_Get(tree,0);  if(root != NULL)  {    iret = recursivr_degree(root->node);  }  return iret;}
/*  递归调用,显示当前结点的值,及其所有子结点的值*/static void recursivr_display(GTreeNode *node,GTree_Printf pfunc, int subindex, char div,int gap){  if(node != NULL)  {    for(int i = 0; i < subindex; i++)    {      printf("%c",div);    }    //回调函数    pfunc(node->data);    if(node->child != NULL)    {      for(int i = 0; i < List_Length(node->child); i++)      {        TLNode *childNode = (TLNode*)List_Get(node->child,i);        if(childNode != NULL)        {          recursivr_display(childNode->node,pfunc,subindex + gap,div,gap);        }      }    }  }}/*  显示树的结构和内容  tree:树的指针  pfunc:毁掉函数指针,由用户自行编写  div:自定义分割符  gap:自定义间隔*/void GTree_Display(GTree* tree, GTree_Printf pfunc, char div,int gap){  TLNode *root = (TLNode*)List_Get(tree,0);  if(root != NULL)  {    recursivr_display(root->node,pfunc,0,div,gap);  }}

7、完整源码下载

文件名:gtree-1.0.tar.gz
链接: http://pan.baidu.com/s/1o6OLhYq 密码: tew8

编译步骤:

0.1 解压缩:tar -zxvf gtree-1.0.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./GTree

0 0
原创粉丝点击