2022年8月18日荣耀笔试题第三题

2022年8月18日荣耀笔试题第三题

题目描述:

C语言的结构体是C语言中最常见的一种数据结构,C语言中复合数据类型的一类。结构体是一些元素的集合,这些元素称为结构体的成员,且这些成员可以为不同的类型,也可以是其他结构体。
由于结构体是一个复杂类型,因此在代码写作中,经常需要获取到结构体占用的长度,现在仅考虑一字节对齐的情况(即结构体的总长度就等于其所有成员的长度总和),计算结构体的长度。

输入描述:

若干个结构体,结构体中成员的类型仅包含:
char(长度1)
short(长度2)
long(长度4)
其他结构体类型
不包含其他情况,格式如下(//以及后面的说明是为了解释题目,不会在输入中出现):
struct struct_a { // 1、格式为 struct + 空格 + 结构体名字 + 空格 + {
char member_a; // 2、基本数据类型成员格式为:四个空格 + 类型名称 + 空格 + 成员名字 + ;
short member_b;
long member_c;
struct struct_b member_d; // 3、结构体类型成员的格式为:四个空格 + struct + 空格 + 成员名字 + ;
}; // 4、一个结构体以 } + ; 结尾
struct struct_b {
char member_a; // 不同的结构体成员名字可以相同,比如 struct_b 和 struct_a 都可以有一个成员名字叫member_a
};
sizeof(struct struct_a) // 5、格式为 sizeof + ( + struct + 空格 + 结构体名字 + ),输入最后一行是要求计算的 结构体长度,需要根据这行指定的结构体输出结构体大小

结构体名字和成员名字是标识符,输入会确保仅包括字母,数字和下划线。
同一个结构体的成员名称之间不会重复,不同结构体的成员名称之间可能重复。
如果输入有多个结构体,第一个结构体和第二个结构体之间没有空行。
输入的每一行代码不会超过500个字符,结构体名称和成员名称不会超过50个字符。结构体的总长度不会超过10_000_000。

输出描述:

如果结构体的长度能够算出来,则直接根据输入,输出数字。比如上面输入要求sizeof(struct struct_a),代表需要输出struct_a的长度:
8
如果结构体的长度无法算出来(比如:一个结构体A的某个成员是另一个结构体B,但结构体B并未定义;或者结构体A的某个成员是结构体B,结构体B的某个成员是结构体A,导致循环依赖)则直接输出:
0

示例1
输入

struct RecordList {
    short recordListTotalValue;
    long recordListTotalPrice;
    struct RecordItem recordItem;
};
struct RecordItem {
    char nameA;
    char nameB;
    short value;
    long price;
};
sizeof(RecordList)

输出

14

示例2
输入

struct RecordList {
    short recordListTotalValue;
    long recordListTotalPrice;
    struct RecordItem recordItem;
};
sizeof(RecordList)

输出

0

【拙劣解法,欢迎指教】

思路:

构建一个有向图,每个struct看成一个图节点,struct里面包含的char、short、long成员直接累加长度,记录为节点的权值,而struct里面的struct成员则作为当前节点的邻居节点,当前节点有一条边指向它。
这样构造有向图,然后使用拓扑排序计算整个图所有节点的权值之和,同时判断图是否有环。

代码:

import java.util.*;

public class Main {
    private static final Map<String, Integer> len = new HashMap<>();

    static {
        len.put("char", 1);
        len.put("short", 2);
        len.put("long", 4);
    }
	
	// 图节点定义
    static class Node {
        int weight;
        List<String> neighbors;

        Node() {
            weight = 0;
            neighbors = new ArrayList<>();
        }
    }

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        List<String> lines = new ArrayList<>();
        String s;
        while (!(s = in.nextLine().trim()).isBlank()) {
            lines.add(s);
        }
        System.out.println(totalLength(lines));
    }

    private static int totalLength(List<String> lines) {
        Map<String, Node> graph = new HashMap<>();
        for (int i = 0; i < lines.size(); ) {
            String s1 = lines.get(i++);
            String s2;
            if (s1.startsWith("struct")) {
                String name = s1.split(" ")[1];
                graph.put(name, new Node());
                int w = 0;
                while (true) {
                    s2 = lines.get(i++);
                    if (s2.equals("};")) {
                        break;
                    }
                    if (s2.startsWith("struct")) {
                        String neighbor = s2.split(" ")[1];
                        graph.get(name).neighbors.add(neighbor);
                    } else {
                        w += len.get(s2.split(" ")[0]);
                    }
                }
                graph.get(name).weight = w;
            } else if (s1.startsWith("sizeof")) {
                return topSort(graph);
            }
        }
        return 0;
    }

    private static int topSort(Map<String, Node> graph) {
        int ans = 0;
        int count = 0;
        Set<String> nodes = graph.keySet();
        Map<String, Integer> inDegree = new HashMap<>();
        // 计算节点入度
        for (String node : nodes) {
            for (String nb : graph.get(node).neighbors) {
                if (!graph.containsKey(nb)) {
                    // 邻居节点nb没有被定义
                    return 0;
                }
                inDegree.put(nb, inDegree.getOrDefault(nb, 0) + 1);
            }
        }
        Queue<String> queue = new LinkedList<>();
        // 没有入度的节点先入队
        for (String node : nodes) {
            if (!inDegree.containsKey(node)) {
                queue.offer(node);
                ans += graph.get(node).weight;
                count++;
            }
        }
        while (!queue.isEmpty()) {
            String p = queue.poll();
            for (String nb : graph.get(p).neighbors) {
                inDegree.put(nb, inDegree.get(nb) - 1);
                if (inDegree.get(nb) == 0) {
                    queue.offer(nb);
                    ans += graph.get(nb).weight;
                    count++;
                }
            }
        }
        return count == nodes.size() ? ans : 0;
    }
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值