PAT甲级【2019年3月考题】——A1159 Structure_of_a_BinaryTree【30】

本文介绍了一种通过后序和中序遍历序列重建二叉树的方法,并验证关于树结构的陈述是否正确,包括节点关系、层级、是否为完全二叉树等问题。文章提供了解决方案的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Suppose that all the keys in a binary tree are distinct positive integers. Given the postorder and inorder traversal sequences, a binary tree can be uniquely determined.

Now given a sequence of statements about the structure of the resulting tree, you are supposed to tell if they are correct or not. A statment is one of the following:

A is the root
A and B are siblings
A is the parent of B
A is the left child of B
A is the right child of B
A and B are on the same level
It is a full tree
Note:
Two nodes are on the same level, means that they have the same depth.
A full binary tree is a tree in which every node other than the leaves has two children.
Input Specification:
Each input file contains one test case. For each case, the first line gives a positive integer N (≤30), the total number of nodes in the binary tree. The second line gives the postorder sequence and the third line gives the inorder sequence. All the numbers in a line are no more than 103 10^310
3
and are separated by a space.

Then another positive integer M (≤30) is given, followed by M lines of statements. It is guaranteed that both A and B in the statements are in the tree.

Output Specification:
For each statement, print in a line Yes if it is correct, or No if not.

Sample Input:
9
16 7 11 32 28 2 23 8 15
16 23 7 32 11 2 28 15 8
7
15 is the root
8 and 2 are siblings
32 is the parent of 11
23 is the left child of 16
28 is the right child of 2
7 and 11 are on the same level
It is a full tree
Sample Output:
Yes
No
Yes
No
Yes
Yes
Yes

【声明】

  由于此题还未上PAT官网题库,故没有测试集,仅仅是通过了样例,若发现错误,感谢留言指正。

Solution:

  这道题不难,先通过后序和中序重构整颗二叉树,在重构时,使用hash表来存储每个节点值对应的节点,这样就可以解决后面询问是不是父节点和左右子节点的问题。

  然后使用DFS来遍历整棵树,得到每个节点的深度值,其中记得记录每个节点的姐妹节点是谁,并进行判断是不是完整二叉树。

  到此,对于题目中的7个问题都有相应的记录进行解决

  唯一麻烦的是,对于问题的处理,题目是输入一整句话,那么判断属于哪个问题和将其中的关键数字取出来就比较麻烦,我是使用string中的find来判断属于哪个问题,并使用循环来获取数字,当然你也可以使用istringstream函数进行切割获取数据。

#include <iostream>
#include <queue>
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;
struct Node
{
	int val;
	Node *l, *r;
	Node(int a = 0) :val(a), l(nullptr), r(nullptr) {}
};
int n, m;
bool isfullTree = true;
vector<int>post, in, siblings(1010, -1), level(1010, -1);
unordered_map<int, Node*>map;
Node* creatTree(int inL, int inR, int postL, int postR)//重建二叉树
{
	if (inL > inR)
		return nullptr;
	Node *root = new Node(post[postR]);
	map[root->val] = root;//记录节点对应的key值
	int k = inL;
	while (k <= inR && in[k] != post[postR])++k;
	int nums = k - inL;
	root->l = creatTree(inL, k - 1, postL, postL + nums - 1);
	root->r = creatTree(k + 1, inR, postL + nums, postR - 1);
	return root;
}
void DFS(Node *root, int L)
{
	if (root == nullptr)
		return;
	if ((root->l == nullptr && root->r) || (root->r == nullptr && root->l))
		isfullTree = true;//不是完全二叉树
	level[root->val] = L;//记录层数
	if (root->l&& root->r)//记录姐妹节点
	{
		siblings[root->l->val] = root->r->val;
		siblings[root->r->val] = root->l->val;
	}
	DFS(root->l, L + 1);
	DFS(root->r, L + 1);
}
vector<int> getNumber(const string &str, bool isOneNumber)//获取数据
{
	vector<int>res;
	int a = 0;
	for (int i = 0; i < str.length(); ++i)
	{
		if (isdigit(str[i]))
			a = a * 10 + str[i] - '0';
		else if (a > 0)
		{
			res.push_back(a);
			a = 0;
			if (isOneNumber || res.size() == 2)//就输出一个字符就行
				break;
		}
	}
	if (!isOneNumber && res.size() < 2)//获取处于最后的数字
		res.push_back(a);
	return res;
}
int main()
{
	cin >> n;
	post.resize(n);
	in.resize(n);
	for (int i = 0; i < n; ++i)
		cin >> post[i];
	for (int i = 0; i < n; ++i)
		cin >> in[i];
	Node *root = creatTree(0, n - 1, 0, n - 1);
	DFS(root, 1);//获取层数
	cin >> m;
	getchar();
	while (m--)
	{
		string str;
		getline(cin, str);
		if (str.find("root", 0) != -1)//查询根节点
		{
			vector<int>res = getNumber(str, true);
			if (root->val == res[0])
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("siblings", 0) != -1)//查询姐妹节点
		{
			vector<int>res = getNumber(str, false);			
			if (siblings[res[0]] == res[1])
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("parent", 0) != -1)//查询父节点
		{
			vector<int>res = getNumber(str, false);
			if ((map[res[0]]->l && map[res[0]]->l->val == res[1]) ||
				(map[res[0]]->r && map[res[0]]->r->val == res[1]))
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("left", 0) != -1)//左节点
		{
			vector<int>res = getNumber(str, false);
			if (map[res[1]]->l && map[res[1]]->l->val == res[0])
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("right", 0) != -1)//右节点
		{
			vector<int>res = getNumber(str, false);
			if (map[res[1]]->r && map[res[1]]->r->val == res[0])
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("level", 0) != -1)//同样的深度
		{
			vector<int>res = getNumber(str, false);
			if (level[res[0]]==level[res[1]])
				printf("Yes\n");
			else
				printf("No\n");
		}
		else if (str.find("full", 0) != -1)//是不是完整二叉树
		{
			if (isfullTree)
				printf("Yes\n");
			else
				printf("No\n");
		}
	}
	return 0;
}

我的代码有点繁琐,后然我逛博客发现了一个更简便的字符处理函数sscanf,还有就是由于重构二叉树的同时就是一个DFS的过程,这样我们就可以将其深度值得到。当然,我感觉我的代码还是有点优点的,不是么 ^_^.

附带博主代码:

#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<string>
#include<cstring>
#include<unordered_map>
#include<unordered_set>
using namespace std;
const int maxn=1005;
const int INF=0x3f3f3f3f;
unordered_map<int,int> level,parents;
struct node {
    int data;
    int layer;
    node *lchild,*rchild;
};
vector<int> post,in;
node* newNode(int data,int layer) {
    node* root=new node;
    root->data=data;
    root->layer=layer;
    level[data]=layer;
    root->lchild=root->rchild=NULL;
    return root;
}
bool flag=true;
node* create(int parent,int postLeft,int postRight,int inLeft,int inRight,int layer) {
    if(postLeft>postRight) return NULL;
    node* root=newNode(post[postRight],layer);
    parents[root->data]=parent;
    int index=inLeft;
    while(in[index]!=root->data) index++;
    int numLeft=index-inLeft;
    root->lchild=create(root->data,postLeft,postLeft+numLeft-1,inLeft,index-1,layer+1);
    root->rchild=create(root->data,postLeft+numLeft,postRight-1,index+1,inRight,layer+1);
    //如果有叶子,就必须有两片叶子
    if((root->lchild || root->rchild ) && (!root->lchild || !root->rchild)) flag=false;
    return root;
}
int main() {
    int n,m;
    unordered_map<int,int> ppos,ipos;
    scanf("%d",&n);
    post.resize(n);
    in.resize(n);
    for(int i=0; i<n; i++) {
        scanf("%d",&post[i]);
        ppos[post[i]]=i;
    }
    for(int i=0; i<n; i++) {
        scanf("%d",&in[i]);
        ipos[in[i]]=i;
    }
    node* root = create(n-1,0,n-1,0,n-1,0);
    scanf("%d\n",&m);
    string ask;
    for(int i=0; i<m; i++) {
        getline(cin,ask);
        int num1=0,num2=0;
        if(ask.find("root")!=string::npos) {
            sscanf(ask.c_str(),"%d is the root",&num1);
            if(ppos[num1]==n-1) puts("Yes");
            else puts("No");
        } else if(ask.find("siblings")!=string::npos) {
            sscanf(ask.c_str(),"%d and %d are siblings",&num1,&num2);
            if(level[num1]==level[num2] && parents[num1]==parents[num2]) puts("Yes");
            else puts("No");
        } else if(ask.find("parent")!=string::npos) {
            sscanf(ask.c_str(),"%d is the parent of %d",&num1,&num2);
            if(parents[num2]==num1) puts("Yes");
            else puts("No");
        } else if(ask.find("left")!=string::npos) {
            sscanf(ask.c_str(),"%d is the left child of %d",&num1,&num2);
            if(parents[num1]==num2 && ipos[num1]<ipos[num2]) puts("Yes");
            else puts("No");
        } else if(ask.find("right")!=string::npos) {
            sscanf(ask.c_str(),"%d is the right child of %d",&num1,&num2);
            if(parents[num1]==num2 && ipos[num1]>ipos[num2]) puts("Yes");
            else puts("No");
        } else if(ask.find("same")!=string::npos) {
            sscanf(ask.c_str(),"%d and %d are on the same level",&num1,&num2);
            if(level[num1]==level[num2]) puts("Yes");
            else puts("No");
        } else if(ask.find("full")!=string::npos) {
            if(flag) puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

 

<think>好的,我现在要解决的问题是用户询问如何正确编写代码行`re_A, rgb_A, binary_A = color_rgb( filename ).cuda()`。用户可能在使用某个自定义的`color_rgb`函数,并希望将返回的三个张量移动到GPU上。但当前写法可能有误,需要找出正确的写法。 首先,我需要理解这行代码的意图。`color_rgb(filename)`可能是一个自定义函数,返回三个变量:`re_A`、`rgb_A`和`binary_A`。然后用户调用了`.cuda()`方法,希望将这些变量转移到GPU。但问题在于,如果`color_rgb`返回的是一个元组或其他结构,直接调用`.cuda()`可能不会如预期那样应用到每个变量上。例如,如果`color_rgb`返回的是三个张量组成的元组,那么`.cuda()`需要分别应用到每个张量,而不是整个元组上。 接下来,我需要考虑可能的错误情况。例如,如果`color_rgb`返回的是一个包含三个张量的元组,那么`.cuda()`应用到这个元组时,会报错,因为元组没有`.cuda()`方法。正确的做法应该是对每个张量分别调用`.cuda()`,或者在函数内部处理移动。因此,用户可能需要修改函数或者在赋值后移动每个变量到GPU。 另外,用户可能期望这三个变量都是PyTorch张量,因此需要确保每个返回的值都是张量,并且正确调用了`.cuda()`方法。如果函数`color_rgb`返回的是非张量对象,比如numpy数组,那么需要先转换为张量再移动。 可能的解决方案包括: 1. 在函数返回后,对每个变量单独调用`.cuda()`。 2. 修改`color_rgb`函数,使其在返回前将每个张量移动到GPU。 3. 确保函数返回的是张量,并且正确处理了设备移动。 还需要考虑用户是否有权限修改`color_rgb`函数。如果没有,那么只能在调用后处理。如果有,那么优化函数内部可能更高效。 此外,可能需要检查是否存在其他错误,比如函数`color_rgb`是否接受`filename`参数并正确返回三个张量,是否存在导入错误或函数定义错误等。 总结可能的正确写法是,在函数返回三个张量后,分别将它们移动到GPU。例如: ```python re_A, rgb_A, binary_A = color_rgb(filename) re_A = re_A.cuda() rgb_A = rgb_A.cuda() binary_A = binary_A.cuda() ``` 或者,如果函数可以修改,在函数内部处理设备移动: ```python def color_rgb(filename): # 处理逻辑 return re_A.cuda(), rgb_A.cuda(), binary_A.cuda() ``` 同时,需要确保张量已经是PyTorch张量,否则需要先转换。例如,使用`torch.from_numpy`将numpy数组转换为张量,再调用`.cuda()`。 另外,用户可能需要使用`.to(device)`方法,以支持更灵活的设备分配,例如: ```python device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') re_A, rgb_A, binary_A = color_rgb(filename) re_A = re_A.to(device) # 同理其他变量 ``` 这样可以提高代码的可移植性,适应不同环境。 可能用户遇到的错误是直接在返回的元组上调用`.cuda()`,导致AttributeError,因为元组没有该方法。正确的做法是分别处理每个张量。 最后,可能需要建议用户检查`color_rgb`的实现,确认其返回类型是否正确,以及是否需要先转换为张量再进行设备移动。</think>以下是针对该代码的详细修正方案与技术解析: --- ### 错误诊断 原代码`re_A, rgb_A, binary_A = color_rgb(filename).cuda()`存在两个典型问题: 1. **方法调用对象错误**:`color_rgb()`若返回tuple类型,tuple对象本身没有`.cuda()`方法 2. **设备迁移顺序错误**:应先获取返回值再进行设备迁移操作 --- ### 正确实现方案 #### 场景1:函数返回PyTorch张量 ```python # 正确写法(分步操作) re_A, rgb_A, binary_A = color_rgb(filename) # 获取CPU上的张量 re_A = re_A.cuda() # 迁移到GPU rgb_A = rgb_A.cuda() binary_A = binary_A.cuda() # 精简写法(列表推导式) re_A, rgb_A, binary_A = [x.cuda() for x in color_rgb(filename)] ``` #### 场景2:函数返回非张量数据 ```python # 若返回numpy数组需先转换 import torch def color_rgb(filename): # 假设返回numpy数组 return np_array1, np_array2, np_array3 re_A, rgb_A, binary_A = color_rgb(filename) re_A = torch.from_numpy(re_A).cuda() # 先转Tensor再迁移 ``` --- ### 最佳实践建议 1. **统一设备管理**: ```python device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') re_A, rgb_A, binary_A = color_rgb(filename) re_A = re_A.to(device) # 自动适配设备 ``` 2. **函数级优化**: ```python # 修改原始函数实现 def color_rgb(filename, device='cuda'): # 数据处理逻辑 return re_A.to(device), rgb_A.to(device), binary_A.to(device) # 直接调用 re_A, rgb_A, binary_A = color_rgb(filename) # 自动返回GPU张量 ``` --- ### 错误类型对照表 | 错误代码 | 原因 | 解决方案 | |---------|------|---------| | `AttributeError: 'tuple' object has no attribute 'cuda'` | 对元组直接调用了cuda() | 对每个元素单独迁移 | | `TypeError: can't convert np.ndarray to torch.Tensor` | 未转换numpy数组 | 先执行torch.from_numpy() | --- ### 性能优化技巧 1. **并行迁移**: ```python # 使用map提高迁移效率 re_A, rgb_A, binary_A = map(lambda x: x.cuda(), color_rgb(filename)) ``` 2. **原位操作**: ```python re_A = re_A.contiguous().cuda() # 确保内存连续后迁移 ``` --- ### 完整示例代码 ```python import torch # 模拟数据生成函数 def color_rgb(filename): # 假设生成3个CPU张量 return ( torch.randn(224, 224), # re_A torch.rand(3, 224, 224), # rgb_A torch.randint(0,2,(224,224)) # binary_A ) # 正确调用流程 if __name__ == "__main__": # 方案1:分步迁移 re, rgb, binary = color_rgb("test.jpg") re = re.cuda() # 方案2:生成时直接指定设备 def optimized_color_rgb(filename): device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') return ( torch.randn(224, 224).to(device), torch.rand(3, 224, 224).to(device), torch.randint(0,2,(224,224)).to(device) ) # 验证设备信息 re_gpu, rgb_gpu, binary_gpu = optimized_color_rgb("test.jpg") print(re_gpu.device) # 输出: cuda:0 ``` --- ### 常见问题FAQ **Q1:为什么不能直接在返回结果上调用.cuda()?** 因为Python的元组对象本身没有`.cuda()`方法,该方法是PyTorch张量的成员方法 **Q2:如何批量迁移多个张量到GPU?** 推荐使用列表推导式或`map()`函数: ```python # 列表推导式方案 tensors = [t.cuda() for t in color_rgb(filename)] # map函数方案 tensors = list(map(lambda x: x.cuda(), color_rgb(filename))) ``` **Q3:迁移到GPU时出现内存不足错误怎么办?** 可尝试以下方法: 1. 使用`pin_memory`加速数据传输 2. 分批处理数据 3. 使用`torch.cuda.empty_cache()`释放显存 --- 通过上述修正方案,可以确保张量设备迁移的正确性和执行效率。建议优先采用函数内设备指定的优化方案,从数据生成源头控制设备位置,可提升整体代码的健壮性和可维护性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值