二叉樹性質和遍歷

二叉樹

二叉樹性質

  1. 在第n層,最多有2n12^{n-1}個節點
  2. 深度爲n層的二叉樹,最多有2n12^{n}-1個節點
  3. 任何一個二叉樹,葉節點有n0n_{0}個,度爲2的非葉節點有n2n_{2}個,那麼n0=n2+1n_{0}=n_{2}+1
  4. 具有n個節點的完全二叉樹,的高度爲log2n+1\lfloor log_{2}n \rfloor +1\lfloor\rfloor表示向下取整

二叉樹遍歷

  • 前序遍歷:中左右
  • 中序遍歷:左中右
  • 後序遍歷:左右中

遞歸方式

在這裏插入圖片描述
如果用遞歸方式,那麼遍歷順序是固定的,打印節點的時間決定了是那種遍歷。拿上圖來說,對於F左側,順序是FCA(A左子樹爲空)A(A右子樹爲空)ACDB(B左子樹爲空)D…

  • 前序遍歷:在第一次進入打印節點
  • 中序遍歷:第二次打印節點
  • 後序遍歷:第三次打印節點

代碼

#include <iostream>
#include <stdlib.h>

//節點
struct Node {
    int value;
    Node* left;
    Node* right;

    Node(int v = 0): value(v), left(nullptr), right(nullptr) {}
};

//向二叉樹插入元素
void insert_tree(Node* &root, int value) {
    if (nullptr == root) {
        root = new Node(value);
        return;
    }
    if (value < root->value) {
        insert_tree(root->left, value);
    } else if (value > root->value) {
        insert_tree(root->right, value);
    }
}

//生成二叉樹
void create_tree(Node* root, int root_value, int size) {
    root->value = root_value++;
    for (int i = 0; i <= size; ++i) {
        insert_tree(root, i);
    }
}

//銷燬二叉樹
void destroy_tree(Node* root) {
    if (root == nullptr) {
        return;
    }

    destroy_tree(root->left);
    destroy_tree(root->right);

    delete root;
}

//前序遍歷
void pre_order_recur(Node* head) {
    if (head == nullptr) {
        return;
    }
    std::cout << head->value << " ";
    pre_order_recur(head->left);
    pre_order_recur(head->right);
}

//中序遍歷
void in_order_recur(Node* head) {
    if (head == nullptr) {
        return;
    }
    in_order_recur(head->left);
    std::cout << head->value << " ";
    in_order_recur(head->right);
}

//後序遍歷
void post_order_recur(Node* head) {
    if (head == nullptr) {
        return;
    }
    post_order_recur(head->left);
    post_order_recur(head->right);
    std::cout << head->value << " ";
}

int main(void)
{
    Node* root = new Node();
    create_tree(root, 5, 9);

    pre_order_recur(root);
    std::cout << std::endl;
    in_order_recur(root);
    std::cout << std::endl;
    post_order_recur(root);
    std::cout << std::endl;

    destroy_tree(root);
    return 0;
}

非遞歸方式

非遞歸遍歷需要一個棧輔助,把節點按照順序壓入棧中。前序遍歷和後序遍歷在循環開始前都需要頭結點先入隊。

  • 前序遍歷:彈出就打印,有右就壓右,有左就壓左
  • 中序遍歷:根不爲空左遞歸(壓棧),根若爲空右遞歸,右遞歸時再打印
  • 後序遍歷:需要兩個棧;彈出壓入s2,有左就壓左(s1),有右就壓右(s1),最後纔打印
  • 層序遍歷:層序遍歷,使用隊列
    1.頭結點入隊
    2.頭結點彈出打印
    3.左右子節點先後入隊列
    4.按順序彈出打印,並將子節點先後入隊

代碼

#include <iostream>
#include <stack>

//節點
struct Node {
    int value;
    Node* left;
    Node* right;

    Node(int v = 0): value(v), left(nullptr), right(nullptr) {}
};

//向二叉樹插入元素
void insert_tree(Node* &root, int value) {
    if (nullptr == root) {
        root = new Node(value);
        return;
    }
    if (value < root->value) {
        insert_tree(root->left, value);
    } else if (value > root->value) {
        insert_tree(root->right, value);
    }
}

//生成二叉樹
void create_tree(Node* root, int root_value, int size) {
    root->value = root_value++;
    for (int i = 0; i <= size; ++i) {
        insert_tree(root, i);
    }
}

//銷燬二叉樹
void destroy_tree(Node* root) {
    if (root == nullptr) {
        return;
    }

    destroy_tree(root->left);
    destroy_tree(root->right);

    delete root;
}

//前序遍歷
void pre_order(Node* head) {
    if (head != nullptr) {
        std::stack<Node*> s;
        s.push(head);

        while (!s.empty()) {
            head = s.top();
            s.pop();
            std::cout << head->value << " ";
            if (head->right != nullptr) {
                s.push(head->right);
            }
            if (head->left != nullptr) {
                s.push(head->left);
            }
        }
    }
}

//中序遍歷
void in_order(Node* head) {
    if (head != nullptr) {
        std::stack<Node*> s;
        while (!s.empty() || head != nullptr) {
            if (head != nullptr) {
                s.push(head);
                head = head->left;
            } else {
                head = s.top();
                s.pop();
                std::cout << head->value << " ";
                head = head->right;
            }
        }
    }
}

//後序遍歷
void post_order(Node* head) {
    if (head != nullptr) {
        std::stack<Node*> s1;
        std::stack<Node*> s2;
        s1.push(head);

        while (!s1.empty()) {
            head = s1.top();
            s1.pop();
            s2.push(head);
            if (head->left != nullptr) {
                s1.push(head->left);
            }
            if (head->right != nullptr) {
                s1.push(head->right);
            }
        }

        while (!s2.empty()) {
            head = s2.top();
            std::cout << head->value << " ";
            s2.pop();
        }
    }
}

//層序遍歷,使用隊列
//1.頭結點入隊
//2.頭結點彈出打印
//3.左右子節點先後入隊列
//4.按順序彈出打印,並將子節點先後入隊
void level_order(Node* head) {
    std::queue<Node*> q;
    q.push(head);
    Node *node;
    while (!q.empty()) {
        node = q.front();
        std::cout << node->value << std::endl;
        q.pop();
        if (node->left != nullptr) {
            q.push(node->left);
        }
        if (node->right != nullptr) {
            q.push(node->right);
        }
    }
}

int main(void)
{
    Node* root = new Node();
    create_tree(root, 5, 9);

    pre_order(root);
    std::cout << std::endl;
    in_order(root);
    std::cout << std::endl;
    post_order(root);
    std::cout << std::endl;

    destroy_tree(root);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章