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;
段错误通常是由于程序访问了无效的内存地址导致的。你的代码中,有几个问题可能导致段错误:
queue
,这可能导致内存冲突。建议在函数开头定义一个队列即可。while
循环可能会访问无效的内存地址。在第一个 while
循环中,你在遍历 temp
的下一个邻接点之前,没有检查 temp
是否为 NULL
。同样的问题也出现在第二个 while
循环中。如果 temp
为 NULL
,访问 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;
}