Skip to content

2023年 408 数据结构 第 41 题

数据结构2023年综合题10分

题目

已知有向图 G 采用邻接矩阵存储,类型定义如下:

c
typedef struct {                    // 图的类型定义
    int  numVertices, numEdges;     // 图中顶点数和有向边数
    char VerticesList[MAXV];        // 顶点表,MAXV 为已定义常量
    int  Edge[MAXV][MAXV];          // 邻接矩阵
} MGraph;

将图中出度大于入度的顶点称为 K 顶点。例如在题 41 图中,顶点 a 和 b 都是 K 顶点。

abdc

设计算法 int printVertices(MGraph G):对给定任意非空有向图 G,输出 G 中所有 K 顶点,并返回 K 顶点的个数。要求:

(1) 给出算法的设计思想。

(2) 根据算法思想,写出 C/C++ 描述,并注释。

解析

(1) 设计思想

答案:扫一遍邻接矩阵,同时统计每个顶点的出度数组 outDeg[] 和入度数组 inDeg[];再扫一遍顶点表,输出所有 outDeg[i] > inDeg[i] 的顶点,并计数返回。

邻接矩阵 Edge[i][j] != 0 表示存在弧 ,对应:

  • 顶点 出度加 1(i 行某个非 0 项)
  • 顶点 入度加 1(j 列某个非 0 项)

所以一次双重 for 循环就能同时统计所有顶点的入出度。

示例验证:题面给的图中,a → b、a → d、b → d、b → c、c → d,逐个计数:

顶点出度入度出 > 入?
a20✓ K
b21✓ K
c11
d03

K 顶点 = {a, b},与题面一致。

(2) 代码实现

c
#define MAXV 100

typedef struct {
    int  numVertices, numEdges;
    char VerticesList[MAXV];
    int  Edge[MAXV][MAXV];
} MGraph;

int printVertices(MGraph G) {
    int n = G.numVertices;
    int outDeg[MAXV] = {0};
    int inDeg [MAXV] = {0};
    int count = 0;

    // ① 一次双重扫描,同时统计每个顶点的出度和入度
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (G.Edge[i][j] != 0) {
                outDeg[i]++;       // i 出 1 条边
                inDeg [j]++;       // j 入 1 条边
            }

    // ② 扫一遍顶点,输出所有 K 顶点
    for (int i = 0; i < n; i++)
        if (outDeg[i] > inDeg[i]) {
            printf("%c ", G.VerticesList[i]);
            count++;
        }

    return count;
}

关键点说明

  • 一次双重循环就够,不需要分别扫两次。第一次扫行得出度、第二次扫列得入度是低效写法;用一次循环 + 两个累加器同时记录更省事,复杂度同为 O(n²) 但常数减半。
  • 输出"顶点"不是"下标":返回值是 K 顶点个数,但题目要求"输出 G 中所有 K 顶点",所以打印时用 G.VerticesList[i](顶点名),不要直接打印下标 i。
  • 复杂度:时间 O(n²),主要在双重扫描(与邻接矩阵的存储规模相当,已是该存储下的下界);空间 O(n),两个度数组。
  • 若改为邻接表存储:出度天然容易(一个顶点的邻接链表长度),但入度需要倒过来扫所有链表,复杂度变为 O(n + e)。本题给定邻接矩阵,O(n²) 反而是最自然写法。

最后更新:

🎬 可视化演示
加载中...

提示:可在可视化区直接操作播放、步进、修改参数