[二叉树]关于前序、中序、后序、层序序列

一些概念

满二叉树(Full Binary Tree) 和 完全二叉树(Complete Binary Tree) 是两个不同的概念


满二叉树(Full Binary Tree)->必须完全填满

  • 每个非叶子节点都有两个孩子
  • 或者说:每个节点要么是叶子节点,要么有 两个孩子
  • 举例:
        A
      /   \
     B     C
    / \   / \
   D   E F   G

完全二叉树(Complete Binary Tree)->最后一层可以不填满

  • 从上到下、从左到右依次填满
  • 只有最后一层可以不满,但必须从左往右连续填充
  • 举例:
        A
      /   \
     B     C
    / \   / 
   D   E F  

存树方式

一共n个节点
开一个数组int tree[n<<2] 4倍大小
node<<1表示左子树
node<<1|1表示右子树

tree[]中存的就是层序序列

GPT的介绍

✅ 哪些组合能唯一建树?

提供的遍历 是否能唯一建树? 说明
中序 + 前序 ✅ 能 最常见、能唯一建树
中序 + 后序 ✅ 能 也可以唯一建树
前序 + 后序 ❌ 一般不行 除非是满二叉树才行
只有一种遍历 ❌ 不能 信息不够,多种可能的树

必须有一个中序序列 才能唯一确定一颗二叉树

那如果是“完全二叉树”呢?

如果你明确知道这棵树是完全二叉树,那情况就不一样了:

✅ 只要你给出:
  • 前序遍历 + 完全二叉树信息 可以唯一建树
  • 后序遍历 + 完全二叉树信息 可以唯一建树
  • 中序遍历 + 完全二叉树信息 可以唯一建树
  • 层序遍历 本身就能唯一确定完全二叉树

完全二叉树的关键特点是:节点编号是固定的!

比如:

1 -> root
2 -> left of root
3 -> right of root
4 -> left of node 2
...

这就是你前面用 node<<1node<<1|1 的核心!


✅ 小结

遍历方式 是否能唯一建树?
前序+中序 / 中序+后序
层序 + 完全二叉树
前序/后序 + 完全二叉树结构
只有一种遍历
前序+后序 ❌(除非满二叉树)

如何通过给定的序列确定一颗树?

一、中序+X

  • X要么是先序 要么是后序
  • 核心就是通过X确定根在哪里
  • 再从中序中找到根的位置
  • 左右两边就是左右子树 再递归左右两边建树

1.中序+后序->先序

const int N = 10;
int in[N],post[N],tree[N<<2];
int n;

//inl表示当前子树在中序序列中的起点 postl 后序序列起点 
//len表示当前子树长度 (节点个数)
//pos用来分配节点在tree数组中的下标(pos<<1 左子树,pos<<1|1 右子树)
void build(int inl,int postl,int len,int pos){
    int root = post[postl+len-1];
    tree[pos]=root;

    if(len==1) return;

    int i=0;
    while(in[inl+i]!=root) i++;//在中序序列中找到根的下标
    int l=i,r=len-i-1;//l,r为左右子树长度
    //左右子树非空就递归建树
    if(l) build(inl, postl,l,pos<<1);
    if(r) build(inl+l+1,postl+l,r,pos<<1|1);
}

void preprint(int node){
    if(node>n*4||tree[node]==0){
        return;
    }
    cout<<(char)(tree[node]-1+'A');
    preprint(node<<1);
    preprint(node<<1|1);
}

void solve(){
    string s;cin>>s;
    for(int i=0;i<s.size();i++){
        in[i]=s[i]-'A'+1;
    }
    cin>>s;
    for(int i=0;i<s.size();i++){
        post[i]=s[i]-'A'+1;
    }
    n=s.size();
    build(0,0,n,1);

    preprint(1);
}

中序+先序->后序

const int N = 2010;
int tree[N<<2],pre[N],in[N];
int n;

void build(int inl,int prel,int len,int pos){
    int root=pre[prel];
    tree[pos]=root;

    if(len==1) return;
    int i=0;

    while(in[inl+i]!=root) i++;
    int l=i,r=len-i-1;
    if(l) build(inl,prel+1,l,pos<<1);
    if(r) build(inl+l+1,prel+l+1,r,pos<<1|1);
}

void postprint(int node){
    if(tree[node]==-1){
        return;
    }

    postprint(node<<1);
    postprint(node<<1|1);
    cout<<(char)(tree[node]-1+'A');
}

void solve(){
    string s;
    while(cin>>s){
        n=s.size();
        memset(tree,-1,sizeof tree);
        memset(pre,0,sizeof pre);
        memset(in,0,sizeof in);

        for(int i=0;i<s.size();i++){
            pre[i]=s[i]-'A'+1;
        }
        cin>>s;
        for(int i=0;i<s.size();i++){
            in[i]=s[i]-'A'+1;
        }

        build(0,0,n,1);
        postprint(1);
        cout<<endl;
    }
}

二、给定完全二叉树+某一种序列

#include 
#include 
#include 
using namespace std;

const int MAXN = 2005;
char tree[MAXN];  // 用数组模拟树,编号从1开始
string s;         // 前序输入的字符串(含#)
int pos;          // 当前在字符串中处理到的位置

// 建树,参数是当前处理到的节点编号
void build(int node) {
    if (pos >= s.size()) return;

    if (s[pos] == '#') {
        pos++; // 空节点,跳过
        return;
    }

    tree[node] = s[pos++]; // 建立当前节点
    build(node << 1);      // 左儿子
    build(node << 1 | 1);  // 右儿子
}

// 中序遍历
void inOrder(int node) {
    if (tree[node] == 0) return;
    inOrder(node << 1);
    cout << tree[node];
    inOrder(node << 1 | 1);
}

// 后序遍历
void postOrder(int node) {
    if (tree[node] == 0) return;
    postOrder(node << 1);
    postOrder(node << 1 | 1);
    cout << tree[node];
}

// 层序遍历
void levelOrder(int root) {
    queue<int> q;
    if (tree[root]) q.push(root);
    while (!q.empty()) {
        int u = q.front(); q.pop();
        cout << tree[u];
        if (tree[u << 1]) q.push(u << 1);
        if (tree[u << 1 | 1]) q.push(u << 1 | 1);
    }
}

void levelOrder(){//这样也可以 因为tree中存的就是层序序列
	int n=s.size();
    for(int i=1;i<n*4;i++){
        if(tree[i]) cout<<tree[i];
    }
}
int main() {
    while (cin >> s) {
        memset(tree, 0, sizeof(tree));
        pos = 0;
        build(1); // 从1号节点开始建树
        inOrder(1);
        cout << " ";
        postOrder(1);
        cout << " ";
        levelOrder(1);
        cout << endl;
    }
    return 0;
}

先序

void build(int node) {
    if (pos >= s.size()) return;

    if (s[pos] == '#') {
        pos++; // 空节点,跳过
        return;
    }

    tree[node] = s[pos++]; // 建立当前节点
    build(node << 1);      // 左儿子
    build(node << 1 | 1);  // 右儿子
}

中序

gpt写的 不太懂

string in;
int tree[N<<2];
int build( int& index, int l, int r) {
    if (l > r) return -1; // 递归出口
    
    // 选择当前节点
    int mid = (l + r) / 2;
    if (in[mid] == '#') {
        return -1; // 当前节点为空
    }

    // 生成当前节点,并填充到树中
    int node = index++;
    tree[node] = in[mid] - '0'; // 假设树节点的值为数字字符

    // 递归构建左子树
    int left = build(index, l, mid - 1);

    // 递归构建右子树
    int right = build(index, mid + 1, r);

    return node;
}

你可能感兴趣的:(算法,二叉树,树,数据结构,c++)