其實這是一個見仁見智的問題初步建立。遞歸還是非遞歸綜合運用,不過是兩種不同的遍歷形式,不存在絕對的優(yōu)劣的方法,而且一般情況下可以相互補充實事求是。我個人選擇非遞歸出于以下幾種因素:
避免樹層次過多導致函數調用堆棧溢出; 避免C語言函數調用開銷核心技術體系; 所有狀態(tài)可見可控開拓創新。
當然以上因素并不重要,開心就好必然趨勢。
一切皆套路促進善治,不變應萬變
既然本文講究套路,那么干脆現(xiàn)在就把套路給出來好了多樣性,偽代碼形式:
/* log對象 */ typedef struct node_backlog { node指針; 回溯點位置(索引); }; /* Dump */ void dump(tree) { 從根節(jié)點開始迭代; 初始化log堆棧; for (; ;) { if (節(jié)點指針為空) { 從log對象中獲取回溯點位置; if (不存在發揮效力,或無效的回溯點) { 壓棧空節(jié)點指針; } else { 壓棧當前節(jié)點指針明顯,同時記錄下一個回溯點位置; } if (回溯點位置索引為0) { 輸出層次縮進安全鏈、畫路徑,打印節(jié)點內容; } 進入下一層; } else { if (log堆棧為空) return; 彈出log對象創新為先,獲取最近記錄的節(jié)點指針; } } }
無限層次樹形筆記本簡單吧無限層次樹形筆記本 真正做到?而且我敢說,這個套路對于所有樹形結構都是通用的創新延展,只要能夠深度遍歷強化意識。
不信我給出三個實戰(zhàn)例子。
目錄樹或字典樹
代碼在gist基本情況。這是個MIB樹現場,是管理網絡節(jié)點(設備)用的。簡要地講力量,它具有兩重特性:
節(jié)點之間的層次嵌套關系我有所應,決定了它屬于目錄層次結構; 節(jié)點的key具有公共前綴深入實施,使得它也類似于(或可用于)字典結構至關重要。
我們不需要關心其CRUD實現(xiàn),只需要知道有一棵現(xiàn)成的目錄樹或者字典樹效果,我們如何在終端輸出它的形狀無障礙。
無限層次樹形筆記本#define OID_MAX_LEN 64 struct node_backlog { /* node to be backlogged */ struct mib_node *node; /* the backtrack point, next to the orignal sub-index of the node, valid when >= 1, invalid == 0 */ int next_sub_idx; }; static inline void nbl_push(struct node_backlog *nbl, struct node_backlog **top, struct node_backlog **bottom) { if (*top - *bottom< OID_MAX_LEN) { (*(*top)++) = *nbl; } } static inline struct node_backlog * nbl_pop(struct node_backlog **top, struct node_backlog **bottom) { return *top > *bottom? --*top : NULL; } void mib_tree_dump(void) { int level = 0; oid_t id = 0; struct mib_node *node = *dummy_root; struct node_backlog nbl, *p_nbl = NULL; struct node_backlog *top, *bottom, nbl_stack[OID_MAX_LEN]; top = bottom = nbl_stack; for (; ;) { if (node != NULL) { /* Fetch the pop-up backlogged node's sub-id. If not backlogged, set 0. */ int sub_idx = p_nbl != NULL ? p_nbl->next_sub_idx : 0; /* Reset backlog for the node has gone deep down */ p_nbl = NULL; /* Backlog the node */ if (is_leaf(node) || sub_idx + 1 >= node->sub_id_cnt) { nbl.node = NULL; nbl.next_sub_idx = 0; } else { nbl.node = node; nbl.next_sub_idx = sub_idx + 1; } nbl_push(*nbl, *top, *bottom); level++; /* Draw lines as long as sub_idx is the first one */ if (sub_idx == 0) { int i; for (i = 1; i < level; i++) { if (i == level - 1) { printf("%-8s", "+-------"); } else { if (nbl_stack[i - 1].node != NULL) { printf("%-8s", "|"); } else { printf("%-8s", " "); } } } printf("%s(%d)\n", node->name, id); } /* Go deep down */ id = node->sub_id[sub_idx]; node = node->sub_ptr[sub_idx]; } else { p_nbl = nbl_pop(*top, *bottom); if (p_nbl == NULL) { /* End of traversal */ break; } node = p_nbl->node; level--; } } }
代碼不算復雜無限層次樹形筆記本,就講幾個要點
深度優(yōu)先遍歷要利用回溯點快速融入,就是走到一個分支的盡頭后認為,上溯到原先路過的某個位置,從另一個分支繼續(xù)遍歷增強,如果回溯到根節(jié)點更合理,就說明遍歷結束了,所以更優美,回溯點是必須要記錄的各方面。問題是記錄哪個位置呢?以二叉樹為例無限層次樹形筆記本 成效與經驗,遍歷了左子樹后適應性,接下來遍歷的就是右子樹,所以回溯點是右孩子稍有不慎;對于多叉樹重要作用,遍歷第N個分支后,接下來要遍歷N+1分支最為顯著,所以回溯點是N+1尤為突出;如果遍歷完最后一個分支,則需要繼續(xù)上溯尋找回溯點了環境。所以呢空間載體,我們就用sub_idx + 1來記錄回溯點無限層次樹形筆記本 ,我們還可以利用這個屬性做個分類相對簡便,值大于等于1時重要組成部分,回溯點有效,值等于0合作,回溯點無效勃勃生機。
關于log堆棧操作,這里使用了二級指針的技巧一站式服務。這個堆棧十分小巧廣度和深度,所以利用函數局部變量做存儲也未嘗不可,還有不需要對外暴露數據的好處引領作用。那么對于堆棧指針加強宣傳,就需要傳遞二次指針來改變它。比如我們看入棧操作:
(*(*top)++) = *nbl;
這是將log對象拷貝給top指向位置用的舒心,然后將top指針上移技術發展,top和bottom的差值就是堆棧元素的數目。由于top是二級指針集成,所以被賦值的是**top重要手段,指針移動就是(*top)++。再來看出棧操作:
return --*top;
文章地址:http://cdgoodok.com/article/other/wsmsyfdgbl.html