參考:Mark Allen Weiss 著《數據結構與算法分析——C語言描述》(第二版)python
1 樹的定義git
一棵樹是一些節點的集合。這個集合能夠是空集;若非空,則是一棵樹由稱做根的節點r以及0個或者多個非空的子樹組成。這些子樹中每一棵的根都被來自根 r的一條有向的邊所鏈接。圖1 就是一棵具體的樹,算法
圖1 一棵具體的樹數據結構
2 樹中的基本術語post
2.1 葉子節點
沒有兒子的節點測試
2.2 兄弟節點
具備相同父親的節點spa
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: None 10 """ 11 # 1.列舉出,當前給定的文件夾下的全部文件,以及子文件 12 file_list = os.listdir(dir) 13 14 # 2. 獲取當前路徑下文件夾名稱並打印 15 # 2.1 獲取當前文件夾名稱 16 index = dir.rfind("/") 17 if index == -1: 18 file = dir 19 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 + "/" + fname 27 # 3.2 控制每行打印時的段前空格數 28 sizedepth = new_fname.count("/") - num 29 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 return 13 global totalSize 14 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 totalSize 22 23 # K\B\G單位的轉換 24 def sizeConvert(size): # 單位換算 25 """ 26 :param size: a number,int 27 :return: a number,float,Keep three decimal places after the decimal point. 28 """ 29 K, M, G = 1024, 1024**2, 1024**3 30 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 = dir 15 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 + "/" + fname 25 # 3.2 控制每行打印時的段前空格數 26 sizedepth = new_fname.count("/") - num 27 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 樹的分類