第五章节 树和二叉树

本文详细介绍了数据结构中的二叉树概念,包括基本性质、存储方式(顺序和链式),以及常见的遍历算法(前序、中序、后序和层序)。此外,还涵盖了Huffman树的编码和解码过程,以及森林与二叉树的转换。
摘要由CSDN通过智能技术生成

参考:1.数据结构C语言版|第2版;2.力扣;3.2024年数据结构考研复习指导。三个参考分别依次对应文章三个部分。

第一部分

基本概念

n ( n ≥ 0 ) n(n\geq0) n(n0)个结点的有限集,它或为空树 ( n = 0 ) (n=0) (n=0);或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;(2)除根结点以外的其余节点可分为 m ( m > 0 ) m(m>0) m(m>0)个互不相交的有限集 T 1 , T 2 , ⋯   , T m T_1,T_2,\cdots,T_m T1,T2,,Tm,其中每一个集合本身又是一棵树,并且称为根的子树。重要术语:孩子、双亲(PS:说双亲但是实际只有一个)、兄弟、祖先、子孙、叶子或者终端结点、内部结点或者非终端结点、结点的度、树的度、树的高度或者深度、有序树、无序树、森林。 二叉树 n ( n ≥ 0 ) n(n\geq0) n(n0)个结点所构成的集合,它或为空树 ( n = 0 ) (n=0) (n=0);或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;(2)除根结点以外的其余结点分为两个互不相交的子集 T 1 T_1 T1 T 2 T_2 T2,分别称为T的左子树和右子树,且 T 1 T_1 T1 T 2 T_2 T2本身又都是二叉树。满二叉树: 深度为k且含有 2 k − 1 2^k-1 2k1个结点的二叉树。完全二叉树: 深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。

基本性质

性质1: 在二叉树的第 i i i层上至多有 2 i − 1 2^{i-1} 2i1个结点 ( i ≥ 1 ) (i\geq1) (i1)性质2: 深度为k的二叉树至多有 2 k − 1 2^k-1 2k1个结点 ( k ≥ 1 ) (k\geq 1) (k1)性质3: 对任何一棵二叉树T,如果其终端结点数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1性质4: 具有n个结点的完全二叉树的深度为 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2^n\rfloor+1 log2n+1性质5: 如果对一棵有n个结点的完全二叉树的结点按层序编号,则对任一结点 i ( 1 ≤ i ≤ n ) i(1\leq i\leq n) i(1in),有(1)如果 i = 1 i=1 i=1,则结点 i i i是二叉树的根,无双亲;如果 i > 1 i>1 i>1,则其双亲 P A R E N T ( i ) PARENT(i) PARENT(i)是节点 ⌊ i / 2 ⌋ \lfloor i/2\rfloor i/2。(2)如果 2 i > n 2i>n 2i>n,则结点 i i i无左孩子(结点 i i i为叶子结点);否则其左孩子 L C H I L D ( i ) LCHILD(i) LCHILD(i)是结点 2 i 2i 2i。(3)如果 2 i + 1 > n 2i+1>n 2i+1>n,则结点 i i i无右孩子;否则其右孩子 R C H I L D ( i ) RCHILD(i) RCHILD(i)是结点 2 i + 1 2i+1 2i+1。(注意与代码的区别)

存储结构

顺序存储
首先用0补充成完全二叉树,然后从上到下从左只有写吧。
链式存储

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
};

经典应用1

遍历

前序遍历

递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> result;
    vector<int> preorderTraversal(TreeNode* root) {
        PreOrder(root);
        return result;
    }
    void PreOrder(TreeNode * root)
    {
        if (!root) return;
        result.push_back(root->val);
        PreOrder(root->left);
        PreOrder(root->right);
    }
};

非递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        if (!root) return result;
        stack<TreeNode *> z;
        z.push(root);result.push_back(root->val);
        while (!z.empty())
            if (z.top()->left)
            {
                TreeNode * temp=z.top()->left;z.top()->left=nullptr;
                z.push(temp);result.push_back(temp->val);
            }
            else if (z.top()->right)
            {
                TreeNode * temp=z.top()->right;z.top()->right=nullptr;
                z.push(temp);result.push_back(temp->val);
            }
            else z.pop();
        return result;
    }
};
中序遍历

递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> result;
    vector<int> inorderTraversal(TreeNode* root) {
        InOrder(root);
        return result;
    }
    void InOrder(TreeNode * root)
    {
        if (!root) return;
        InOrder(root->left);
        result.push_back(root->val);
        InOrder(root->right);
    }
};

非递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        if (!root) return result;
        stack<TreeNode *> z;
        z.push(root);
        while (!z.empty())
            if (z.top()->left)
            {
                TreeNode * temp=z.top()->left;z.top()->left=nullptr;z.push(temp);
            }
            else
            {
                result.push_back(z.top()->val);
                if (z.top()->right)
                {
                    TreeNode * temp=z.top()->right;z.pop();z.push(temp);
                }
                else z.pop();
            }
        return result;
    }
};
后序遍历

递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> result;
    vector<int> postorderTraversal(TreeNode* root) {
        PostOrder(root);
        return result;
    }
    void PostOrder(TreeNode * root)
    {
        if (!root) return;
        PostOrder(root->left);
        PostOrder(root->right);
        result.push_back(root->val);
    }
};

非递归

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        if (!root) return result;
        stack<TreeNode *> z;
        z.push(root);
        while (!z.empty())
            if (z.top()->left)
            {
                TreeNode * temp=z.top()->left;z.top()->left=nullptr;z.push(temp);
            }
            else if (z.top()->right)
            {
                TreeNode * temp=z.top()->right;z.top()->right=nullptr;z.push(temp);
            }
            else {result.push_back(z.top()->val);z.pop();}
        return result;
    }
};
层序遍历
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> lb;
        if (!root) return lb;
        queue<TreeNode *> dl;
        dl.push(root);
        while (!dl.empty())
        {
            queue<TreeNode *> temp_dl;
            vector<int> temp_lb;
            while (!dl.empty())
            {
                TreeNode * temp_node=dl.front();dl.pop();
                if (temp_node->left) temp_dl.push(temp_node->left);
                if (temp_node->right) temp_dl.push(temp_node->right);
                temp_lb.push_back(temp_node->val);
            }
            lb.push_back(temp_lb);
            dl=temp_dl;
        }
        return lb;
    }
};

建树

先序序列加上中序序列可以建立唯一的二叉树。
后序序列加上中序序列可以建立唯一的二叉树。
先序序列加上后序序列不能建立唯一的二叉树。

根据先序序列加上中序序列建立二叉树
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> lb1,lb2;
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        lb1=preorder;lb2=inorder;
        TreeNode * result=new TreeNode;
        traverse(result,0,lb1.size()-1,0,lb2.size()-1);
        return result;
    }
    void traverse(TreeNode * node,int l1,int r1,int l2,int r2)
    {
        node->val=lb1[l1];
        int m;
        for (int i=l2;i<=r2;i++)
            if (lb2[i]==node->val)
            {
                m=i;break;
            }
        if (m!=l2)
        {
            node->left=new TreeNode;
            traverse(node->left,l1+1,l1+m-l2,l2,m-1);
        }
        if (m!=r2)
        {
            node->right=new TreeNode;
            traverse(node->right,l1+m-l2+1,r1,m+1,r2);
        }
    }
};
根据后序序列加上中序序列建立二叉树
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<int> lb1,lb2;
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        lb1=postorder;lb2=inorder;
        TreeNode * result=new TreeNode;
        traverse(result,0,lb1.size()-1,0,lb2.size()-1);
        return result;
    }
    void traverse(TreeNode * node,int l1,int r1,int l2,int r2)
    {
        node->val=lb1[r1];
        int m;
        for (int i=l2;i<=r2;i++)
            if (lb2[i]==node->val)
            {
                m=i;break;
            }
        if (m!=l2)
        {
            node->left=new TreeNode;
            traverse(node->left,l1,r1-(r2-m)-1,l2,m-1);
        }
        if (m!=r2)
        {
            node->right=new TreeNode;
            traverse(node->right,r1-(r2-m),r1-1,m+1,r2);
        }
    }
};

计算

计算树的最小深度
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int minDepth(TreeNode* root) {
        if (!root) return 0;
        if (!root->left) return minDepth(root->right)+1;
        if (!root->right) return minDepth(root->left)+1;
        if (!root->left and !root->right) return 0;
        return min(minDepth(root->left),minDepth(root->right))+1;
    }
};
计算树的最大深度
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (!root) return 0;
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};

杂七杂八

线索二叉树的特点:若节点有左子树,则lchild域指示其左孩子,否则lchild指示其前驱;若节点有右子树,则rchild域指示其右孩子,否则rchild指示其后继。 注意前驱后继含义。
树的经典表示方法:
双亲表示
用node数组

struct node
{
    char s;
    int prev;
};

孩子表示
用node数组

struct next
{
    int position;
    next * brother;
};
struct node
{
    char s;
    next * child;
};

孩子表示还有一种就是用度表示那种。
孩子兄弟
二叉链表

struct node
{
    int value;
    node * firstchild;
    node * nextbrother;
};

森林转二叉树: 1.每个结点左指针指向它的从左向右的第一个孩子,右指针指向它的右兄弟。;2.第一棵树根节点的右指针指向第二棵树的根节点,以此类推。
二叉树转森林: 1.反向森林转二叉树2;2.反向森林转二叉树1。

经典应用2

Huffman树编码及其解码

输入样例

5
1 2 3 4 5
010011001011

输出样例

010
011
00
10
11
abcde
#include<iostream>
#include<vector>
#include<string>
#include<unordered_map>
using namespace std;
int n;
vector<int> lt1;
struct Node
{
    int x=-1;
    Node * l=nullptr;
    Node * r=nullptr;
};
vector<Node *> lt2;
pair<Node *,Node *> function1()
{
    vector<Node *>::iterator zz1=lt2.begin(),zz2=lt2.begin()+1;
    if ((*zz1)->x>(*zz2)->x) 
    {
        vector<Node *>::iterator zz_temp=zz1;zz1=zz2;zz2=zz_temp;
    }
    for (vector<Node *>::iterator zz3=lt2.begin()+2;zz3!=lt2.end();zz3++)
        if ((*zz3)->x<=(*zz1)->x) {zz2=zz1;zz1=zz3;}
        else if ((*zz3)->x<(*zz2)->x) zz2=zz3;
    //这样做使huffman树唯一
    Node * zz1node=*zz1;Node * zz2node=*zz2;
    bool x=zz1<zz2?1:0;
    lt2.erase(zz1);
    if (x) lt2.erase(zz2-1);
    else lt2.erase(zz2);
    if (x) return make_pair(zz1node,zz2node);
    return make_pair(zz2node,zz1node);
}
void create()
{
    for (int i=0;i<n-1;i++)
    {
        Node * nodel;Node * noder;
        pair<Node *,Node *> temp=function1();
        nodel=temp.first;noder=temp.second;
        Node * node_father=new Node;
        node_father->x=nodel->x+noder->x;
        node_father->l=nodel;
        node_father->r=noder;
        lt2.push_back(node_father);
    }
}
typedef Node * Tree;
unordered_map<int,string> zd;
//构建字典
void function2(Node * node,string s)
{
    if (node->l==nullptr and node->r==nullptr)
    {
        zd[node->x]=s;return;
    }
    if (node->l!=nullptr) function2(node->l,s+'0');
    if (node->r!=nullptr) function2(node->r,s+'1');
}
int function4(int x)
{
    for (int i=0;i<n;i++)
        if (lt1[i]==x)
            return i;
    return -1;
}
void function3(Node * node)
{
    string s;cin>>s;Node * temp=node;
    for (int i=0;i<s.size();i++)
    {
        if (s[i]=='0') temp=temp->l;
        else temp=temp->r;
        if (temp->l==nullptr and temp->r==nullptr)
        {
            int x=function4(temp->x);
            cout<<char('a'+x)<<flush;
            temp=node;
        }
    }
}
int main()
{
    //n大于等于2;
    cin>>n;
    for (int i=0;i<n;i++)
    {
        int x;cin>>x;
        lt1.push_back(x);
        Node * node=new Node;node->x=x;lt2.push_back(node);
    }
    create();
    Tree root=lt2[0];
    string s;
    function2(root,s);
    for (int x:lt1) cout<<zd[x]<<endl;
    function3(root);
    return 0;
}

感觉严书这有点乱,我是按照严书写的。

第二部分

会了上面经典应用,这一部分也就会了。
就不做其他题目了。

第三部分

老实做吧,不多评价。
PS: ⌊ l o g 2 n ⌋ + 1 = ⌈ l o g 2 n + 1 ⌉ , n ∈ N ∗ . \lfloor log_2^n \rfloor+1 =\lceil log_2^{n+1} \rceil,n\in N^*. log2n+1=log2n+1,nN.

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值