【PAT】A1102 Invert a Binary Tree (25point(s))


Author: CHEN, Yue
Organization: 浙江大学
Time Limit: 400 ms
Memory Limit: 64 MB
Code Size Limit: 16 KB

A1102 Invert a Binary Tree (25point(s))

The following is from Max Howell @twitter:

Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.

Now it’s your turn to prove that YOU CAN invert a binary tree!

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (≤10) which is the total number of nodes in the tree – and hence the nodes are numbered from 0 to N−1. Then N lines follow, each corresponds to a node from 0 to N−1, and gives the indices of the left and right children of the node. If the child does not exist, a - will be put at the position. Any pair of children are separated by a space.

Output Specification:

For each test case, print in the first line the level-order, and then in the second line the in-order traversal sequences of the inverted tree. There must be exactly one space between any adjacent numbers, and no extra space at the end of the line.

Sample Input:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

Sample Output:

3 7 2 6 4 0 5 1
6 5 7 4 3 2 0 1

Code

#include <stdio.h>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct NODE{
    int data,lchild,rchild;
};
vector<NODE> tree;
vector<int> level,in;
int havePar[20];
void inLevelOrder(int root){
    queue<int> q;
    q.push(root);
    while(!q.empty()){
        int temp=q.front();
        q.pop();
        level.push_back(temp);
        if(tree[temp].lchild!=-1)   q.push(tree[temp].lchild);
        if(tree[temp].rchild!=-1)   q.push(tree[temp].rchild);
    }
}
void inInOrder(int root){
    if(root==-1)    return;
    inInOrder(tree[root].lchild);
    in.push_back(tree[root].data);
    inInOrder(tree[root].rchild);
}
int main(){
    int n;
    char a,b;
    scanf("%d",&n);
    tree.resize(n);
    for(int i=0;i<n;i++){
        getchar();
        scanf("%c %c",&a,&b);
        tree[i].data=i;
        if(a=='-')  tree[i].rchild=-1;
        else{
            tree[i].rchild=a-'0';
            havePar[a-'0']=1;
        }
        if(b=='-')  tree[i].lchild=-1;
        else{
            tree[i].lchild=b-'0';
            havePar[b-'0']=1;
        }

    }
    for(int i=0;i<n;i++){		// 结点无父结点
        if(havePar[i]==0){
            inLevelOrder(i);
            inInOrder(i);
            break;
        }
    }
    for(int i=0;i<level.size();i++){
        if(i==0)    printf("%d",level[i]);
        else        printf(" %d",level[i]);
    }
    printf("\n");
    for(int i=0;i<in.size();i++){
        if(i==0)    printf("%d",in[i]);
        else    printf(" %d",in[i]);
    }
    return 0;
}

Analysis

-给出一棵树求其逆着的树的层序和中序遍历。

-注:我在输入时就将左右孩子互换了位置。

《编译原理》是计算机科学中一门极为重要的课程,主要探讨如何将高级程序设计语言转换成机器可执行的指令。清华大学的张素琴教授在这一领域有着深厚的学术造诣,其编译原理课后习题答案对于学习者而言是非常珍贵的资源。这份压缩文件详细解析了课程中所涉及的概念、理论和方法的实践应用,目的是帮助学生更好地理解编译器设计的核心内容。 编译原理的核心知识点主要包括以下几点: 词法分析:作为编译过程的首要环节,词法分析器会扫描源代码,识别出一个个称为“标记”(Token)的最小语法单位。通常借助正则表达式来定义各种标记的模式。 语法分析:基于词法分析产生的标记流,语法分析器依据文法规则构建语法树。上下文无关文法(CFG)是编译器设计中常用的一种形式化工具。 语义分析:这一步骤用于理解程序的意义,确保程序符合语言的语义规则。语义分析可分为静态语义分析和动态语义分析,前者主要检查类型匹配、变量声明等内容,后者则关注运行时的行为。 中间代码生成:编译器通常会生成一种高级的中间表示,如三地址码或抽象语法树,以便于后续的优化和目标代码生成。 代码优化:通过消除冗余计算、改进数据布局等方式提升程序的执行效率,同时不改变程序的语义。 目标代码生成:根据中间代码生成特定机器架构的目标代码,这一阶段需要考虑指令集体系结构、寄存器分配、跳转优化等问题。 链接:将编译后的模块进行合并,解决外部引用,最终形成一个可执行文件。 错误处理:在词法分析、语法分析和语义分析过程中,编译器需要能够检测并报告错误,例如语法错误、类型错误等。 张素琴教授的课后习题答案覆盖了上述所有核心知识点,并可能包含实际编程练习,比如实现简单的编译器或解释器,以及针对特定问题的解题策略。通过解答这些习题,学生可以加深对编译原理的理解,提升解决问题的能力,为今后参与编译器开发或软件工程实践奠定坚实的基础。这份资源不仅是学习编译原理的有力辅助材料,也是
### 处理奇异矩阵求逆的方法 当遇到需要对奇异矩阵求逆的操作时,由于奇异矩阵不存在真正的逆矩阵,因此直接调用 `np.linalg.inv` 函数将会抛出异常。为了应对这种情况,可以考虑以下几种替代方案: #### 使用伪逆矩阵 对于奇异矩阵或接近奇异的矩阵,计算其Moore-Penrose广义逆(即伪逆)是一个有效的解决方案。Numpy提供了专门用于此目的的功能——`pinv()` 方法。 ```python import numpy as np # 创建一个奇异矩阵作为例子 singular_matrix = np.array([[1, 2], [2, 4]]) try: inv_singular = np.linalg.inv(singular_matrix) except np.linalg.LinAlgError: print("Matrix is singular and cannot be inverted.") pseudo_inverse = np.linalg.pinv(singular_matrix) print(f"Pseudo inverse of the matrix:\n{pseudo_inverse}") ``` 这种方法能够返回最接近原矩阵行为的一个解,在某些应用场景下可能已经足够满足需求[^1]。 #### 添加微扰项使矩阵变为非奇异 另一种常见的做法是在原始数据上加上一个小量的身份矩阵(Identity Matrix),从而使得原本可能是零的行列式变得不等于零,进而允许对其进行常规意义上的反转操作。这通常被称为Tikhonov正则化技术的一部分。 ```python epsilon = 1e-8 * np.eye(len(singular_matrix)) regularized_matrix = singular_matrix + epsilon inverse_with_perturbation = np.linalg.inv(regularized_matrix) print(f"Inverse with perturbation added to make it non-singular:\n{inverse_with_perturbation}") ``` 通过这种方式可以在一定程度上缓解数值不稳定带来的影响,并获得近似的逆矩阵结果[^3]。 #### 应用SVD分解重构逆矩阵 如果目标仅仅是解决问题而不是严格意义上找到精确的逆,则还可以利用奇异值分解(SVD)来构建所谓的“截断”版本的逆矩阵。具体来说就是忽略那些非常小甚至为零的奇异值对应的分量,只保留较大贡献的部分来进行重建工作。 ```python U, s, Vt = np.linalg.svd(singular_matrix, full_matrices=False) threshold = 1e-10 s_inv = np.where(abs(s)>threshold, 1/s, 0.) svd_based_inverse = (Vt.T @ np.diag(s_inv) @ U.T) print(f"SVD based approximate inverse:\n{svd_based_inverse}") ``` 上述三种策略都可以有效地规避因尝试对奇异矩阵执行标准求逆而引发的各种错误情况。选择哪种取决于具体的上下文环境以及最终期望达到的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值