二叉樹的樹形結構打印

打印樹形結構初衷

樹形結構是算法裏很常見的一種數據結構,從二叉樹到多叉樹,還有不少變種。每當須要程序員本身手動實現樹形結構時,由於結構自己的複雜性,不容易調試驗證。但通常的調試對樹形數據結構的總體把控十分有限,甚至會讓人迷失在一大堆的調試信息海洋裏。若是可以將數據樹形打印出來,那麼咱們理解樹形結構的算法就事半功倍。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;
}

結果:數據結構

 

參考文章:https://www.v2ex.com/t/338653測試

相關文章
相關標籤/搜索