264-C++ 二叉树

17 篇文章 0 订阅

1.树的定义
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二叉树是最简单的树形结构
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果一个节点的左孩子是一个棵满二叉树,它的右孩子也是一棵满二叉树,那么这棵树是否一定是一个满二叉树?

答案:不一定
这种情况就不是一颗满二叉树
在这里插入图片描述
如果一个节点的左孩子是一个棵完全二叉树,它的右孩子也是一棵完全二叉树,那么这棵树是否一定是一个完全二叉树呢?

答案:不一定
在这里插入图片描述
如果是满二叉树,可以用顺序表存储,如果是普通二叉树,使用顺序表浪费的空间很多,所以一般不使用顺序表存储普通二叉树
在这里插入图片描述
三叉链表的存储密度要比二叉链表的存储密度要小
原因是三叉链表要有三个指针来表示节点和节点之间的关系,而二叉链表只有两个,但是三叉链表要比二叉链表要好一点,好在三叉链表找父节点的时候要比二叉链表好找的多的多

一般排序二叉树、VL树、红黑树都采取的是三叉链表的方式,因为需要不断的进行回溯,需要访问父节点
在这里插入图片描述
下面存储的都是下标,如果没有左边的图,可以根据右边的表来推测出图是什么样的
在这里插入图片描述
在这里插入图片描述
实际上都是递归的访问形式
中序遍历的结果:CBDAE
在这里插入图片描述
先序遍历的第一个节点就是根节点,然后以该根节点为分界点,将先序遍历左边分为左先序遍历和右先序遍历,将中序遍历左边分为左中序遍历和右中序遍历,新产生的左先序遍历和右先序遍历的第一个节点都是根节点,然后依次进行下去
在这里插入图片描述
根据先序序列和中序序列创建二叉树

//根据先序遍历和中序遍历打印出序列
BtNode* CreatePI(const char* ps, const char* is, int n)
{
    BtNode* s = NULL;
    if (n >= 1)//还有数据
    {
        s = Buynode();//购买一个节点
        s->data = ps[0];
        int pos = FindIs(is, n, ps[0]);
        if (pos == -1) exit(1);
        s->leftchild = CreatePI(ps+1,is,pos);
        s->rightchild = CreatePI(ps+pos+1,is+pos+1,n-pos-1);
    }
    return s;
}
//根据先序和中序可以推测出结构
BtNode* CreateBinartTreePI(const char*ps, const char* is, int n)
{
    if (ps == NULL || is == NULL || n <= 0) return NULL;
    else return CreatePI(ps, is, n);
}
int main()
{
    char ps[] = { "ABCDEFGH" };
    char is[] = { "CBEDFAGH" };
    char ls[] = { "CEFDBHGA" };
    int n = strlen(ps);
    BinaryTree root = NULL;
    root = CreateBinartTreePI(ps, is, n);
    PreOrder(root);
    cout << endl;
    InOrder(root);
    cout << endl;
    PastOrder(root);
    cout << endl;
    return 0;
}

在这里插入图片描述
通过中序序列和后序序列创建二叉树

BtNode* CreateIL(const char* is, const char* ls, int n)
{
    BtNode* s = NULL;
    if (n > 0)//还有数据
    {
        s = Buynode();//购买一个节点
        s->data = ls[n-1];//下标是从0开始的,最后一个元素的下标是n-1
        int pos = FindIs(is, n, ls[n-1]);
        if (pos == -1) exit(1);
        s->leftchild = CreateIL(is, ls , pos);
        s->rightchild = CreateIL(is + pos + 1, ls + pos,n-pos-1);
    }
    return s;
}
//根据后序和中序可以推测出结构
BtNode* CreateBinartTreeIL(const char* is, const char* ls, int n)
{
    if (is == NULL || ls == NULL || n <= 0) return NULL;
    else return CreateIL(is,ls, n);
}
int main()
{
    char ps[] = { "ABCDEFGH" };
    char is[] = { "CBEDFAGH" };
    char ls[] = { "CEFDBHGA" };
    int n = strlen(ps);
    BinaryTree root = NULL;
    //root = CreateBinartTreePI(ps, is, n);
    root = CreateBinartTreeIL(is, ls, n);
    PreOrder(root);
    cout << endl;
    InOrder(root);
    cout << endl;
    PastOrder(root);
    cout << endl;
    return 0;
}

中序遍历(递归和非递归版本)

//中序遍历
void InOrder(BtNode* p)
{
    if (p != NULL)
    {
        InOrder(p->leftchild);
        cout << p->data << " ";
        InOrder(p->rightchild);
    }
}
void NiceInOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    std::stack<BtNode*> st;
    while (ptr != NULL || !st.empty())
    {
        while (ptr != NULL)
        {
            st.push(ptr);
            ptr = ptr->leftchild;
        }
        ptr = st.top();
        st.pop();
        cout << ptr->data;
        ptr = ptr->rightchild;
    }
}
void StkNiceInOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    stack<StkNode> st;
    st.push(StkNode(ptr));
    while (!st.empty())
    {
        StkNode node = st.top(); st.pop();
        if (++node.pos == 2)//中序遍历,当第二次出栈时打印
        {
            cout << node.pnode->data;
            if (node.pnode->rightchild != NULL)//可能还存在右子树
            {
                st.push(StkNode(node.pnode->rightchild));
            }
        }
        else
        {
            st.push(node);//记得入栈
            if (node.pnode->leftchild != NULL)
            {
                st.push(StkNode(node.pnode->leftchild));
            }
        }
    }
}

只有先序序列和后序序列是无法创建二叉树的
先序遍历(递归和非递归版本)

//先序遍历
void PreOrder(BtNode* p)
{
    if (p != NULL)
    {
        cout << p->data << " ";
        PreOrder(p->leftchild);
        PreOrder(p->rightchild);
    }
}
void NicePreOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    stack<BtNode*> st;
    st.push(ptr);
    while (!st.empty())
    {
        ptr = st.top();
        st.pop();
        cout << ptr->data;
        if (ptr->rightchild != NULL)
        {
            st.push(ptr->rightchild);
        }
        if (ptr->leftchild != NULL)
        {
            st.push(ptr->leftchild);
        }
    }
}

后序遍历的优化(递归和非递归版本)
NicePastOrder函数中元素出栈三次时,肯定左子树和右子树都访问过了,第一次将元素入栈,将元素出栈,pos值为1,再次入栈(这一步很重要),判断左子树是否存在,如果存在,将左孩子入栈,左孩子处理完毕后,再将元素出栈,pos值变为2,再次入栈(这一步很重要),判断右子树是否存在,如果存在,将右孩子入栈,右孩子处理完毕后,再将元素出栈,pos值变为3,打印该元素

//后序遍历
void PastOrder(BtNode* p)
{
    if (p != NULL)
    {
        PastOrder(p->leftchild);
        PastOrder(p->rightchild);
        cout << p->data << " ";
    }
}
void NicePastOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    std::stack<BtNode*> st;
    BtNode* tag = NULL;
    while (ptr != NULL || !st.empty())
    {
        while (ptr != NULL)
        {
            st.push(ptr);
            ptr = ptr->leftchild;
        }
        ptr = st.top();
        st.pop();
        if (ptr->rightchild == NULL || ptr->rightchild == tag)
        {
            cout << ptr->data;
            tag = ptr;
            ptr = NULL;
        }
        else
        { 
            st.push(ptr);
            ptr =ptr->rightchild;
        }
    }
}
void StkNicePastOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    stack<StkNode> st;
    st.push(StkNode(ptr));
    while (!st.empty())
    {
        StkNode node = st.top(); st.pop();
        if (++node.pos == 3)
        {
            cout << node.pnode->data;
        }
        else
        {
            st.push(node);
            if (node.pos == 1 && node.pnode->leftchild != NULL)
            {
                st.push(StkNode(node.pnode->leftchild));
            }
            else if (node.pos == 2 && node.pnode->rightchild != NULL)
            {
                st.push(StkNode(node.pnode->rightchild));
            }
        }
    }
}

层次遍历,从左往右一层一层输出

void LevelOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    queue<BtNode*> qu;
    qu.push(ptr);
    while (!qu.empty())
    {
        ptr = qu.front(); 
        qu.pop();
        cout << ptr->data;
        if (ptr->leftchild != NULL)
        {
            qu.push(ptr->leftchild);
        }
        if (ptr->rightchild != NULL)
        {
            qu.push(ptr->rightchild);
        }
    }
}

计算二叉树节点的个数count,左子树的个数+右子树的个数+1

int Count(BtNode* ptr)
{
    if (ptr == NULL) return 0;
    return Count(ptr->leftchild) + Count(ptr->rightchild) + 1;
}

计算二叉树的深度depth,左子树和右子树中深度大的+1

int Depth(BtNode* ptr)
{
    if (ptr == NULL) return 0;
    return std::max(Depth(ptr->leftchild),Depth(ptr->rightchild)) + 1;
}

Z型打印

void ZLevelOrder(BtNode* ptr)
{
    if (ptr == NULL) return;
    stack<BtNode*> ast;
    stack<BtNode*> bst;
    ast.push(ptr);
    while (!ast.empty() || !bst.empty())
    {
        while (!ast.empty())
        {
            ptr = ast.top(); ast.pop();
            cout << ptr->data;
            if (ptr->leftchild != NULL)
            {
                bst.push(ptr->leftchild);
            }
            if (ptr->rightchild != NULL)
            {
                bst.push(ptr->rightchild);
            }
        }
        while (!bst.empty())
        {
            ptr = bst.top(); bst.pop();
            cout << ptr->data;
            if (ptr->rightchild != NULL)
            {
                ast.push(ptr->rightchild);
            }
            if (ptr->leftchild != NULL)
            {
                ast.push(ptr->leftchild);
            }
        }
    }
}

判断是否是满二叉树

bool Is_FullBiary(BtNode* ptr)
{
    if (ptr == NULL) return true;//空树是满二叉树
    bool tag = true;
    queue<BtNode*> aqu;
    queue<BtNode*> bqu;
    int s = 1;
    aqu.push(ptr);
    while (!aqu.empty() || !bqu.empty())
    {
        if (aqu.size() != s)
        {
            tag = false;
            break;
        }
        while (!aqu.empty())
        {
            ptr = aqu.front(); aqu.pop();
            if (ptr->leftchild != NULL)
            {
                bqu.push(ptr->leftchild);
            }
            if (ptr->rightchild != NULL)
            {
                bqu.push(ptr->rightchild);
            }
        }
        s += s;
        if (s != bqu.size())
        {
            tag = false;
            break;
        }
        while (!bqu.empty())
        {
            ptr = bqu.front(); bqu.pop();
            if (ptr->leftchild != NULL)
            {
                aqu.push(ptr->leftchild);
            }
            if (ptr->rightchild != NULL)
            {
                aqu.push(ptr->rightchild);
            }
        }
        s += s;
    }
    return tag;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值