尝试将指针分配给某个对象时在 C 代码中出现分段错误

问题描述

我正在尝试用 C 语言解决一个问题。问题陈述是(阅读整个问题对我的怀疑并不重要):

给定一个由 N 个节点组成的任意无权根树。 该问题的目标是找到树中两个节点之间的最大距离。 两个节点之间的距离是节点之间路径上的边数(任何一对节点之间都会有一条唯一的路径,因为它是一棵树)。
节点将编号为 0 到 N - 1。
树作为数组 A 给出,节点 A[i] 和 i 之间有一条边(0

我创建了 TreeNode 并将所有下一个连接 TreeNode 指针存储在数组中(如图中的邻接列表)

我的解决方案是:

/**
 * @input A : Integer array
 * @input n1 : Integer array's ( A ) length
 * 
 * @Output Integer
 */
 
struct TreeNode2 {
    int value;
    struct TreeNode2 *next;
};

struct TreeNode2* createNode(int n)
{
    struct TreeNode2 *node = (struct TreeNode2 *)calloc(1,sizeof(struct TreeNode2));
    node->value = n;
    node->next = NULL;
    return node;
}

int maximum(int a,int b)
{
    if(a>b)
    return a;
    
    return b;
}

int dfs(struct TreeNode2 **tree,int node)
{
    if( tree[node] == NULL )
    return 0;
    
    int len1 = 0;
    int len2 = 0;
    
    struct TreeNode2 *ptr = tree[node];
    
    while(ptr!=NULL)
    {
        int curr = dfs(tree,(ptr->value));
        if( curr > len1 )
        {
            len1 = curr;
        }
        else if(curr > len2)
        {
            len2 = curr;
        }
        ptr = ptr->next;
    }
    return maximum( len1 + len2,maximum( len1,len2 ) + 1 );
}

int solve(int* A,int n1) 
{
    struct TreeNode2 *tree[n1];
    int i=0;
    for(i=0;i<n1;i++)
    {
        tree[i] = NULL;
    }
    for(i=0;i<n1;i++)
    {
        if(A[i] != -1)
        {
            
            struct TreeNode2 *temp = tree[i];
            struct TreeNode2 *newNode = createNode(A[i]);
            tree[i] = newNode;
            newNode->next = temp;
            
            // printf("A[i] = %d \n",A[i]);
            
            struct TreeNode2 *temp2 = tree[ A[i] ];
            struct TreeNode2 *newNode2 = createNode(i);
            tree[ A[i] ] = newNode2;
            newNode2->next = temp2;
            
        }
    }
    int ans = dfs(tree,0);
    return ans;
}

我在添加时遇到分段错误

tree[ A[i] ] = newNode2;

在 forloop 的求解函数中输入 -1,0。我试过 tree[A[i]] = NULL (它奏效了)。问题是当 A[i] = 0tree[0] = NULL 工作但 tree[0] = newNode2 不工作时,为什么。?

解决方法

从链接中,示例说明显示节点 0 有 三个 [直接] 子节点(节点,1、2、3)。


我可能错了,但我认为一个有效的算法如下:

当我们构建树时,我们记住了最大深度的节点。

树建好后,我们可以遍历它,找到任何一个[叶子]节点的最大深度,该节点不是我们在构建时找到的最大节点。

解决方案是这两个节点的深度之和


这是我为此编写的一些代码。我提交了测试输入,它通过了。

编辑:我已经修改了测试,现在它通过了所有测试,但超出了“效率”测试中的时间限制。

由于 [看似] O(n^2),我的期望也很高,但我想尝试一种不使用“已访问”的非标准方法。

我添加了一些代码来转储可以使用 graphviz 提供给 -DGRAPH 的文本文件。它产生一个输出文件:grf。要处理此问题,请执行以下操作:

dot -Tsvg < grf > grf.svg

然后,您可以将浏览器指向 grf.svg 文件以显示图表。

无论如何,这是工作但很慢的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define sysfault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

#ifndef ROOTLEAF
#define ROOTLEAF    0
#endif

#if ROOTLEAF
#define PTROK(_ptr)     (_ptr != NULL)
#else
#define PTROK(_ptr)     1
#endif

#ifdef DEBUG
#define dbgprt(_fmt...) \
    do { \
        printf(_fmt); \
    } while (0)
#define nodeshow(_node,_tag) \
    do { \
        _nodeshow(_node,_tag); \
    } while (0)
#ifndef GRAPH
#define GRAPH
#endif
#else
#define dbgprt(_fmt...) \
    do { \
    } while (0)
#define nodeshow(_node,_tag) \
    do { \
    } while (0)
#endif

#define MAXNODE     40000

#define COUNTOF(_arr) \
    (sizeof(_arr) / sizeof(_arr[0]))

typedef struct node node_t;
struct node {
    int paridx;
    int depth;

    node_t *parent;
    node_t *next;

    node_t *cldhead;
    node_t *cldtail;

    node_t *leaf;
};

static node_t *root = NULL;
static node_t *lhsbest = NULL;
static node_t *rhsbest = NULL;
static int Acnt = -1;
static node_t nodelist[MAXNODE + 1] = { 0 };
static int soldepth;
static FILE *xfgrf;

static char *
tlsbuf(void)
{
    static int bufidx = 0;
    static char buf[16][1000];
    char *bp;

    bp = buf[bufidx];
    ++bufidx;
    bufidx %= 16;

    *bp = 0;

    return bp;
}

static int
nodenum(node_t *node)
{

    if (node != NULL)
        return node - nodelist;
    else
        return -1;
}

static char *
nodexid(node_t *lhs,node_t *rhs)
{
    int lhsnum = nodenum(lhs);
    int rhsnum = nodenum(rhs);
    int tmp;
    char *buf;

    if (lhsnum > rhsnum) {
        tmp = lhsnum;
        lhsnum = rhsnum;
        rhsnum = tmp;
    }

    buf = tlsbuf();

    sprintf(buf,"%d,%d",lhsnum,rhsnum);

    return buf;
}

static void
_nodeshow(node_t *node,const char *tag)
{

#ifdef DEBUG
    if (node != NULL) {
        dbgprt("nodeshow: %s node=%d paridx=%d depth=%d\n",tag,nodenum(node),node->paridx,node->depth);
    }
    else
        dbgprt("nodeshow: %s null\n",tag);
#endif

}

// newnode -- create new node;
static node_t *
newnode(int idx,node_t *par)
{
    node_t *node;

    node = &nodelist[idx];

    if (par != NULL) {
        node->paridx = nodenum(par);
        node->depth = par->depth + 1;
    }
    else
        node->paridx = -1;

    node->parent = par;

    return node;
}

// fastfind -- find node based on i from A[i]
static node_t *
fastfind(int value)
{
    node_t *node;

    node = &nodelist[value];
    nodeshow(node,"fastfind");

    return node;
}

// addchild -- attach child node to parent
static void
addchild(node_t *par,node_t *cld)
{

    cld->next = par->cldhead;
    par->cldhead = cld;
}

int
pathok(node_t *cur)
{
    int okay;

    if (ROOTLEAF)
        okay = (cur != NULL);
    else
        okay = (cur != NULL) && (cur != root);

    return okay;
}

int
pathcost(node_t *lhs,node_t *rhs)
{
    int lhsok;
    int rhsok;
    int cost;

    dbgprt("pathcost: ENTER lhs=%d rhs=%d xid=%s\n",nodenum(lhs),nodenum(rhs),nodexid(lhs,rhs));

    cost = 0;

    if (lhs == root) {
        dbgprt("pathcost: QWKROOT\n");
        cost = rhs->depth;
        lhs = NULL;
        rhs = NULL;
    }

    while (1) {
        if ((lhs == NULL) && (rhs == NULL))
            break;

        // join at lower level than root
        if (lhs == rhs)
            break;

#ifdef DEBUG
        nodeshow(lhs,"LHS");
        nodeshow(rhs,"RHS");
#endif

        lhsok = pathok(lhs);
        rhsok = pathok(rhs);

        if (PTROK(lhs) && PTROK(rhs) && (lhs->depth > rhs->depth)) {
            //nodeshow(lhs,"LHSDEEP");

            if (lhsok) {
                cost += 1;
                dbgprt("pathcost: LCOST/D cost=%d\n",cost);
                lhs = lhs->parent;
            }

            continue;
        }

        if (PTROK(lhs) && PTROK(rhs) && (rhs->depth > lhs->depth)) {
            //nodeshow(lhs,"RHSDEEP");

            if (rhsok) {
                cost += 1;
                dbgprt("pathcost: RCOST/D cost=%d\n",cost);
                rhs = rhs->parent;
            }

            continue;
        }

        if (PTROK(lhs) && lhsok) {
            cost += 1;
            dbgprt("pathcost: LCOST/S cost=%d\n",cost);
            lhs = lhs->parent;
        }

        if (PTROK(rhs) && rhsok) {
            cost += 1;
            dbgprt("pathcost: RCOST/S cost=%d\n",cost);
            rhs = rhs->parent;
        }
    }

    dbgprt("pathcost: EXIT cost=%d\n",cost);

    return cost;
}

void
search1(void)
{
    int curcost;
    node_t *end = &nodelist[Acnt];
    node_t *leafbase = NULL;
    node_t *lhs = NULL;
    node_t *rhs = NULL;
    int bestcost = 0;
    int leafcnt = 0;

    // link all leaf nodes together
    for (rhs = nodelist;  rhs < end;  ++rhs) {
        if (ROOTLEAF) {
            if (rhs != nodelist) {
                if (rhs->cldhead != NULL)
                    continue;
            }
        }
        else {
            if (rhs->cldhead != NULL)
                continue;
        }

        nodeshow(rhs,"ISLEAF");

        if (leafbase == NULL)
            leafbase = rhs;

        if (lhs != NULL)
            lhs->leaf = rhs;

        lhs = rhs;
        ++leafcnt;
    }

    lhsbest = NULL;
    rhsbest = NULL;

    do {
        if (leafcnt == 1) {
            bestcost = leafbase->depth;
            lhsbest = leafbase;
            break;
        }

        for (lhs = leafbase;  lhs != NULL;  lhs = lhs->leaf) {
            nodeshow(lhs,"LEAFLHS");
            for (rhs = lhs->leaf;  rhs != NULL;  rhs = rhs->leaf) {
                curcost = pathcost(lhs,rhs);
                if (curcost > bestcost) {
                    lhsbest = lhs;
                    nodeshow(lhsbest,"LHSGUD");

                    rhsbest = rhs;
                    nodeshow(rhsbest,"RHSGUD");

                    bestcost = curcost;
                }
            }
        }

    } while (0);

    nodeshow(lhsbest,"LHSBEST");
    nodeshow(rhsbest,"RHSBEST");

    soldepth = bestcost;
}

int
pathcost2(node_t *lhs,node_t *rhs)
{
    int lhsok;
    int rhsok;
    int cost;

    dbgprt("pathcost2: ENTER lhs=%d rhs=%d xid=%s\n",cost);
            rhs = rhs->parent;
        }
    }

    dbgprt("pathcost2: EXIT cost=%d\n",cost);

    return cost;
}

void
search2(void)
{
    int curcost;
    node_t *end = &nodelist[Acnt];
    node_t *leafbase = NULL;
    node_t *lhs = NULL;
    node_t *rhs = NULL;
    int bestcost = 0;
    int leafcnt = 0;
    int maxdepth = 0;

    lhsbest = NULL;
    rhsbest = NULL;

    // link all leaf nodes together
    for (rhs = nodelist;  rhs < end;  ++rhs) {
        if (rhs->cldhead != NULL)
            continue;

        nodeshow(rhs,"ISLEAF");

        if (rhs->depth > maxdepth) {
            maxdepth = rhs->depth;
            rhsbest = rhs;
        }

        if (leafbase == NULL)
            leafbase = rhs;

        if (lhs != NULL)
            lhs->leaf = rhs;

        lhs = rhs;
        ++leafcnt;
    }

    do {
        bestcost = maxdepth;
        lhsbest = leafbase;

        if (leafcnt == 1) {
            bestcost = leafbase->depth;
            lhsbest = leafbase;
            break;
        }

        for (lhs = leafbase;  lhs != NULL;  lhs = lhs->leaf) {
            nodeshow(lhs,"RHSGUD");

                    bestcost = curcost;
                }
            }
        }
    } while (0);

    nodeshow(lhsbest,"RHSBEST");

    soldepth = bestcost;
}

void
dograph(void)
{
#ifdef GRAPH
    int idx;
    node_t *cur;
    node_t *par;
    char *bp;
    char buf[100];

    xfgrf = fopen("grf","w");
    fprintf(xfgrf,"digraph {\n");

    for (idx = 0;  idx < Acnt;  ++idx) {
        cur = &nodelist[idx];

        bp = buf;
        bp += sprintf(bp,"label=\"N%d D%d\"",nodenum(cur),cur->depth);
        if (cur == rhsbest)
            bp += sprintf(bp," color=Green");
        if (cur == lhsbest)
            bp += sprintf(bp," color=Red");
        fprintf(xfgrf,"\tN%d [%s]\n",buf);

        par = cur->parent;
        if (par != NULL)
            fprintf(xfgrf,"\tN%d -> N%d\n",nodenum(par),nodenum(cur));
    }

    fprintf(xfgrf,"}\n");
    fclose(xfgrf);
#endif
}

int
solve(int *A,int argcnt)
{
    int idx;
    int parval;
    node_t *par;

    if (root != NULL) {
        memset(nodelist,sizeof(nodelist));
        root = NULL;
    }

    // find the root node
    // FIXME/CAE -- probably always the first
    Acnt = argcnt;
    for (idx = 0;  idx < Acnt;  ++idx) {
        int parval = A[idx];

        if (parval == -1) {
            dbgprt("solve: ROOT idx=%d\n",idx);
            root = newnode(idx,NULL);
            break;
        }
    }

    // build all child nodes:
    for (idx = 0;  idx < Acnt;  ++idx) {
        parval = A[idx];
        if (parval == -1)
            continue;

        dbgprt("solve: NODE idx=%d parval=%d\n",idx,parval);

        // find parent
        par = fastfind(parval);

        // create node
        node_t *cur = newnode(idx,par);

        // attach child to parent
        addchild(par,cur);
    }

    // traverse all nodes in the tree to find max distance ...
    search2();

    dograph();

    return soldepth;
}
,

最后我发现了这个问题,实际上在这个问题树中,连接是无向的,所以代码卡在了 dfs 的循环中。我使用了访问数组来解决这个问题。