数据结构 二叉树

二叉树

二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个节点。

特殊类型

  1. 满二叉树:如果一棵二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层上,则这棵二叉树为满二叉树。
  2. 完全二叉树:深度为k,有n个节点的二叉树当且仅当其每一个节点都与深度为k的满二叉树中编号从1到n的节点一一对应时,称为完全二叉树 。
    完全二叉树的特点是叶子节点只可能出现在层序最大的两层上,并且某个节点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1。

相关术语

①节点:包含一个数据元素及若干指向子树分支的信息。
②节点的度:一个节点拥有子树的数目称为节点的度。
③叶子节点:也称为终端节点,没有子树的节点或者度为零的节点。
④分支节点:也称为非终端节点,度不为零的节点称为非终端节点 。
⑤树的度:树中所有节点的度的最大值。
⑥节点的层次:从根节点开始,假设根节点为第1层,根节点的子节点为第2层,依此类推,如果某一个节点位于第L层,则其子节点位于第L+1层。
⑦树的深度:也称为树的高度,树中所有节点的层次最大值称为树的深度。
⑧有序树:如果树中各棵子树的次序是先后次序,则称该树为有序树。
⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树 。
⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根节点删除,则该树就变成了一片森林,森林中的树由原来根节点的各棵子树构成 。

性质

性质1:二叉树的第i层上至多有2i-1(i≥1)个节点 。
性质2:深度为h的二叉树中至多含有2h-1个节点。
性质3:若在任意一棵二叉树中,有n0个叶子节点,有n2个度为2的节点,则必有n0=n2+1 。
性质4:具有n个节点的满二叉树深为log2n+1。
性质5:若对一棵有n个节点的完全二叉树进行顺序编号(1≤i≤n),那么,对于编号为i(i≥1)的节点:

当i=1时,该节点为根,它无双亲节点 。
当i>1时,该节点的双亲节点的编号为i/2 。
若2i≤n,则有编号为2i的左节点,否则没有左节点 。
若2i+1≤n,则有编号为2i+1的右节点,否则没有右节点。

遍历二叉树

遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有节点,使每一个节点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个节点转换成为一个线性序列来表示 。

1.先(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴ 访问根结点;
⑵ 遍历左子树;
⑶ 遍历右子树。
2.中(根)序遍历的递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵访问根结点;
⑶遍历右子树。
3.后(根)序遍历得递归算法定义:
若二叉树非空,则依次执行如下操作:
⑴遍历左子树;
⑵遍历右子树;
⑶访问根结点。

线索二叉树

按照某种遍历方式对二叉树进行遍历,可以把二叉树中所有节点排列为一个线性序列。在该序列中,除第一个节点外,每个节点有且仅有一个直接前驱节点;除最后一个节点外,每个节点有且仅有一个直接后继节点。但是,二叉树中每个节点在这个序列中的直接前驱节点和直接后继节点是什么,二叉树的存储结构中并没有反映出来,只能在对二叉树遍历的动态过程中得到这些信息。为了保留节点在某种遍历序列中直接前驱和直接后继的位置信息,可以利用二叉树的二叉链表存储结构中的那些空指针域来指示。这些指向直接前驱节点和指向直接后继节点的指针被称为线索(thread),加了线索的叉树称为线索二叉树 。

刷题

1.【问题描述】已知二叉树的先序遍历序列和中序遍历序列(二叉树中元素类型为字符类型,元素个数不超过20),输出该二叉树的后序遍历序列,并输出该二叉树的高度和叶子节点数

#include <iostream>
#include <string>

using namespace std;

struct TreeNode
{
    char val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(char x) : val(x), left(NULL), right(NULL) {}
};

int findInorderIndex(const string &inorder, int start, int end, char target)
{
    for (int i = start; i <= end; ++i)
    {
        if (inorder[i] == target)
        {
            return i;
        }
    }
    return -1;
}

TreeNode *buildTree(const string &preorder, int &preIndex,
                    const string &inorder, int inStart, int inEnd)
{ 
    if (preIndex >= preorder.length() || inStart > inEnd)
    {
        return NULL;
    }

    char rootValue = preorder[preIndex];
    TreeNode *root = new TreeNode(rootValue);
    preIndex++;

    int rootIndex = findInorderIndex(inorder, inStart, inEnd, rootValue);

    root->left = buildTree(preorder, preIndex, inorder, inStart, rootIndex - 1);
    root->right = buildTree(preorder, preIndex, inorder, rootIndex + 1, inEnd);

    return root;
}

string buildPostOrder(TreeNode *root)
{
    if (!root)
    {
        return "";
    }

    return buildPostOrder(root->left) + buildPostOrder(root->right) + root->val;
}

int treeHeight(TreeNode *root)
{
    if (!root)
    {
        return 0;
    }

    int leftHeight = treeHeight(root->left);
    int rightHeight = treeHeight(root->right);

    return 1 + max(leftHeight, rightHeight);
}

int leafNodeCount(TreeNode *root)
{
    if (!root)
    {
        return 0;
    }

    if (!root->left && !root->right)
    {
        return 1;
    }

    return leafNodeCount(root->left) + leafNodeCount(root->right);
}

int main()
{
    string preorder, inorder;

    cin >> preorder;

    cin >> inorder;

    int preIndex = 0;
    TreeNode *root = buildTree(preorder, preIndex, inorder, 0, inorder.length() - 1);

    string postorder = buildPostOrder(root);
    cout << postorder << endl;
    int height = treeHeight(root);
    int leafNodeCountValue = leafNodeCount(root);

    cout << height<<" "<<leafNodeCountValue<<endl;
     

    return 0;
}

2.【问题描述】已知二叉树的后序遍历序列和中序遍历序列(二叉树中元素类型为字符类型),输出该二叉树的层次遍历序列。

#include <iostream>
#include <queue>

using namespace std;

struct TreeNode
{
    char val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(char x) : val(x), left(NULL), right(NULL) {}
};

int findInorderIndex(const string &inorder, int start, int end, char target)
{
    for (int i = start; i <= end; ++i)
    {
        if (inorder[i] == target)
        {
            return i;
        }
    }
    return -1;
}

TreeNode *buildTree(const string &inorder, const string &postorder,
                    int inStart, int inEnd, int postStart, int postEnd)
{
    if (inStart > inEnd || postStart > postEnd)
    {
        return NULL;
    }

    char rootValue = postorder[postEnd];
    TreeNode *root = new TreeNode(rootValue);

    int rootIndex = findInorderIndex(inorder, inStart, inEnd, rootValue);
    int leftSubtreeSize = rootIndex - inStart;

    root->left = buildTree(inorder, postorder, inStart, rootIndex - 1,
                           postStart, postStart + leftSubtreeSize - 1);

    root->right = buildTree(inorder, postorder, rootIndex + 1, inEnd,
                            postStart + leftSubtreeSize, postEnd - 1);

    return root;
}

void levelOrderTraversal(TreeNode *root)
{
    if (!root)
    {
        return;
    }

    queue<TreeNode *> q;
    q.push(root);

    while (!q.empty())
    {
        TreeNode *current = q.front();
        q.pop();

        cout << current->val;

        if (current->left)
        {
            q.push(current->left);
        }

        if (current->right)
        {
            q.push(current->right);
        }
    }
}

int main()
{
    string inorder, postorder;

    cin >> postorder;
    cin >> inorder;

    TreeNode *root = buildTree(inorder, postorder, 0, inorder.length() - 1,
                               0, postorder.length() - 1);

    levelOrderTraversal(root);
    cout << endl;

    return 0;
}
  1. 后序遍历的非递归方式实现
#include <iostream>
#include <stack>
#include <string>

using namespace std;

struct TreeNode
{
    char val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(char x) : val(x), left(NULL), right(NULL) {}
};

TreeNode *buildTree(const string &preorder, const string &inorder,
                    int preStart, int preEnd, int inStart, int inEnd)
{
    if (preStart > preEnd || inStart > inEnd)
    {
        return NULL;
    }

    char rootValue = preorder[preStart];
    TreeNode *root = new TreeNode(rootValue);

    int rootIndex;
    for (rootIndex = inStart; rootIndex <= inEnd; ++rootIndex)
    {
        if (inorder[rootIndex] == rootValue)
        {
            break;
        }
    }

    int leftSubtreeSize = rootIndex - inStart;

    root->left = buildTree(preorder, inorder, preStart + 1, preStart + leftSubtreeSize,
                           inStart, rootIndex - 1);

    root->right = buildTree(preorder, inorder, preStart + leftSubtreeSize + 1, preEnd,
                            rootIndex + 1, inEnd);

    return root;
}

string postorderTraversal(TreeNode *root)
{
    string result;
    if (!root)
    {
        return result;
    }

    stack<TreeNode *> s;
    TreeNode *lastVisited = NULL;

    while (root || !s.empty())
    {
        while (root)
        {
            s.push(root);
            root = root->left;
        }

        TreeNode *topNode = s.top();

                if (topNode->right && topNode->right != lastVisited)
        {
            root = topNode->right;
        }
        else
        {
            result += topNode->val;
            s.pop();
            lastVisited = topNode;
        }
    }

    return result;
}

int main()
{
    string preorder, inorder;

    cin >> preorder;

    cin >> inorder;

    TreeNode *root = buildTree(preorder, inorder, 0, preorder.length() - 1,
                               0, inorder.length() - 1);

    string postorder = postorderTraversal(root);
    cout << postorder << endl;

    return 0;
}
  1. 二叉树先序遍历非递归实现
#include <iostream>
#include <stack>
#include <string>

using namespace std;

struct TreeNode
{
    char val;
    TreeNode *left;
    TreeNode *right;

    TreeNode(char x) : val(x), left(NULL), right(NULL) {}
};

TreeNode *buildTree(const string &inorder, const string &postorder,
                    int inStart, int inEnd, int postStart, int postEnd)
{
    if (inStart > inEnd || postStart > postEnd)
    {
        return NULL;
    }

    char rootValue = postorder[postEnd];
    TreeNode *root = new TreeNode(rootValue);

    int rootIndex;
    for (rootIndex = inStart; rootIndex <= inEnd; ++rootIndex)
    {
        if (inorder[rootIndex] == rootValue)
        {
            break;
        }
    }

    int leftSubtreeSize = rootIndex - inStart;

    root->left = buildTree(inorder, postorder, inStart, rootIndex - 1,
                           postStart, postStart + leftSubtreeSize - 1);

    root->right = buildTree(inorder, postorder, rootIndex + 1, inEnd,
                            postStart + leftSubtreeSize, postEnd - 1);

    return root;
}

string preorderTraversal(TreeNode *root)
{
    string result;
    if (!root)
    {
        return result;
    }

    stack<TreeNode *> s;
    s.push(root);

    while (!s.empty())
    {
        TreeNode *current = s.top();
        s.pop();

        result += current->val;

        if (current->right)
        {
            s.push(current->right);
        }

        if (current->left)
        {
            s.push(current->left);
        }
    }

    return result;
}

int main()
{
    string postorder, inorder;

    cin >> postorder;

    cin >> inorder;

    TreeNode *root = buildTree(inorder, postorder, 0, inorder.length() - 1,
                               0, postorder.length() - 1);

    string preorder = preorderTraversal(root);
    cout << preorder << endl;

    return 0;
}
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XforeverZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值