c/c++ 有向无环图 directed acycline graph
c/c++ 有向无环图 directed acycline graph
概念:
图中点与点之间的线是有方向的,图中不存在环。用邻接表的方式,实现的图。
名词:
- 顶点的入度:到这个顶点的线的数量。
- 顶点的出度:从这个顶点出发的线的数量。
实现思路:
1,计算出每个顶点的入度,存放到辅助数组cnt中
2,找到入度为0的顶点集合。
3,从入度为0的顶点集合,拿出一个顶点,这个顶点就是第一个顶点(不唯一)。
4,找到与以3处顶点为出发点的顶点,然后把这些顶点的入度减一,减一后发现如果入度为0了,更新辅助数组cnt
5,重复2-4
难点:
辅助数组cnt的作用:
- 刚开始是存放每个顶点的入度
- 找到入度为0的顶点后,入栈;出栈的元素就是找到的顶点,发现入度为0的顶点后,继续入栈,然后出栈...
辅助数组cnt的运用,建议用gdb,多debug几次,就能明白了。
图为下图1:
图1

graph_link.h
#ifndef __graph_link__
#define __graph_link__
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h>
#define default_vertex_size 10
#define T char
//边的结构
typedef struct Edge{
//顶点的下标
int idx;
//指向下一个边的指针
struct Edge* link;
}Edge;
//顶点的结构
typedef struct Vertex{
//顶点的值
T data;
//边
Edge* adj;
}Vertex;
//图的结构
typedef struct GraphLink{
int MaxVertices;
int NumVertices;
int NumEdges;
Vertex* nodeTable;
}GraphLink;
//初始化图
void init_graph_link(GraphLink* g);
//显示图
void show_graph_link(GraphLink* g);
//插入顶点
void insert_vertex(GraphLink* g, T v);
//插入边尾插
void insert_edge_tail(GraphLink* g, T v1, T v2);
//插入边头插
void insert_edge_head(GraphLink* g, T v1, T v2);
//取得指定顶点的第一个后序顶点
int get_first_neighbor(GraphLink* g, T v);
//取得指定顶点v1的临街顶点v2的第一个后序顶点
int get_next_neighbor(GraphLink* g, T v1, T v2);
//拓扑排序
void topo_sort(GraphLink* g);
#endif
graph_link.c
#include "graph_link.h"
//初始化图
void init_graph_link(GraphLink* g){
g->MaxVertices = default_vertex_size;
g->NumVertices = g->NumEdges = 0;
g->nodeTable = (Vertex*)malloc(sizeof(Vertex) * g->MaxVertices);
assert(NULL != g->nodeTable);
for(int i = 0; i < g->MaxVertices; ++i){
g->nodeTable[i].adj = NULL;
}
}
//显示图
void show_graph_link(GraphLink* g){
if(NULL == g)return;
for(int i = 0; i < g->NumVertices; ++i){
printf("%d %c->", i, g->nodeTable[i].data);
Edge* p = g->nodeTable[i].adj;
while(NULL != p){
printf("%d->", p->idx);
p = p->link;
}
printf(" NULL\n");
}
}
//插入顶点
void insert_vertex(GraphLink* g, T v){
if(g->NumVertices >= g->MaxVertices)return;
g->nodeTable[g->NumVertices++].data = v;
}
//查找顶点的index
int getVertexIndex(GraphLink* g, T v){
for(int i = 0; i < g->NumVertices; ++i){
if(v == g->nodeTable[i].data)return i;
}
return -1;
}
//创建边
void buyEdge(Edge** e, int idx){
Edge* p = (Edge*)malloc(sizeof(Edge));
p->idx = idx;
p->link = NULL;
if(NULL == *e){
*e = p;
}
else{
Edge* tmp = *e;
while(tmp->link != NULL){
tmp = tmp->link;
}
tmp->link = p;
}
}
//插入边(尾插)
void insert_edge_tail(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2);
if(p1 == -1 || p2 == -1)return;
buyEdge(&(g->nodeTable[p1].adj), p2);
g->NumEdges++;
buyEdge(&(g->nodeTable[p2].adj), p1);
g->NumEdges++;
}
//插入边(头插)
void insert_edge_head(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2);
if(p1 == -1 || p2 == -1)return;
Edge* p = (Edge*)malloc(sizeof(Edge));
p->idx = p2;
p->link = g->nodeTable[p1].adj;
g->nodeTable[p1].adj = p;
/*
p = (Edge*)malloc(sizeof(Edge));
p->idx = p1;
p->link = g->nodeTable[p2].adj;
g->nodeTable[p2].adj = p;
*/
}
//取得指定顶点的第一个后序顶点
int get_first_neighbor(GraphLink* g, T v){
int i = getVertexIndex(g, v);
if (-1 == i)return -1;
Edge* p = g->nodeTable[i].adj;
if(NULL != p)
return p->idx;
else
return -1;
}
//取得指定顶点v1的临街顶点v2的第一个后序顶点
int get_next_neighbor(GraphLink* g, T ve1, T ve2){
int v1 = getVertexIndex(g, ve1);
int v2 = getVertexIndex(g, ve2);
if(v1 == -1 || v2 == -1)return -1;
Edge* t = g->nodeTable[v1].adj;
while(t != NULL && t->idx != v2){
t = t->link;
}
if(NULL != t && t->link != NULL){
return t->link->idx;
}
return -1;
}
//拓扑排序
void topo_sort(GraphLink* g){
int n = g->NumVertices;
//表示各个顶点的入度,先都初始化为0
int* cnt = (int*)malloc(sizeof(int) * n);
assert(NULL != cnt);
for(int i = 0; i < n; ++i){
cnt[i] = 0;
}
Edge* p;
//算出各个顶点的入度
for(int i = 0; i < n; ++i){
p = g->nodeTable[i].adj;
while(p != NULL){
cnt[p->idx]++;
p = p->link;
}
}
int top = -1;
for(int i = 0; i < n; ++i){
if(cnt[i] == 0){
//入度为0的顶点入栈(模拟入栈)
cnt[i] = top; //push
top = i;
}
}
int v,w;
for(int i = 0; i < n; ++i){
if(top == -1)return;//有回路存在
v = top; //模拟出栈
top = cnt[top];
printf("%c->", g->nodeTable[v].data);
w = get_first_neighbor(g, g->nodeTable[v].data);
while(-1 != w){
if(--cnt[w] == 0){
//入度为0的顶点入栈(模拟入栈)
cnt[w] = top;
top = w;
}
w = get_next_neighbor(g,g->nodeTable[v].data,g->nodeTable[w].data);
}
}
free(cnt);
}
graph_linkmain.c
#include "graph_link.h"
int main(){
GraphLink gl;
//初始化图
init_graph_link(&gl);
//插入节点
insert_vertex(&gl, 'A');
insert_vertex(&gl, 'B');
insert_vertex(&gl, 'C');
insert_vertex(&gl, 'D');
insert_vertex(&gl, 'E');
insert_vertex(&gl, 'F');
//插入边(头插)
insert_edge_head(&gl, 'A', 'B');
insert_edge_head(&gl, 'A', 'C');
insert_edge_head(&gl, 'A', 'D');
insert_edge_head(&gl, 'C', 'B');
insert_edge_head(&gl, 'C', 'E');
insert_edge_head(&gl, 'D', 'E');
insert_edge_head(&gl, 'F', 'D');
insert_edge_head(&gl, 'F', 'E');
//显示图
show_graph_link(&gl);
//拓扑排序
topo_sort(&gl);
printf("\n");
}
编译方法:gcc -g graph_link.c graph_linkmain.c
c/c++ 有向无环图 directed acycline graph的更多相关文章
- C#实现有向无环图(DAG)拓扑排序
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在 ...
- 【学习笔记】有向无环图上的DP
手动博客搬家: 本文发表于20180716 10:49:04, 原地址https://blog.csdn.net/suncongbo/article/details/81061378 首先,感谢以下几 ...
- 大数据工作流任务调度--有向无环图(DAG)之拓扑排序
点击上方蓝字关注DolphinScheduler(海豚调度) |作者:代立冬 |编辑:闫利帅 回顾基础知识: 图的遍历 图的遍历是指从图中的某一个顶点出发,按照某种搜索方法沿着图中的边对图中的所有顶点 ...
- 图->有向无环图->拓扑排序
文字描述 关于有向无环图的基础定义: 一个无环的有向图称为有向无环图,简称DAG图(directed acycline graph).DAG图是一类较有向树更一般的特殊有向图. 举个例子说明有向无环图 ...
- 拓扑排序-有向无环图(DAG, Directed Acyclic Graph)
条件: 1.每个顶点出现且只出现一次. 2.若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面. 有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说. 一 ...
- 有向无环图的应用—AOV网 和 拓扑排序
有向无环图:无环的有向图,简称 DAG (Directed Acycline Graph) 图. 一个有向图的生成树是一个有向树,一个非连通有向图的若干强连通分量生成若干有向树,这些有向数形成生成森林 ...
- javascript实现有向无环图中任意两点最短路径的dijistra算法
有向无环图 一个无环的有向图称做有向无环图(directed acycline praph).简称DAG 图.DAG 图是一类较有向树更一般的特殊有向图, dijistra算法 摘自 http://w ...
- 算法精解:DAG有向无环图
DAG是公认的下一代区块链的标志.本文从算法基础去研究分析DAG算法,以及它是如何运用到区块链中,解决了当前区块链的哪些问题. 关键字:DAG,有向无环图,算法,背包,深度优先搜索,栈,BlockCh ...
- [转帖]MerkleDAG全面解析 一文读懂什么是默克尔有向无环图
MerkleDAG全面解析 一文读懂什么是默克尔有向无环图 2018-08-16 15:58区块链/技术 MerkleDAG作为IPFS的核心数据结构,它融合了Merkle Tree和DAG的优点,今 ...
随机推荐
- jsp、jQuery、servlet交互实现登录功能
做一个web项目,往往需要有一个登录模块,验证用户名和密码之后跳转页面.为了实现更好的交互,往往需要用到 jQuery 等实现一些友好提示.比如用户名或者密码输入为空的时候提示不能为空:点击提交的时候 ...
- Android studio 编译出现的问题记录
1.app:transformClassesWithJarMergingForDebug'. Error:Execution failed for task ':app:transformClasse ...
- JavaScript之深拷贝和浅拷贝
前言 工作中会经常遇到操作数组.对象的情况,你肯定会将原数组.对象进行‘备份’当真正对其操作时发现备份的也发生改变,此时你一脸懵逼,到时是为啥,不是已经备份了么,怎么备份的数组.对象也会发生变化.如果 ...
- Go Web:自带的ServeMux multiplexer
ServeMux简介 ServeMux扮演的角色是Multiplexer,它用来将将请求根据url路由给已注册的handler.如下图: 上图中为3个路径注册了handler,一个是"/&q ...
- linux四剑客-grep/find/sed/awk/详解-技术流ken
四剑客简介 相信接触过linux的大家应该都学过或者听过四剑客,即sed,grep,find,awk,有人对其望而生畏,有人对其爱不释手.参数太多,变化形式太多,使用超级灵活,让一部分人难以适从继而望 ...
- [Redux] redux的概述
redux 的概述 随着 javascript 单页应用的不断发展,javascript 需要管理比以往都要多的状态,管理不断变化的 state 非常困难,数据流动不断变的模糊不可预测,代码的开发与维 ...
- 南大算法设计与分析课程复习笔记(1) L1 - Model of computation
一.计算模型 1.1 定义: 我们在思考和处理算法的时候是机器无关.实现语言无关的.所有的算法运行在一种“抽象的机器”之上,这就是计算模型. 1.2 种类 图灵机是最有名的计算模型,本课使用更简单更合 ...
- MVC学习之路(1) EF 增删查改合集
首先再Model中创建一个类[WMBlogDB] public class WMBlogDB : DbContext { //连接字符串. public WMBlogDB() : base(" ...
- ___Jquery多选框的取值及反显数据
Jquery操作 ------------------------------------------------------ var arr = new Array(); $("input ...
- 使用PoolingHttpClientConnectionManager解决友盟(umeng)推送在多线程环境推送失败的问题
在友盟(umeng)提供的服务端推送的sdk中,使用的是apache提供的httpclient.在单线程化境下,httpclient工作没有问题.但是由于umeng的sdk中并未考虑并发的情况,因此很 ...