显示的是段错误,问题详情如下


int visit[10000]={0};
int c(LGraph Graph)
{
    visit[0]=1;
    Ptr t=Graph->G[0].FirstEdge;
    Ptr queue[10000];
    int front=0,rear=0;
    queue[rear++]=t;
    int cnt=0;
    while(front<rear){
        Ptr temp=queue[front++];
        while(temp->next){
            queue[rear++]=temp->next;
            visit[temp->next->adjV]=1;
            temp=temp->next;
        }
    }
    cnt++;
    for(int i=0;i<Graph->Nv;i++){
        if(visit[i]==0){
            Ptr t=Graph->G[i].FirstEdge;
            Ptr queue[10000];
            int front=0,rear=0;
            queue[rear++]=t;
            int cnt=0;
            while(front<rear){
                Ptr temp=queue[front++];
                while(temp->next){
                    queue[rear++]=temp->next;
                    visit[temp->next->adjV]=1;
                    temp=temp->next;
                }
            }
            cnt++;
        }
    }
    return cnt;
}

因为我现在看不了原题了所以大概回忆着写了出来,就是让求有几个强连通分量,然后数据结构是邻接表,我的思路是首先从序号为0的结点开始进行广度优先遍历,也就是层序遍历,把序号0所在的强连通分量都遍历后,我再检查所有节点中谁没被遍历过,即visit[i]==0;
然后用和上面同样的方法进行遍历
但是总是不对,显示为段错误,到底怎么回事呢?

基于Monster 组和GPT的调写:
改了改:

int visit[10000]={0};

int c(LGraph Graph)
{
    visit[0]=1;
    Ptr t=Graph->G[0].FirstEdge;
    Ptr queue[10000];
    int front=0,rear=0;
    queue[rear++]=t;
    int cnt=0;

    while(front<rear){
        Ptr temp=queue[front++];
        while(temp){
            if(!visit[temp->adjV]){
                queue[rear++]=Graph->G[temp->adjV].FirstEdge;
                visit[temp->adjV]=1;
            }
            temp=temp->next;
        }
    }

    cnt++;
    for(int i=0;i<Graph->Nv;i++){
        if(!visit[i]){
            Ptr t=Graph->G[i].FirstEdge;
            front=0,rear=0;
            queue[rear++]=t;
            cnt++;
            while(front<rear){
                Ptr temp=queue[front++];
                while(temp){
                    if(!visit[temp->adjV]){
                        queue[rear++]=Graph->G[temp->adjV].FirstEdge;
                        visit[temp->adjV]=1;
                    }
                    temp=temp->next;
                }
            }
        }
    }
    return cnt;
}


该回答引用ChatGPT

根据你的代码和描述,我猜测你在进行队列操作时可能存在越界或访问非法内存的情况,导致程序崩溃。具体来说,你在对邻接表进行遍历时,使用了两个指针 t 和 temp,但是在遍历过程中,这两个指针指向的位置可能会越界或访问非法内存,导致程序崩溃。

另外,你在内层循环中定义了一个名为 queue 的数组,这会覆盖外层循环中定义的 queue 数组,导致程序逻辑混乱。

为了解决这个问题,你可以尝试使用一维数组来实现队列,避免定义多个同名的数组。同时,建议在每次使用指针时,先检查指针是否为 NULL,以避免越界或访问非法内存的情况。例如,你可以在内层循环中使用如下代码:

while (temp != NULL) {
    if (!visit[temp->adjV]) {
        queue[rear++] = temp;
        visit[temp->adjV] = 1;
    }
    temp = temp->next;
}


此外,你需要将变量 cnt 的定义移动到循环外部,以避免在每次遍历时重置该变量。例如,可以将它定义在函数开头,然后在每次遍历后将其加 1。

最后,建议在程序开头添加头文件和命名空间,以避免一些不必要的问题。例如:


#include <iostream>
using namespace std;

以下答案基于ChatGPT与GISer Liu编写:

段错误通常是由于程序访问了无效的内存地址导致的。你的代码中,有几个问题可能导致段错误:

  1. 你在两个地方都定义了同名的队列 queue,这可能导致内存冲突。建议在函数开头定义一个队列即可。
  2. 你的 while 循环可能会访问无效的内存地址。在第一个 while 循环中,你在遍历 temp 的下一个邻接点之前,没有检查 temp 是否为 NULL。同样的问题也出现在第二个 while 循环中。如果 tempNULL,访问 temp->next 就会导致段错误。

你可以尝试在代码中添加一些断言来检查指针是否为 NULL,以及检查数组下标是否越界。同时,你也可以使用调试工具来帮助定位段错误的原因。


我在你的代码上修改了一下,标记有修复的就是改动的地方

int visit[10000] = {0};

int c(LGraph Graph)
{
    visit[0] = 1;
    Ptr t = Graph->G[0].FirstEdge;
    Ptr queue[10000];
    int front = 0, rear = 0;
    queue[rear++] = t;
    int cnt = 0;
    while (front < rear) {
        Ptr temp = queue[front++];
        while (temp->next != NULL) {  // 修复:检查下一个邻接点是否为空
            queue[rear++] = temp->next;
            visit[temp->next->adjV] = 1;
            temp = temp->next;
        }
    }
    cnt++;
    for (int i = 0; i < Graph->Nv; i++) {
        if (visit[i] == 0) {
            // 修复:重置 visit 数组
            memset(visit, 0, sizeof(visit));
            Ptr t = Graph->G[i].FirstEdge;
            Ptr queue2[10000];  // 修复:使用另一个队列
            int front2 = 0, rear2 = 0;
            queue2[rear2++] = t;
            int cnt2 = 0;  // 修复:将计数器移到 while 循环外面
            while (front2 < rear2) {
                Ptr temp = queue2[front2++];
                while (temp->next != NULL) {
                    queue2[rear2++] = temp->next;
                    visit[temp->next->adjV] = 1;
                    temp = temp->next;
                }
            }
            cnt += 1;  // 修复:累加计数器
        }
    }
    return cnt;
}


修复后的代码:

int visit[10000]={0};

int c(LGraph Graph)
{
    visit[0]=1;
    Ptr t=Graph->G[0].FirstEdge;
    Ptr queue[10000];
    int front=0,rear=0;
    queue[rear++]=t;
    int cnt=0;
    while(front<rear){
        Ptr temp=queue[front++];
        while(temp->next){
            queue[rear++]=temp->next;
            visit[temp->next->adjV]=1;
            temp=temp->next;
        }
    }
    cnt++;
    for(int i=0;i<Graph->Nv;i++){
        if(visit[i]==0){
            Ptr t=Graph->G[i].FirstEdge;
            front=0,rear=0; // 不再定义新的 queue 数组
            queue[rear++]=t;
            cnt++; // 每次发现一个未被遍历过的顶点,就增加 cnt 的值
            while(front<rear){
                Ptr temp=queue[front++];
                while(temp->next){
                    queue[rear++]=temp->next;
                    visit[temp->next->adjV]=1;
                    temp=temp->next;
                }
            }
        }
    }
    return cnt;
}

参考GPT和自己的思路,这段代码有几个问题:

在 while 循环中,将 visit[temp->next->adjV] 设为1,这样会导致某些节点被重复访问,因为一个节点可能在多条边中作为邻接点出现,所以应该将 visit[temp->next->adjV] 改为 visit[temp->adjV]。

cnt 在第一次循环外被初始化为1,但是这样会导致只统计了强连通分量的个数,而没有统计每个强连通分量中的节点数。应该在第二个 while 循环中统计每个强连通分量中的节点数,并将其累加到 cnt 中。

在第二个 while 循环中,每次循环都重新定义了一个新的 queue 数组,这样会导致第一个 queue 数组中保存的数据丢失,因此应该将 queue 数组定义在函数开头,并且在每次循环前将 front 和 rear 重置为0。

下面是修改后的代码:

int visit[10000] = {0};
int queue[10000]; // 定义队列数组
int c(LGraph Graph)
{
    int cnt = 0;
    for(int i = 0; i < Graph->Nv; i++){
        if(visit[i] == 0){
            visit[i] = 1;
            Ptr t = Graph->G[i].FirstEdge;
            int front = 0, rear = 0;
            queue[rear++] = i; // 入队
            cnt++; // 强连通分量个数加1
            while(front < rear){
                int temp = queue[front++]; // 出队
                Ptr p = Graph->G[temp].FirstEdge;
                while(p != NULL){
                    if(visit[p->adjV] == 0){ // 如果邻接点未被访问
                        visit[p->adjV] = 1;
                        queue[rear++] = p->adjV; // 入队
                    }
                    p = p->next;
                }
            }
        }
    }
    return cnt;
}

修改后的代码中,在第一个 for 循环外部定义了 queue 数组,使用 rear 和 front 来维护队列。在第二个 while 循环中,每次循环前都将 front 和 rear 重置为0,以确保每次循环时队列是空的。同时,在每个强连通分量的遍历中,使用 i 来遍历节点,而不是使用固定的 0 节点。

这样应该就能够正常地计算强连通分量了。
如果对您有帮助,请给与采纳,谢谢。


int visit[10000]={0};
int c(LGraph Graph)
{
    visit[0]=1;
    Ptr queue[10000];
    int front=0,rear=0;
    queue[rear++]=Graph->G[0].FirstEdge;
    int cnt=1;
    while(front<rear){
        Ptr temp=queue[front++];
        while(temp->next){
            if(visit[temp->next->adjV]==0){
                queue[rear++]=temp->next;
                visit[temp->next->adjV]=1;
                cnt++;
            }
            temp=temp->next;
        }
    }
    return cnt;
}