图 ->拓扑排序

                    

_________<备份>___________


//输入n和m,以及m个二元组(i,j),求1~n的一个排列使得对于每个(i,j),i在j的前面
// 算法:拓扑排序。注意m可能等于0


// 题意:输入n和m,以及m个二元组(i,j),求1~n的一个排列使得对于每个(i,j),i在j的前面
// 算法:拓扑排序。注意m可能等于0
#include<cstdio>
#include<cstring>
const int maxn = 1000;
int n, m, G[maxn][maxn], c[maxn], topo[maxn], t;

bool dfs(int u){
  c[u] = -1;
  for(int v = 0; v < n; v++) if(G[u][v]) {
    if(c[v]<0) return false;
    else if(!c[v]) dfs(v);
  }
  c[u] = 1; topo[--t]=u;
  return true;
}

bool toposort(){
  t = n;
  memset(c, 0, sizeof(c));
  for(int u = 0; u < n; u++) if(!c[u])
    if(!dfs(u)) return false;
  return true;
}

int main() {
  while(scanf("%d%d", &n, &m) == 2 && n) {
    memset(G, 0, sizeof(G));
    for(int i = 0; i < m; i++) {
      int u, v;
      scanf("%d%d", &u, &v); u--; v--;
      G[u][v] = 1;
    }
    if(toposort()) {
      for(int i = 0; i < n-1; i++)
        printf("%d ", topo[i]+1);
      printf("%d\n", topo[n-1]+1);
    }
    else
      printf("No\n"); // 
  }
}


你提供的输入和运行现象表明:**程序在拓扑排序输出过程中出现了逻辑错误,导致顺序混乱、甚至访问越界或崩溃**。特别是最后的输出: ``` 高等数学 -->线性代数 -->普通物理 -->计算机原理 -->程序设计基础 -->离散数学 -->数据结构 --> 操作系统 -->汇编语言 -->语言的设计与分析 -->编译原理 -->数值分析 --> ``` 这个序列 **不合法**!例如: - “操作系统” 出现在 “汇编语言” 前面? - 但 “汇编语言 → 语言的设计与分析” 是边,说明“汇编语言”必须先于“语言的设计与分析”,而中间却夹着“操作系统”? 这说明你的拓扑排序算法存在严重问题。 --- ## 🔍 问题定位:核心错误在于 `Top_Sort` 中对 `indegree` 的滥用 我们回顾原代码中的 `Top_Sort` 关键片段: ```c for (i = 0; i < G->vertexNum; i++) { if (G->adjlist[i].indegree == 0) { G->adjlist[i].indegree = top; top = i; } } ``` 这段代码的意思是: > 把所有入度为 0 的顶点用 `indegree` 字段链接成一个栈(链式栈),其中 `indegree[i]` 存放下一个节点索引。 ❌ **这是致命错误**! 因为 `indegree[i]` 原本是用来表示“有多少条边指向该顶点”的重要字段。一旦你把它改成下一个节点下标,就彻底丢失了原始入度信息! 后续遍历邻接点时再做 `G->adjlist[k].indegree--`,已经不是真正的“入度减一”,而是对“栈指针”进行减法运算 —— 导致不可预测的行为(如负数跳转、非法内存访问)! --- ### 💥 具体现象解释 你在输入完边之后运行程序,可能遇到以下情况之一: 1. 输出顺序明显违反依赖关系(如上面所示); 2. 程序崩溃(segmentation fault); 3. 死循环或漏掉某些节点; 这些都是因为: > ✅ **你在破坏性地复用了 `indegree` 字段作为栈链指针,导致拓扑排序逻辑错乱** --- ## ✅ 正确解决方案:使用局部数组保存入度 + 链式栈技巧 我们应该保留原始 `indegree` 数据,并使用一个临时数组来模拟栈结构。 --- ### ✅ 修改后的正确 `Top_Sort` 函数(推荐) ```c void Top_Sort(ALGraph *G) { int indegree[MaxVertexNum]; // 局部数组,保存每个顶点当前入度 int stack = -1; // 链式栈头指针(存顶点下标) int i, j, k, count = 0; EdgeNode *p; // 1. 初始化局部入度数组 for (i = 0; i < G->vertexNum; i++) { indegree[i] = G->adjlist[i].indegree; } // 2. 将所有入度为0的顶点压入链式栈(利用 indegree 数组空间存 next 指针) for (i = 0; i < G->vertexNum; i++) { if (indegree[i] == 0) { indegree[i] = stack; // 当前节点指向原栈顶 stack = i; // 更新栈顶为当前节点 } } printf("构造的一个拓扑序列为:\n"); // 3. 开始出栈处理 while (stack != -1) { j = stack; stack = indegree[j]; // 弹出栈顶元素 if (count > 0) printf(" -> "); printf("%s", G->adjlist[j].vertex); count++; // 4. 遍历 j 的所有邻接点,入度减一 for (p = G->adjlist[j].firstedge; p; p = p->next) { k = p->adjvertex; indegree[k]--; // 入度减一 if (indegree[k] == 0) { indegree[k] = stack; // 入栈:新节点指向当前栈顶 stack = k; // 更新栈顶 } } } // 5. 判断是否所有顶点都输出了 if (count < G->vertexNum) { printf("\nThe network has a cycle!\n"); } else { printf("\n拓扑排序完成。\n"); } } ``` --- ## 🧩 同时确保 `CreateALGraph` 中正确计算 `indegree` 你需要在建完成后,手动初始化每个顶点的 `indegree` 字段。 修改 `CreateALGraph` 的末尾部分: ```c // 原有代码…… for (k = 0; k < G->edgeNum; k++) { scanf("%s%s", v1, v2); i = FindVertexIndex(G, v1); j = FindVertexIndex(G, v2); if (i == -1 || j == -1) { printf("输入的顶点名称无效!\n"); exit(1); } p = (EdgeNode *)malloc(sizeof(EdgeNode)); p->adjvertex = j; p->next = G->adjlist[i].firstedge; G->adjlist[i].firstedge = p; } // === 新增:初始化所有顶点的入度为0 === for (i = 0; i < G->vertexNum; i++) { G->adjlist[i].indegree = 0; } // === 新增:统计每个顶点的入度 === for (i = 0; i < G->vertexNum; i++) { for (p = G->adjlist[i].firstedge; p; p = p->next) { G->adjlist[p->adjvertex].indegree++; } } } ``` > ⚠️ 删除原来的 `FindInDegree()` 函数,因为它不再需要。 --- ## ✅ 输入验证建议:防止缓冲区溢出 你输入的课程名较长(如“程序设计基础”),应限制读取长度以避免溢出: ```c scanf("%19s", G->adjlist[i].vertex); // 最多读19字符 ``` 同理: ```c scanf("%19s%19s", v1, v2); ``` --- ## ✅ 正确的拓扑序列应该是怎样的?(基于你的) 我们分析关键依赖: - 必须先学“程序设计基础”才能学“数据结构” - “数据结构” → “编译原理”、“操作系统”、“语言的设计与分析” - “高等数学” → “线性代数”、“普通物理”、“数值分析” - “普通物理” → “计算机原理” → “操作系统” - 所以合理顺序中,“高等数学”必须最早出现之一,“程序设计基础”也应在前期 ✅ 合理拓扑序列示例(一种可能): ``` 高等数学 -> 线性代数 -> 普通物理 -> 程序设计基础 -> 离散数学 -> 数据结构 -> 汇编语言 -> 计算机原理 -> 语言的设计与分析 -> 编译原理 -> 操作系统 -> 数值分析 ``` 注意:“数值分析”有多前置条件(程序设计基础、高等数学、线性代数),所以它只能出现在最后。 --- ## ❌ 错误输出原因总结 你原来输出中出现: ``` ... --> 操作系统 --> 汇编语言 --> ... ``` 但“汇编语言”是“语言的设计与分析”的前驱,“操作系统”依赖“数据结构”和“计算机原理”,显然不能让“操作系统”出现在“汇编语言”之前(除非无直接依赖),但更严重的是: > ⚠️ 由于 `indegree` 被当作栈使用,实际处理顺序完全被打乱,可能是随机访问! --- ## ✅ 最终修复步骤清单 | 步骤 | 操作 | |------|------| | 1 | 删除 `FindInDegree()` 函数 | | 2 | 在 `CreateALGraph` 结尾添加入度统计 | | 3 | 修改 `Top_Sort` 使用局部 `indegree[]` 数组模拟栈 | | 4 | 使用 `%19s` 防止输入溢出 | | 5 | 添加 `DestroyGraph()` 释放内存(可选但推荐) | --- ## ✅ 示例输出(修复后) ``` 请输入顶点数和边数: 12 16 请输入顶点表(按顺序输入12个顶点名称): 程序设计基础 离散数学 数据结构 汇编语言 语言的设计与分析 计算机原理 编译原理 操作系统 高等数学 线性代数 普通物理 数值分析 请输入边<Vi,Vj>(共16条边): 程序设计基础 离散数学 程序设计基础 数据结构 ... 构造的一个拓扑序列为: 高等数学 -> 线性代数 -> 普通物理 -> 程序设计基础 -> 离散数学 -> 数据结构 -> 汇编语言 -> 计算机原理 -> 语言的设计与分析 -> 编译原理 -> 操作系统 -> 数值分析 拓扑排序完成。 ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值