樹形結構是算法裏很常見的一種數據結構,從二叉樹到多叉樹,還有不少變種。每當須要程序員本身手動實現樹形結構時,由於結構自己的複雜性,不容易調試驗證。但通常的調試對樹形數據結構的總體把控十分有限,甚至會讓人迷失在一大堆的調試信息海洋裏。若是可以將數據樹形打印出來,那麼咱們理解樹形結構的算法就事半功倍。node
咱們知道 Linux 有個 tree 命令用來打印樹狀目錄列表,能夠將某個目錄下的全部文件和子目錄一覽無遺,很是直觀,本文能夠說就是爲了實現這個效果,並給出源碼實現。ios
樹形打印可分爲深度優先和廣度優先兩種。雖然廣度優先更加直觀,但基於咱們的屏幕寬度不夠,難以容納整棵樹,因此採用深度優先的方式。而且先打印右子樹再打印左子樹,測着頭觀察數據更加直觀,哈哈!程序員
#ifndef _AVLTREE_H #define _AVLTREE_H #include <iostream> template<typename T> class avlnode { public: T val; avlnode* left; avlnode* right; avlnode(T x) :val(x), left(nullptr), right(nullptr) {} }; template<typename T> class avltree { typedef avlnode<T> avlnode; public: avltree() : avlroot(nullptr) {} ~avltree() {} void insert(const T& val) { treeInsert(avlroot, val); } void del(const T& val) { treeDelete(avlroot, val); } void watch() { printTreeForWatch(avlroot); } private: int max(int a, int b) { return a > b ? a : b; } int treeHeight(const avlnode* root) { if (root == nullptr) return 0; return max(treeHeight(root->left), treeHeight(root->right)) + 1; } int treeBalanceFector(const avlnode* root) { //計算平衡因子 if (root == nullptr) return 0; return treeHeight(root->left) - treeHeight(root->right); } avlnode* rotateLeft(avlnode* root) { avlnode* tmp = root->right; root->right = tmp->left; tmp->left = root; return tmp; } avlnode* rotateRight(avlnode* &root) { avlnode* tmp = root->left; root->left = tmp->right; tmp->right = root; return tmp; } avlnode* minNode(avlnode* root) { if (root->left != nullptr) root = root->left; return root; } avlnode* treeRebalance(avlnode* root) { int fector = treeBalanceFector(root); if (fector > 1 && treeBalanceFector(root->left) > 0) // LL return rotateRight(root); if (fector > 1 && treeBalanceFector(root->left) <= 0) // LR { root->left = rotateLeft(root->left); return rotateRight(root); } if (fector < -1 && treeBalanceFector(root->right) <= 0) // RR return rotateLeft(root); if (fector < -1 && treeBalanceFector(root->right) > 0) // RL { root->right = rotateRight(root->right); return rotateLeft(root); } return root; } void treeInsert(avlnode*& root, const T& val) { if (root == nullptr) { root = new avlnode(val); } else { if (val == root->val) return; if (val < root->val) treeInsert(root->left, val); else treeInsert(root->right, val); } root = treeRebalance(root); } void treeDelete(avlnode*& root, const T& val) { if (root == nullptr) return; if (val == root->val) { if (root->right != nullptr){ avlnode* min_node = minNode(root->right); root->val = min_node->val; delete min_node; } else { avlnode* deleteNode = root; root = root->left; delete deleteNode; } } else { if (val < root->val) treeDelete(root->left, val); else treeDelete(root->right, val); } root = treeRebalance(root); } struct backlog { avlnode *node; int next_sub_idx; }; enum { LeftIndex, RightIndex }; enum { MaxLevel = 64 }; static inline void nbl_push(backlog *nbl, backlog **top, backlog **bottom) { if (*top - *bottom < MaxLevel) { (*(*top)++) = *nbl; } } static inline backlog * nbl_pop(backlog **top, backlog **bottom) { return *top > *bottom ? --*top : nullptr; } static inline int nbl_is_empty(backlog *top, backlog *bottom) { return top == bottom; } static inline bool is_leaf(avlnode *node) { return node->left == nullptr && node->right == nullptr; } static void node_print(avlnode *node) { if (node != nullptr) { printf("%d\n", node->val); } } static void printTreeForWatch(avlnode *root) { int level = 0; avlnode *node = root; backlog nbl; backlog *p_nbl = nullptr; backlog *top, *bottom, nblStack[MaxLevel]; top = bottom = nblStack; for (;;) { if (node != nullptr) { //如下兩句很是巧妙實現,回到回溯點時不打印回溯點,打印左節點,該過程循環兩遍, //第一遍不打印,第二遍節點存在,且p_nbl已爲空,此時sub_index爲RightIndex,會打印 int sub_index = p_nbl != nullptr ? p_nbl->next_sub_idx : RightIndex; p_nbl = nullptr; //記錄回溯點,先保存左再保存右,當前sub_index爲RightIndex打印 if (is_leaf(node) || sub_index == LeftIndex) { nbl.node = nullptr; nbl.next_sub_idx = RightIndex; } else { nbl.node = node; nbl.next_sub_idx = LeftIndex; } nbl_push(&nbl, &top, &bottom); level++; if (sub_index == RightIndex) { for (int i = 1; i < level; ++i) { if (i == level - 1) { printf("%-8s", "+-------"); } else { if (nblStack[i - 1].node != nullptr) { printf("%-8s", "|"); } else { printf("%-8s", " "); } } } node_print(node); } node = sub_index == LeftIndex ? node->left : node->right; } else { p_nbl = nbl_pop(&top, &bottom); if (p_nbl == nullptr) { break; } node = p_nbl->node; level--; } } } private: avlnode* avlroot; }; #endif
測試驗證以下:算法
int main() { avltree<int> tree; for (int i = 0; i < 10; ++i) { tree.insert(i); } tree.watch(); system("pause"); return 0; }
結果:數據結構