树的相关小测试 题解 1. 从下至上按层遍历二叉树 2. 使用前序字符串构建一个二叉树,并中序遍历这棵树。 3. 求节点的哈夫曼的带权路径长度

第一题和第三题起初想法都是构建树的相关数据结构,但通过挖掘题目的性质,尤其是输出要求,无需搭建一棵完整的树。

题意

给定一颗二叉树,要求从下至上按层遍历二叉树,每层的访问顺序是从左到右,每一层单独输出一行。输入形式为广义表,它表示的二叉树,结点元素类型为整型,且都大于0,例如:1( 2( 3 ( 4, 5 ) ), 6( 7, 8( 9, 10 ) ) )。现要你从下至上,打印每一层的结点元素值,且每层访问顺序是从左到右。

分析

题目要求的广义表输入,可以联系括号匹配。通过层数来将节点分类存储,既能够适应广义表,又能够直接层次遍历。

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int MAXN = 1e5;
string str;
vector<int> tree[MAXN]; //tree[i]表示第i层(从0计数)的一串节点
int main(){
    cin >> str;
    int dep = 0, maxdep = -1, sum = 0;
    for (int i = 0; i < (int)str.length(); i++){
        if('0' <= str[i] && str[i] <= '9'){ /*注意,输入数字不一定为个位数!*/
            sum = sum * 10 + str[i] - '0';
        } 
        else{
            if(sum > 0) tree[dep].push_back(sum);
            sum = 0; //重置sum
            if (str[i] == '(') dep++; 
            else if (str[i] == ')') dep--;
        }
        maxdep = max(maxdep, dep); //记录最大深度
    }
    for (int i = maxdep; i >= 0; i--){
        for(int j = 0; j < (int)tree[i].size(); j++)
            printf("%d ", tree[i][j]);
        printf("
");
    }
    return 0;
}

2. 使用前序字符串构建一个二叉树,并中序遍历这棵树。

题意

使用前序字符串构建一个二叉树,并输出这棵树中序遍历。字符串使用“#”表示孩子为空的情况。eg: abd#g###ce##f##

分析

题目中的前序遍历序列,与以往不同的是已经给定空节点。由此得到的序列与深搜方向基本一致(顺序不一定完全吻合),一开始对字符串向右遍历,实际上就是往树的左侧链进行遍历,一旦遍历过程中遇到#就立即转向到其兄弟节点(即右节点),继续深入搜索。

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 1e5;
string str;
char tree[MAXN];
int Build(int pos, int rt){ //pos为输入字符串的下标,rt表示当前子树的根节点
    tree[rt] = str[pos]; 
    if(str[pos] == '#') { //当str[pos]说明此时rt节点为叶节点
        tree[rt] = str[pos];
        return pos; //返回叶节点的位置,便于上一层的继续深入
    }
    int last = Build(pos + 1, rt << 1);  //建左子树,同时取得最近的叶节点对应于字符串的下标
    last = Build(last + 1, rt << 1 | 1); //建右子树,与上同理
    return last; 
}
void dfs(int rt){ //深搜得到中序遍历
    if(tree[rt] == '#' || tree[rt] == ' ') return;
    dfs(rt << 1);
    cout << tree[rt];
    dfs(rt << 1 | 1);
}
int main(){
    cin >> str;
    Build(0, 1);
    dfs(1); 
    return 0;
}

3. 求节点的哈夫曼的带权路径长度

题意

已知输入一串正整数,正整数之间用空格键分开,请建立一个哈夫曼树,以输入的数字为叶节点,求这棵哈夫曼树的带权路径长度。

分析

往上建树的模拟过程中,对每一次节点合并得到的新节点权值进行累加,其实就是对带权路径累加

#include <iostream>
#include <cstdio>
#include <vector>
#include <string>
#include <queue>
#include <algorithm>
using namespace std;
const int MAXN = 100;
priority_queue< int, vector<int>, greater<int> > myque;
int tot = 0;
int main(){
    int n; scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        int tmp; scanf("%d", &tmp);
        myque.push(tmp);
    }
    int sum = 0;
    while(myque.size() > 1){
        int lc = myque.top();
        myque.pop();
        int rc = myque.top();
        myque.pop();
        myque.push(lc + rc);
        sum += (lc + rc);
    }
    printf("%d
", sum);
}