2021.01.23二叉树学习总结

树的简介

一、一个树的节点有父节点(father)左节点(left)右节点(right),没有父节点的叫做根节点(root)
二、每个树只有一个根节点(root)
三、每个节点只有一个父节点(father)
在这里插入图片描述

节点的度:又有子节点的数目,不为0则是分支节点,0则是叶子节点
树的高度:树的最大层次

二叉树的建立

首先我们需要声明节点的数据(数据类型随情况而定):

struct phone
{
    string name = "none";
    double value = 0;
};
typedef phone data; //构建数据区

这里我是用一个phone结构体作为数据

然后我们需要声明节点:

struct Node
{
    data obj;
    Node *left = NULL, *right = NULL;
};                                 //构建节点

这里有两个指针,分别用来指向该节点的左支和右支

数据和节点都好了,下面我们就要声明树了:

class Tree
{
private:
    int size=0;
    Node *root = NULL;
}

树的声明也好了,现在我们就能够创建一个树了:

Tree tree;

我们创建了一个名字叫做tree的树,不过它是一个空树,没有任何数据,现在我们要编写一个insert方法来向树里面插入数据。
数据的插入不是随便的,我们需要自己定义一个插入的规则。
数据的插入规则我们一般都是这样定义:
左节点<父节点<右节点
在这里插入图片描述
我们用代码实现这个规则:

bool cmp(data &father, data &node) //自定义规则
{
    if (father.value == node.value)
        return node.name < father.name;
    return node.value < father.value;
}

然后就是编写insert函数:

void insert(data obj, bool (*cmp)(data &father, data &node) = cmp) //插入数据。(增)
{
    auto node = new Node;   //新建一个节点
    node->obj = obj;        //将数据放入节点
    if (this->root == NULL) //如果是空树,直接让新节点作为根节点
    {
        root = node;
        return;
    }
}

如果是空树,我们就把插入的节点当作根节点就行了,如果不是空树,我们还要加上下面这段:

auto father = this -> root;
while (father != NULL)
{
    if (cmp(father->obj, node->obj)) //按照自定义规则插入节点
    {
        if (father->left == NULL)
        {
            father->left = node;
            return;
        }
        else
            father = father->left;
    }
    else
    {
        if (father->right == NULL)
        {
            father->right = node;
            return;
        }
        else
            father = father->right;
    }
}

数据插入完成,节点多了一个,所以size++,insert完整代码如下:

void insert(data obj, bool (*cmp)(data &father, data &node) = cmp) //插入数据。(增)
    {
        auto node = new Node;   //新建一个节点
        node->obj = obj;        //将数据放入节点
        if (this->root == NULL) //如果是空树,直接让新节点作为根节点
        {
            root = node;
            return;
        }
        auto father = this->root;
        while (father != NULL)
        {
            if (cmp(father->obj, node->obj)) //按照自定义规则插入节点
            {
                if (father->left == NULL)
                {
                    father->left = node;
                    return;
                }
                else
                    father = father->left;
            }
            else
            {
                if (father->right == NULL)
                {
                    father->right = node;
                    return;
                }
                else
                    father = father->right;
            }
        }
        size++;
    }

树的遍历(非递归实现中序遍历):

这里我用的是中序遍历,中序遍历可以按照节点从小到大的顺序遍历一遍。
因为我们的的规则是:
左节点<父节点<右节点
假如我们有11个数据按照下面的顺序插入树中:

3210967541811

最后创建的树如下图所示:
在这里插入图片描述
因为左支所有节点 < 父节点 < 右支所有节点
所以,从根节点开始,我们先到左支叶节点,然后从叶节点开始往上输出,如果遇到节点有右支,我们就进入又节点,直到遍历所有节点,下面是递归实现:

void print(Node *node)
{
    if (node == NULL)
        return;
    print(node->left);
    cout << node->obj.value;
    print(node->right);
}

因为我想把print作为tree类的一个方法,所以递归不太好弄,于是我用栈模拟了递归过程,其实系统的递归本身也是用栈实现的:

void pirnt(void) //打印二叉树,使用中序遍历法
{
    if (root == NULL)
        return;
    stack<Node *> st;
    Node *temp;
    st.push(root);
    bool flag = true;
    while (st.size()) //空栈结束
    {
        while (flag && st.top()->left != NULL) //如果top之前没有向左入栈,我们就从左方向把节点入栈
            st.push(st.top()->left);
        temp = st.top(); //取出栈顶的节点,并弹出
        st.pop();
        //输出取出的节点
        cout << "name:" << temp->obj.name << " ";
        cout << "value:" << temp->obj.value << endl;
        //如果取出的节点有右支,则将右节点入栈
        if (temp->right != NULL)
        {
            st.push(temp->right);
            flag = true; //此时top节点已经更新,并且没有向左入栈,我们把标记设为true
        }
        else
            flag = false; //不然的话,栈里面所有的节点都已经向左入过栈了,
                          //就把标记设置为false,否则会重复入栈,导致死循环。
    }
}

这是非递归实现中序遍历。
最后成果
完整代码如下:

#include <bits/stdc++.h>
using namespace std;
struct phone
{
    string name = "none";
    double value = 0;
};
typedef phone data; //构建数据区
struct Node
{
    data obj;
    Node *left = NULL, *right = NULL;
};                                 //构建节点
bool cmp(data &father, data &node) //自定义规则
{
    if (father.value == node.value)
        return node.name < father.name;
    return node.value < father.value;
}
class Tree
{
private:
    int size=0;
    Node *root = NULL;

public:
    const Node *getroot(void)
    {
        return root;
    }
    int size()
    {
        return size;
    }
    void insert(data obj, bool (*cmp)(data &father, data &node) = cmp) //插入数据。(增)
    {
        auto node = new Node;   //新建一个节点
        node->obj = obj;        //将数据放入节点
        if (this->root == NULL) //如果是空树,直接让新节点作为根节点
        {
            root = node;
            return;
        }
        auto father = this->root;
        while (father != NULL)
        {
            if (cmp(father->obj, node->obj)) //按照自定义规则插入节点
            {
                if (father->left == NULL)
                {
                    father->left = node;
                    return;
                }
                else
                    father = father->left;
            }
            else
            {
                if (father->right == NULL)
                {
                    father->right = node;
                    return;
                }
                else
                    father = father->right;
            }
        }
        size++;
    }
    void pirnt(void) //打印二叉树,使用中序遍历法
    {
        if (root == NULL)
            return;
        stack<Node *> st;
        Node *temp;
        st.push(root);
        bool flag = true;
        while (st.size()) //空栈结束
        {
            while (flag && st.top()->left != NULL) //如果top之前没有向左入栈,我们就从左方向把节点入栈
                st.push(st.top()->left);
            temp = st.top(); //取出栈顶的节点,并弹出
            st.pop();
            //输出取出的节点
            cout << "name:" << temp->obj.name << " ";
            cout << "value:" << temp->obj.value << endl;
            //如果取出的节点有右支,则将右节点入栈
            if (temp->right != NULL)
            {
                st.push(temp->right);
                flag = true;//此时top节点已经更新,并且没有向左入栈,我们把标记设为true
            }
            else
                flag = false;//不然的话,栈里面所有的节点都已经向左入过栈了,
                             //就把标记设置为false,否则会重复入栈,导致死循环。
        }
    }
};                             //构建树
int main(void)
{
    Tree tree; //创建一个二叉树
    data temp;
    for (int i = 0; i < 5; i++)//输入5个数据
    {
        cin >> temp.name >> temp.value;
        tree.insert(temp);
    }
    tree.pirnt();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值