深深深深深深入虎穴

深入虎穴

比起之前的AI,这题更倾向对数据结构的理解和应用。只要抓住树的逻辑结构,并选择合适的存储结构,代码的实现并不困难
100行都没到呢,AI都几百行了!

代码实现

点击跳转:7-2 深入虎穴 (30 分)

心得

从逻辑结构入手

首先最直观的感受,是一个逻辑结构对一个算法的重要性
当确定了逻辑结构,解决问题就有了思路,不会手足无措。当我们知道这个“虎穴”应该用树存储之后,要考虑的问题就是应该用什么存储结构来表示这个树,而当存储结构定下来后,就真正进入代码实现的阶段。从结构的定义到函数的操作,一步一步往下走,一个问题自然而然就能得到解决。

灵活的存储结构

明明是一棵树,我们却没有用带两个指针的结点而是用数组存储,用一个并不匹配的存储结构表示其逻辑结构,好神奇的一件事。
不论是被否决的邻接表,还是现在的数组,都可以用来表示一棵树。所以当选择存储结构的时候,思维不能被局限了,逻辑结构和存储结构并非要完全一致
其次,我们将每个结点的指针域所指向的结构,从链表变为了数组。一开始的链表其实也可以解题,但是链表操作麻烦,而且我懒所以不喜欢链表,那么就思考能不能避免链表的出现呢?既然都是一维的数据,我们实际上是可以选择一维数组代替单链表。灵活地选择更为熟悉的结构,对我们的编程有很大的帮助。

指针的空间分配

这个程序虽然没有链表,但是结点的指针域还是用到了指针。而很多bug都来源于这些指针。(所以才不喜欢链表)
其中最常见的,是因为指针没有被分配空间,从而导致非法访问。例如程序中的结点定义

//结点定义
typedef struct {
    int num;    //门后面的门的总数
    int *p;     //指向门之后的门的编号所组成的数组
}node;

指针域中定义了一个指针,没有指定空间,所以一直是野指针。
野指针就是坏蛋,是要尽量去避免的。
在程序中,当我们输入门后面的路数量后,会给p开辟一个数组空间,然后输入数值。这个时候p就指向数组的首地址,并不是野指针呀。
这个时候就要考虑特殊情况,比如门后面的路为0的时候。这个时候我们不需要申请数组,所以实际上是不做操作,这个时候就需要额外将指针变为空指针。
空指针会比野指针友好很多。

    for (int i = 1; i <= n; i++) {
        ......
        if (a[i].num != 0) {    //如果不为0,分配空间并循环输入
            ......
        }
        else {      //如果门后没有路,就将指针置空
            a[i].p = NULL;
        }
    }

猜你喜欢

转载自www.cnblogs.com/luoyang0515/p/10771231.html