You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言带权双向图输入异常问题求助

带权无向图C程序输入问题修复方案

你编写的带权无向图C程序编译正常,但存在三个核心问题:

  • 部分节点无法正常插入,邻接链表丢失已有节点
  • 输入错误检测不完整(负数顶点、非法输入未处理)
  • 同一顶点对的无向边会被重复添加,无法正确检测重复

以下是问题根源分析及修复方案:


1. 核心问题:isPresent函数破坏邻接链表结构

你的isPresent函数直接修改了图的邻接链表头指针,导致每次调用后,原链表的头节点丢失,后续无法访问已插入的节点,也无法正确检测重复边:

// 错误的实现
int isPresent(graph_t* g1, int source, int key)
{
    graph_t* gTmp = g1;
    while(gTmp->adjList[source] != NULL)
    {
      if(gTmp->adjList[source]->key == key)
      {
          printf("Key in Common: %d\n", key);
          return 1;
      }
        gTmp->adjList[source] = gTmp->adjList[source]->next; // 修改了原链表头
    }
    return 0;
}

修复方法:使用临时指针遍历链表,不修改原链表的头指针:

int isPresent(graph_t* g1, int source, int key)
{
    node_t* curr = g1->adjList[source]; // 用临时指针遍历
    while(curr != NULL)
    {
      if(curr->key == key)
      {
          printf("Found duplicate edge %d-%d\n", source, key);
          return 1;
      }
        curr = curr->next;
    }
    return 0;
}

2. 输入验证逻辑不完整

当前输入验证仅检查顶点索引小于nV,未覆盖以下场景:

  • 顶点索引为负数(如输入-1作为source)
  • 用户重新输入后未再次验证合法性
  • scanf输入失败(如输入字母)时,输入缓冲区残留垃圾数据导致死循环

修复方法:完善输入验证逻辑,添加负数检查、重复验证,处理非法输入:
修改main函数中的输入循环部分:

for(int i = 0; i < nV; i++)
{
    int source = -1, key = -1, weight = 0;
    printf("\nInsert edge %d: enter Source, Key and Weight: ", i+1);
    
    // 处理输入格式错误
    while(scanf("%d %d %d", &source, &key, &weight) != 3) {
        while(getchar() != '\n'); // 清空输入缓冲区垃圾
        printf("Invalid input, please enter three integers: ");
    }

    // 验证source合法性(非负+不越界)
    while(source < 0 || source >= nV){
        printf("Source Out of Bounds (0-%d), retry: ", nV-1);
        while(scanf("%d", &source) != 1) {
            while(getchar() != '\n');
            printf("Invalid input, enter a valid source: ");
        }
    }

    // 验证key合法性
    while(key < 0 || key >= nV){
        printf("Key Out of Bounds (0-%d), retry: ", nV-1);
        while(scanf("%d", &key) != 1) {
            while(getchar() != '\n');
            printf("Invalid input, enter a valid key: ");
        }
    }

    // 检测重复边,重新输入后再次验证合法性
    while(isPresent(graph, source, key) == 1)
    {
        printf("Edge already exists, enter new source and key: ");
        while(scanf("%d %d", &source, &key) != 2) {
            while(getchar() != '\n');
            printf("Invalid input, enter two integers: ");
        }
        // 重新验证新输入的source和key
        while(source < 0 || source >= nV){
            printf("Source Out of Bounds (0-%d), retry: ", nV-1);
            while(scanf("%d", &source) != 1) {
                while(getchar() != '\n');
                printf("Invalid input, enter a valid source: ");
            }
        }
        while(key < 0 || key >= nV){
            printf("Key Out of Bounds (0-%d), retry: ", nV-1);
            while(scanf("%d", &key) != 1) {
                while(getchar() != '\n');
                printf("Invalid input, enter a valid key: ");
            }
        }
    }

    addEdge(graph, source, key, weight);
    printf("\nCurrent graph state:\n");
    printGraph(graph);
}

3. 补充:无向边自环处理

原addEdge函数在添加自环(source=key)时会重复添加两条相同的边,需添加判断避免:

void addEdge(graph_t* graph, int src, int key, int w) {
    // Add edge from src to key
    node_t* newN = newNode(key);
    newN->weight = w;
    newN->next = graph->adjList[src];
    graph->adjList[src] = newN;

    // Add edge from key to src (仅当不是自环时添加)
    if(src != key) {
        node_t* newN2 = newNode(src);
        newN2->weight = w;
        newN2->next = graph->adjList[key];
        graph->adjList[key] = newN2;
    }
}

修复后的完整代码

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

typedef struct node {
    int key;
    int weight;
    struct node* next;
} node_t;

typedef struct graph {
    int V;
    node_t** adjList;
} graph_t;

node_t* newNode(int dest);
graph_t* createGraph(int V);
void addEdge(graph_t* graph, int src, int key, int w);
void printGraph(graph_t* graph);
int isPresent(graph_t* g, int source, int key);

int main() {
    int nV = 0;
    printf("Insert number of vertices (nV): ");
    while(scanf("%d", &nV) != 1 || nV <= 0) {
        while(getchar() != '\n');
        printf("Invalid input, enter a positive integer: ");
    }

    graph_t* graph = createGraph(nV);

    for(int i = 0; i < nV; i++)
    {
        int source = -1, key = -1, weight = 0;
        printf("\nInsert edge %d: enter Source, Key and Weight: ", i+1);
        
        while(scanf("%d %d %d", &source, &key, &weight) != 3) {
            while(getchar() != '\n');
            printf("Invalid input, please enter three integers: ");
        }

        while(source < 0 || source >= nV){
            printf("Source Out of Bounds (0-%d), retry: ", nV-1);
            while(scanf("%d", &source) != 1) {
                while(getchar() != '\n');
                printf("Invalid input, enter a valid source: ");
            }
        }

        while(key < 0 || key >= nV){
            printf("Key Out of Bounds (0-%d), retry: ", nV-1);
            while(scanf("%d", &key) != 1) {
                while(getchar() != '\n');
                printf("Invalid input, enter a valid key: ");
            }
        }

        while(isPresent(graph, source, key) == 1)
        {
            printf("Edge already exists, enter new source and key: ");
            while(scanf("%d %d", &source, &key) != 2) {
                while(getchar() != '\n');
                printf("Invalid input, enter two integers: ");
            }
            while(source < 0 || source >= nV){
                printf("Source Out of Bounds (0-%d), retry: ", nV-1);
                while(scanf("%d", &source) != 1) {
                    while(getchar() != '\n');
                    printf("Invalid input, enter a valid source: ");
                }
            }
            while(key < 0 || key >= nV){
                printf("Key Out of Bounds (0-%d), retry: ", nV-1);
                while(scanf("%d", &key) != 1) {
                    while(getchar() != '\n');
                    printf("Invalid input, enter a valid key: ");
                }
            }
        }

        addEdge(graph, source, key, weight);
        printf("\nCurrent graph state:\n");
        printGraph(graph);
    }
    printf("\n=== Final Graph ===\n");
    printGraph(graph);
    return 0;
}

node_t* newNode(int dest) {
    node_t* newNode = (node_t*) malloc(sizeof(node_t));
    newNode->key = dest;
    newNode->weight = 0;
    newNode->next = NULL;
    return newNode;
}

graph_t* createGraph(int V) {
    graph_t* graph = (graph_t*) malloc(sizeof(graph_t));
    graph->V = V;
    graph->adjList = (node_t**) malloc(V * sizeof(node_t*));
    int i;
    for (i = 0; i < V; i++) {
        graph->adjList[i] = NULL;
    }
    return graph;
}

void addEdge(graph_t* graph, int src, int key, int w) {
    node_t* newN = newNode(key);
    newN->weight = w;
    newN->next = graph->adjList[src];
    graph->adjList[src] = newN;

    if(src != key) {
        node_t* newN2 = newNode(src);
        newN2->weight = w;
        newN2->next = graph->adjList[key];
        graph->adjList[key] = newN2;
    }
}

int isPresent(graph_t* g1, int source, int key)
{
    node_t* curr = g1->adjList[source];
    while(curr != NULL)
    {
        if(curr->key == key)
        {
            printf("Found duplicate edge %d-%d\n", source, key);
            return 1;
        }
        curr = curr->next;
    }
    return 0;
}

void printGraph(graph_t* graph) {
    int i;
    for (i = 0; i < graph->V; i++) {
        node_t* currNode = graph->adjList[i];
        printf("Vertex %d: ", i);
        if(currNode == NULL) {
            printf("No adjacent vertices\n");
            continue;
        }
        while (currNode != NULL) {
            printf("%d(W:%d) ", currNode->key, currNode->weight);
            currNode = currNode->next;
        }
        printf("\n");
    }
}

修复后效果

  • 邻接链表不再丢失节点,所有插入的边能正确显示
  • 可检测重复无向边并阻止添加
  • 输入验证覆盖负数、越界、非法输入场景
  • 自环不会被重复添加

内容的提问来源于stack exchange,提问作者N0ZER0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:37:08