树的描述,实现与应用

来源:互联网 发布:女声变男声的软件 编辑:程序博客网 时间:2024/06/02 11:09

一)定义树最自然的方式是递归的方法.一棵树是一些节点的集合.除了根节点外,每个节点都有一条边连接至它的父亲,所以一棵树有N个节点,N-1条边.

深度:对任意节点n,它的深度为从根到n的唯一路径长.根的深度为0.

高度:对任意节点n,它的高度是从n到树叶的最长路径.所有树叶的高为0.

二)树的实现

每个节点的儿子可以变化很大,因此在数据结构中建立到各儿子节点的直接连接是不可行的.

实际的解决方法很简单,用第一个儿子FirstChild和下一兄弟NextSibling的方式.如图:


节点声明的代码如下:

typedef struct TreeNode *PtrToNode;typedef struct TreeNode *Tree;struct TreeNode{    ElementType Element;    PtrToNode FirstChild;    PtrToNode NextSibling;};

三)树的遍历与应用.

磁盘目录的先序遍历.


下面用比较简单的代码大概实现一下目录显示的功能:

#include<stdio.h>#include<malloc.h>typedef struct{    char *Name;    unsigned char Type;//0:represent a file else represent directory}ElementType;typedef struct TreeNode *PtrToNode;typedef struct TreeNode *Tree;struct TreeNode{    ElementType Element;    PtrToNode FirstChild;    PtrToNode NextSibling;};void PrintName(Tree tree,int depth){    while(depth--)        printf("   ");    printf("%s\n",tree->Element.Name);}//先序遍历.递归的方法static void ListDir(Tree tree,int depth){    if(tree == NULL)        return;    PrintName(tree,depth);    if(tree->Element.Type)    {        ListDir(tree->FirstChild,depth + 1);        ListDir(tree->NextSibling,depth);    }}int main()//测试{    Tree tree = (Tree)malloc(sizeof(struct TreeNode));    PtrToNode mark = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode alex = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode junk = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode bill = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode course = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode English = (PtrToNode)malloc(sizeof(struct TreeNode));    PtrToNode work = (PtrToNode)malloc(sizeof(struct TreeNode));    tree->Element.Name = "/usr";    tree->Element.Type = 1;    tree->FirstChild = mark;    tree->NextSibling = NULL;        mark->Element.Name = "mark";    mark->Element.Type = 1;    mark->FirstChild = NULL;    mark->NextSibling = alex;    junk->Element.Name = "junk.c";    junk->Element.Type = 0;    junk->FirstChild = NULL;    junk->NextSibling = NULL;    alex->Element.Name = "alex";    alex->Element.Type = 1;    alex->FirstChild = junk;    alex->NextSibling = bill;    bill->Element.Name = "bill";    bill->Element.Type = 1;    bill->FirstChild = work;    bill->NextSibling = NULL;        work->Element.Name = "work";    work->Element.Type = 1;    work->FirstChild = NULL;    work->NextSibling = course;    course->Element.Name = "course";    course->Element.Type = 1;    course->FirstChild = English;    course->NextSibling = NULL;    English->Element.Name = "English";    English->Element.Type = 0;    English->FirstChild = NULL;    English->NextSibling = NULL;    ListDir(tree,0);    return 0;}
效果如下:



在先序遍历中,对节点的处理工作是在他的儿子被处理之前进行的.另一种遍历的方法是后序遍历.

后续遍历的每一个节点的处理工作要在他的儿子之后才进行的.下面是用后续遍历计算目录的大小的历程.

static int SizeDirectory(DirectoryOrFile D){    int TotalSize = 0;    if(D is a legitimate entry)//D合法    {        TotalSize = FileSize(D);        if(D is directory)//D是目录TotalSize += SizeDirectory(C);//C是D的一个儿子(子目录或子文件)    }return TotalSize;}

如果D不是目录,那么SizeDirectory只返回D所占用的大小.否则,被D占用的大小将被加到

其所有子节点的大小中.



原创粉丝点击