学习记录:二叉树

二叉树

二叉树的性质

每个节点最多都有两个子节点的树称为二叉树。其性质与定义有:

  • (i)层最多有(2^{i-1})个节点
  • 满二叉树:若每一层的节点数都是满的(都为(2^{i-1})),则为满二叉树
  • 完全二叉树:一棵满二叉树只在最后一层有缺失,则称为完全二叉树

而对于完全二叉树,它的子节点与父结点还有一种性质

  • 对于编号为(i)的节点,其父节点为(i/2)

  • 如果编号为(i)的节点有子节点,则其左节点编号为(2i)(2i+1)

    PS:编号从1开始

JaIe6x.jpg

二叉树的储存

一般用指针,和链表同理

struct node{
    int value;
    node *l,*r;
};

用数组也可以,而且能更为直观的表现完全二叉树中子节点与父节点的关系,但是要注意编号从1开始

二叉树的遍历

先用数组模拟来实现遍历,这里设二叉树为 int num[]={-1,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

广度优先遍历

void BFS(int start)
{
    queue<int> q;
    q.push(start);
    cout<<num[start]<<" ";
    while (!q.empty()){
        int t1=q.front()*2,t2=q.front()*2+1;
        if (t1<16){
            q.push(t1);
            cout<<num[t1]<<" ";
        }
        if (t2<16){
            q.push(t2);
            cout<<num[t2]<<" ";
        }
        q.pop();
    }
}

深度优先遍历

深度遍历一颗二叉树共有三种方式

  • 先序遍历:按父节点->左儿子->右儿子的顺序遍历
  • 中序遍历:按左儿子->父节点->右儿子的顺序遍历
  • 后序遍历:按左儿子->右儿子->父节点的顺序遍历

【数据结构】理解二叉树的三种遍历--前序、中序、后序 +层序(简明易懂)强烈推荐这一篇,这一篇博客写的非易懂

不难发现三种遍历其实就互相调整了一下顺序,用递归可以很简单的实现

void preorder(int root)
{
    if (root>16)
        return ;
    cout<<num[root]<<' ';
    preorder(root*2);
    preorder(root*2+1);
}
void inorder(int root)
{
    if (root>16)
        return ;
    inorder(root*2);
    cout<<num[root]<<' ';
    inorder(root*2+1);
}
void postorder(int root)
{
    if (root>16)
        return ;
    postorder(root*2);
    postorder(root*2+1);
    cout<<num[root]<<' ';
}

如果是用指针实现的,那么把退出条件改一下,root*2替换为左指针,root*2+1替换为右指针即可

根据遍历结果确定二叉树

确定二叉树的结构,需要至少两种遍历结果

  • 先序遍历+中序遍历
  • 中序遍历+后序遍历

如果是先序遍历+后序遍历则无法确定一棵二叉树,如图。这时先序遍历+后序遍历的结果相同

JdmkUf.jpg

先序遍历+中序遍历

从推荐的那篇博客,不难发现中序遍历有一个特点:对于一个节点,在中序遍历的结果中,这个节点的左边的节点在二叉树中都在原节点的左边,右边同理。(因为中序遍历可以看作二叉树的投影)

这里以hdu 1710为例,这道题就是已知先序遍历+中序遍历,求后序遍历

先序遍历:1 2 4 7 3 5 8 9 6

中序遍历:4 7 2 1 8 5 9 3 6

  1. 先序的第一个数是整个二叉树的根,再看中序,根据上面说的中序遍历特点可以把所有数字分成两块,472和85936,前者在1的右边,后者在1的左边
  2. 先序的第二个数是前一子树的根,以此类推,4 7又可以放在2的右边
  3. 递归求解,获得一棵二叉树~

JdQdNq.jpg

图示过程如上

hdu 1710代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int pre[maxn],in[maxn],pos[maxn],n,pla;
void solve(int l,int r)
{
    if (l>r) return ;
    pla++;
    if (l==r){
        printf("%d ",in[l]);
        return ;
    }
    int temp=pla;
    for (int i=l;i<=r;i++){
        if (pre[temp]==in[i]){
            solve(l,i-1);
            solve(i+1,r);
            break;
        }
    }
    printf("%d",pre[temp]);
    if (temp>1)
        printf(" ");

}
int main ()
{
    while (~scanf("%d",&n)){
        for (int i=1;i<=n;i++)
            scanf("%d",&pre[i]);
        for (int i=1;i<=n;i++)
            scanf("%d",&in[i]);
        pla=0;
        solve(1,n);
        cout<<endl;
    }
    return 0;
}

原文链接: https://www.cnblogs.com/Salty-Fish/p/12760772.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    学习记录:二叉树

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/344052

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午2:26
下一篇 2023年3月2日 上午2:27

相关推荐