参考:Mark Allen Weiss 著《数据结构与算法分析——C语言描述》(第二版)
1 树的定义
一棵树是一些节点的集合。这个集合可以是空集;若非空,则是一棵树由称作根的节点r以及0个或者多个非空的子树组成。这些子树中每一棵的根都被来自根 r的一条有向的边所连接。图1 就是一棵具体的树,
图1 一棵具体的树
2 树中的基本术语
2.1 叶子节点
没有儿子的节点
2.2 兄弟节点
具有相同父亲的节点
2.3 深度(deep)
对任意节点n的深度 = 根到节点n的唯一路径的长
补充:根的深度为0
2.4 高度
节点X处的高度是从X到一片树叶的最长路径的长
补充:一棵树的高度 = 它的根的高
2.5 举例说明
在图1中,根节点为A,A的儿子节点为B、C、D、E、F、G。叶子节点有B、C、H、I、P、Q、K、L、M、N。互为兄弟节点的有K、L和M。K、L和M的父节点为F。图1 是一棵高度为3的树。图中还有其它关系,这里就不一一举例了,有兴趣的话,可以自己找一找。
3 树的实现
3.1 实现思路
每一个节点除数据外还要一些指针,使得该节点的每一个儿子都有一个指针指向它。由于每个节点的儿子数可以变化很大且事先不知道。
因此,在数据结构中建立到各儿子节点直接的链接是不可行的,此方法会浪费太多的空间。可以将每个节点的所有儿子都放在树节点的链表中。
3.2 实现的伪代码
typedef struct TreeNode *PtrToNode;struct TreeNode { ElementType Element; //存储数据 PtrToNode FirstChild; //指向第一个儿子节点的指针 PtrToNode NextChild; //指向下一兄弟节点的指针};
4 树的基本操作
如果一个树只能存储而无法读取,也就无法使用。那么我们还设计这种结构还有什么意义!遍历又分为先序遍历(preorder traversal)和后序遍历(postorder traversal)两种。
(1)先序遍历(preorder traversal)思想:对节点的处理工作是在它的诸儿子节点被处理之前进行的。
(2)后序遍历(postorder traversal)思想:在一个节点处的工作是在它的诸儿子节点被计算后进行的
5 树的应用
包括UNIX、VAX/VMS 和DOS在内的许多常用操作系统中的目录结构。下面列举两个案例来说明:“列出分级文件系统中目录的例程”和“计算一个目录大小的例程”。
5.1 伪代码
(1)“列出分级文件系统中目录的例程”的伪代码如下,
static void ListDir(DirectoryOrFile D, int Depth) { if(D is a legitimate entry) { PrintName(D, Depth); if(D is a directory) for each child, C of D: ListDir(C, Depth + 1); } }void ListDirectory(DirectoryOrFile D) { ListDir(D, 0); }
(2)“计算一个目录大小的例程”的伪代码如下,
static int SizeListDirectory(DirectoryOrFile D) { int TotalSize; TotalSize = 0; if(D is a directiry) for each child, C of D: TotalSize += SizeListDirectory(C); return TotalSize; }
5.2 python语言实现
(1)“列出分级文件系统中目录的例程”的python语言实现代码如下,
1 import os 2 3 4 # 按照一定格式打印文件或目录名称 5 def listDir(dir, num): 6 """ 7 :param dir: absolute path 8 :param num: the number of "/" before your firstinput path 9 :return: None10 """11 # 1.列举出,当前给定的文件夹下的所有文件,以及子文件12 file_list = os.listdir(dir)13 14 # 2. 获取当前路径下文件夹名称并打印15 # 2.1 获取当前文件夹名称16 index = dir.rfind("/")17 if index == -1:18 file = dir19 file = dir[index + 1:]20 # 2.2 打印文件名及21 print(file)22 23 # 3.针对于列举出的列表,进行遍历24 for fname in file_list:25 # 3.1 拼接当前文件的路径26 new_fname = dir + "/" + fname27 # 3.2 控制每行打印时的段前空格数28 sizedepth = new_fname.count("/") - num29 30 # 3.3 判断是否为目录31 if os.path.isdir(new_fname):32 print(end="\t" * sizedepth)33 listDir(new_fname, num)34 else:35 # 打印文件名称36 print("\t" * (sizedepth) + fname)37 38 # 测试代码39 40 41 if __name__ == '__main__':42 path = "F:/python_AI/python基础/python文件操作/files1"43 num = path.count("/")44 print("num = ", num)45 listDir(path, num)
执行后结果如图2:
图2 打印目录结果
(2)“计算一个目录大小的例程”的python语言实现代码如下,
(i)文件大小计算模块sizedir.py文件,文件内容如下:
1 import os 2 3 totalSize = 0 4 # 计算文件或目录下的所占大小 5 def cal_size(path): 6 """ 7 :param path: an absolute path 8 :return: the size of the input path(file or directory) 9 """10 if not os.path.isdir(path):11 print('Error:"', path, '" is not a directory or does not exist.')12 return13 global totalSize14 for lists in os.listdir(path):15 sub_path = os.path.join(path, lists)16 # print(sub_path)17 if os.path.isfile(sub_path):18 totalSize = totalSize+os.path.getsize(sub_path) # 文件总大小19 elif os.path.isdir(sub_path):20 cal_size(sub_path) # 递归遍历子文件夹21 return totalSize22 23 # K\B\G单位的转换24 def sizeConvert(size): # 单位换算25 """26 :param size: a number,int27 :return: a number,float,Keep three decimal places after the decimal point.28 """29 K, M, G = 1024, 1024**2, 1024**330 if size >= G:31 return str(round(size/G, 3))+' G Bytes'32 elif size >= M:33 return str(round(size/M, 3))+' M Bytes'34 elif size >= K:35 return str(round(size/K, 3))+' K Bytes'36 else:37 return str(size)+' Bytes'
(ii)打印文件名称及大小模块my_size_dir.py,文件内容如下,
1 import os 2 import sizedir 3 4 # 打印文件或目录名称及所占内存大小 5 def listDir(dir, num): 6 7 # 1.列举出,当前给定的文件夹下的所有文件,以及子文件 8 file_list = os.listdir(dir) 9 10 # 2. 获取当前路径下文件夹名称并打印11 # 2.1 获取当前文件夹名称12 index = dir.rfind("/")13 if index == -1:14 file = dir15 file = dir[index + 1:]16 # 2.2 计算当前目录下的文件总大小17 dir_size = sizedir.cal_size(dir)18 # 2.3 打印文件名及文件大小19 print(file, "\t(%s)" % sizedir.sizeConvert(dir_size))20 21 # 3.针对于列举出的列表,进行遍历22 for fname in file_list:23 # 3.1 拼接当前文件的路径24 new_fname = dir + "/" + fname25 # 3.2 控制每行打印时的段前空格数26 sizedepth = new_fname.count("/") - num27 28 # 3.3 判断是否为目录29 if os.path.isdir(new_fname):30 print(end="\t" * sizedepth)31 listDir(new_fname, num)32 else:33 # 打印文件名称及大小34 fsize = sizedir.sizeConvert(os.path.getsize(new_fname))35 print("\t" * (sizedepth) + fname, "\t(%s)" % fsize)36 37 # 测试代码38 if __name__ == '__main__':39 path = "F:/python_AI/python基础/python文件操作/files1"40 num = path.count("/")41 # print(num)42 listDir(path, num)
上面代码执行结果如图3:
图3 打印目录及大小结果
6 树的分类
树的分类如图4。
图4 树的分类
原文出处:https://www.cnblogs.com/cuizhu/p/9470312.html