今天来看大家介绍树,树是一种非线性的数据结构,树是由n个结点组成的有限集合,如果n=0,称为空树;如果n>0,则:有一个特定的称之为根的结点,它只有直接后继,但没有直接前驱;除根以外的其他结点划分为m个互不相交的有限集合,每个集合又是一棵树,并且称之为根的子树。

如图

树的一些基本概念

l 树的结点包含一个数据以及若干指向子树的分支

l 结点拥有的子树数称为结点的度

u 度为0的结点称为叶结点

u 度不为0的结点称为分支结点

l 树的度定义为所有结点中的度的最大值

l 结点的直接后继称为该结点的孩子

u 相应的,该结点称为孩子的双亲

l 结点的孩子的孩子的.....称为该结点的子孙

u 相应的,该结点称为子孙的祖先

l 同一个双亲的孩子之间互称兄弟

l 树中结点的最大层次称为树的深度或高度

l 森林是由n(n>=0)棵互不相交的树组成的集合

在这里,我们用通用树结构来给大家介绍树的一些基本操作和操作实现。通用树的存储结构为:

这里介绍通用树的常用操作:

l 创建树

l 销毁树

l 清空树

l 插入结点到树中

l 删除结点

l 获取某个结点

l 获取根结点

l 获取树的高度

l 获取总结点数

l 获取树的度

l 输出树

代码总分为三个文件:

GTree.h : 放置功能函数的声明,以及树的声明,以及数据的声明

GTree.c : 放置功能函数的定义,以及树结点和组织链表结点的定义

Main.c   : 主函数,使用功能函数完成各种需求,一般用作测试

整体结构图为:

这里详细说下插入结点操作,删除结点操作:

插入结点操作:

如图:

删除结点操作:

如图:

OK! 上代码:

GTree.h :

#ifndef _GTREE_H_
#define _GTREE_H_ typedef void GTree;
typedef void GTreeData;
typedef void (GTree_Printf)(GTreeData*); GTree* GTree_Create(); void GTree_Destroy(GTree* tree); void GTree_Clear(GTree* tree); int GTree_Insert(GTree* tree, GTreeData* data, int pPos); GTreeData* GTree_Delete(GTree* tree, int pos); GTreeData* GTree_Get(GTree* tree, int pos); GTreeData* GTree_Root(GTree* tree); int GTree_Height(GTree* tree); int GTree_Count(GTree* tree); int GTree_Degree(GTree* tree); void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div); #endif

GTree.c :

#include <stdio.h>
#include <malloc.h>
#include "GTree.h"
#include "LinkList.h" typedef struct _tag_GTreeNode GTreeNode;
struct _tag_GTreeNode
{
GTreeData* data;
GTreeNode* parent;
LinkList* child;
}; typedef struct _tag_TLNode TLNode;
struct _tag_TLNode
{
LinkListNode header;
GTreeNode* node;
}; GTree* GTree_Create()
{
return LinkList_Create();
} void GTree_Destroy(GTree* tree)
{
GTree_Clear(tree); LinkList_Destroy(tree);
} void GTree_Clear(GTree* tree)
{
GTree_Delete(tree, 0);
} int GTree_Insert(GTree* tree, GTreeData* data, int pPos)
{
LinkList* list = (LinkList*)tree; int ret = (NULL!=list) && (NULL!=data) && (pPos<LinkList_Length(list)); if(ret)
{
TLNode* trNode = (TLNode*)malloc(sizeof(TLNode));
TLNode* cldNode = (TLNode*)malloc(sizeof(TLNode));
TLNode* pNode = (TLNode*)LinkList_Get(list, pPos); GTreeNode* cNode = (GTreeNode*)malloc(sizeof(GTreeNode)); ret = (NULL!=trNode) && (NULL!=cldNode) && (NULL!=cNode); if(ret)
{
cNode->data = data;
cNode->parent = NULL;
cNode->child = LinkList_Create(); trNode->node = cNode;
cldNode->node = cNode; LinkList_Insert(list, (LinkListNode*)trNode, LinkList_Length(list)); if(NULL != pNode)
{
cNode->parent = pNode->node; LinkList_Insert(pNode->node->child, (LinkListNode*)cldNode, LinkList_Length(pNode->node->child));
}
else
{
free(cldNode);
}
}
else
{
free(trNode);
free(cldNode);
free(cNode);
}
} return ret;
} static int recursive_height(GTreeNode* node)
{
int ret = 0; if(NULL != node)
{
int subHeight = 0;
int i = 0; for(i=0; i<LinkList_Length(node->child); i++)
{
TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); subHeight = recursive_height(trNode->node); if(ret < subHeight)
{
ret = subHeight;
}
} ret = ret+1;
} return ret;
} int GTree_Height(GTree* tree)
{
TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); int ret = 0; if(NULL != trNode)
{
ret = recursive_height(trNode->node);
} return ret;
} static void recursive_delete(LinkList* list, GTreeNode* node)
{
if((NULL != list) && (NULL != node))
{
GTreeNode* parent = node->parent; int index = -1;
int i = 0; for(i=0; i<LinkList_Length(list); i++)
{
TLNode* trNode = (TLNode*)LinkList_Get(list, i); if(node == trNode->node)
{
LinkList_Delete(list, i);
free(trNode);
index = i; break;
}
} if(0 <= index)
{
if(NULL != parent)
{
for(i=0; i<LinkList_Length(parent->child); i++)
{
TLNode* trNode = (TLNode*)LinkList_Get(parent->child, i); if(node == trNode->node)
{
LinkList_Delete(parent->child, i);
free(trNode); break;
}
}
} while(0 < LinkList_Length(node->child))
{
TLNode* trNode = (TLNode*)LinkList_Get(node->child, 0); recursive_delete(list, trNode->node);
} LinkList_Destroy(node->child);
free(node);
}
}
} GTreeData* GTree_Delete(GTree* tree, int pos)
{
TLNode* trNode = (TLNode*)LinkList_Get(tree, pos); GTreeData* ret = NULL; if(NULL != trNode)
{
ret = trNode->node->data; recursive_delete(tree, trNode->node);
} return ret;
} GTreeData* GTree_Get(GTree* tree, int pos)
{
TLNode* trNode = (TLNode*)LinkList_Get(tree, pos); GTreeData* ret = NULL; if(NULL != trNode)
{
ret = trNode->node->data;
} return ret;
} GTreeData* GTree_Root(GTree* tree)
{
return GTree_Delete(tree, 0);
} int GTree_Count(GTree* tree)
{
return LinkList_Length(tree);
} static int recursive_degree(GTreeNode* node)
{
int ret = -1; if(NULL != node)
{
int subDegree = 0;
int i = 0; ret = LinkList_Length(node->child); for(i=0; i<LinkList_Length(node->child); i++)
{
TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); subDegree = recursive_degree(trNode->node); if(ret < subDegree)
{
ret = subDegree;
}
}
} return ret;
} int GTree_Degree(GTree* tree)
{
TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); int ret = -1; if(NULL != trNode)
{
ret = recursive_degree(trNode->node);
} return ret;
} static void recursive_display(GTreeNode* node, GTree_Printf* pFunc, int format, int gap, char div)
{
int i = 0; if((NULL != node) && (NULL != pFunc))
{
for(i=0; i<format; i++)
{
printf("%c", div);
} pFunc(node->data);
printf("\n"); for(i=0; i<LinkList_Length(node->child); i++)
{
TLNode* trNode = (TLNode*)LinkList_Get(node->child, i); recursive_display(trNode->node, pFunc, format+gap, gap, div);
}
}
} void GTree_Display(GTree* tree, GTree_Printf* pFunc, int gap, char div)
{
TLNode* trNode = (TLNode*)LinkList_Get(tree, 0); if((NULL != trNode) && (NULL != pFunc))
{
recursive_display(trNode->node, pFunc, 0, gap, div);
}
}

Main.c  :

#include <stdio.h>
#include "GTree.h" void printf_data(GTreeData* data)
{
printf("%c", (int)data);
} int main(void)
{
GTree* tree = GTree_Create(); int i = 0; GTree_Insert(tree, (GTreeData*)'A', -1);
GTree_Insert(tree, (GTreeData*)'B', 0);
GTree_Insert(tree, (GTreeData*)'C', 0);
GTree_Insert(tree, (GTreeData*)'D', 0);
GTree_Insert(tree, (GTreeData*)'E', 1);
GTree_Insert(tree, (GTreeData*)'F', 1);
GTree_Insert(tree, (GTreeData*)'H', 3);
GTree_Insert(tree, (GTreeData*)'I', 3);
GTree_Insert(tree, (GTreeData*)'J', 3); printf("Tree Height: %d\n", GTree_Height(tree));
printf("Tree Degree: %d\n", GTree_Degree(tree));
printf("Full Tree:\n"); GTree_Display(tree, printf_data, 2, '-'); printf("Get Tree Data: \n"); for(i=0; i<GTree_Count(tree); i++)
{
printf_data(GTree_Get(tree, i));
printf("\n");
} printf("Get Root Data: \n"); printf_data(GTree_Root(tree));
printf("\n"); GTree_Delete(tree, 3);
printf("After Deleting D: \n");
GTree_Display(tree, printf_data, 2, '-'); GTree_Clear(tree); printf("After Clearing Tree:\n"); GTree_Display(tree, printf_data, 2, '.'); GTree_Destroy(tree); return 0;
}

一步一步学数据结构之1--n(通用树)的更多相关文章

  1. 一步一步学ROP之linux_x64篇

    一步一步学ROP之linux_x64篇 一.序 **ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防 ...

  2. 一步一步学ROP之linux_x86篇

    一步一步学ROP之linux_x86篇 作者:蒸米@阿里聚安全 ​ 一.序 ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过 ...

  3. 一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)

    这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...

  4. (转载)一步一步学Linq to sql系列文章

    现在Linq to sql的资料还不是很多,本人水平有限,如果有错或者误导请指出,谢谢. 一步一步学Linq to sql(一):预备知识 一步一步学Linq to sql(二):DataContex ...

  5. 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计

    本帖最后由 xinxincaijq 于 2013-1-9 10:27 编辑 一步一步学ZedBoard & Zynq(四):基于AXI Lite 总线的从设备IP设计 转自博客:http:// ...

  6. 一步一步学android控件(之十五) —— DegitalClock & AnalogClock

    原本计划DigitalClock和AnalogClock单独各一篇来写,但是想想,两个控件的作用都一样,就和在一起写一篇了. DegitalClock和AnalogClock控件主要用于显示当前时间信 ...

  7. 一步一步学Remoting系列文章

    转自:http://www.cnblogs.com/lovecherry/archive/2005/05/24/161437.html (原创)一步一步学Remoting之一:从简单开始(原创)一步一 ...

  8. 一步一步学android控件(之十六)—— CheckBox

    根据使用场景不同,有时候使用系统默认的CheckBox样式就可以了,但是有时候就需要自定义CheckBox的样式.今天主要学习如何自定义CheckBox样式.在CheckBox状态改变时有时需要做一些 ...

  9. 一步一步学Python(2) 连接多台主机执行脚本

    最近在客户现场,每日都需要巡检大量主机系统的备库信息.如果一台台执行,时间浪费的就太冤枉了. 参考同事之前写的一个python脚本,配合各主机上写好的shell检查脚本,实现一次操作得到所有巡检结果. ...

随机推荐

  1. [php]php时间戳当中关于时区的问题

    PHP_VERSION = 5.5.11 话说php函数 time() 的起始时间戳是从:GMT 1970-01-01 00:00:00 开始算起的 写了点测试代码: $gmt1 = strtotim ...

  2. vs2013 MVC 无法确定要使用哪一版本的 ASP.NET Web Pages错误

    在web.config文件<configuration>节点下添加 <appSettings>     <add key="webPages:Version&q ...

  3. 一个基于Qt的截屏程序

    最近有一个arm板上的程序需要重写用户手册,在网上找了许久,没找到合适的截屏工具.于是只好自己动手做一个了. 因为arm板上有已经有了Qt环境,于是想到用 Qt的QPixmap::grabWindow ...

  4. UVA507-- Jill Rides Again

    题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  5. codeigniter使用mongodb/redis

    ci2.x版本,使用mongodb,需要安装pecl-php-mongo扩展(github上很多扩展已不可用,找到个可用版本纪录于此),添加到php.ini中 使用如下 public function ...

  6. server宕机监控、检測、报警程序(139绑定手机短信报警)monitor_down.sh

    宕机监控报警程序 一.   需求来源 宕机对运维人员来说,最痛苦了.怎样检測一台server是否还在正常执行,假设该server宕机,怎样在第一时间监測到并通知一线运维人员进行维护,最大化降低损失. ...

  7. C#深复制和浅复制

    本文在于巩固基础 我们来看看什么是深复制.浅复制: C#中对于数据的复制机制虽然简单但是容易让人误解.C#数据类型大体分为值类型(value type)与引用类型(reference type).对于 ...

  8. JavaScript 开发经验整理

    前言 今年接触了一个B/S的项目,总结了一些JavaScript开发经验,整理些有用的内容与大家分享. 本文会持续更新... 1.实现代码访问的控制 随着项目JavaScript代码库扩大,本应被控制 ...

  9. sql存储过程的简单使用

    存储过程(Stored Procedure)是数据库系统中,一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它. 创建 ...

  10. 链表的实现 -- 数据结构与算法的javascript描述 第六章

    链表 链表是由一组节点组成的集合.每个节点都使用一个对象的引用指向它的后继.指向另一个节点的引用叫做链 结构示意图 : 链表头需要我们标识 head { element:head,next:obj1 ...