Date Structure: Graph --- Represent graph structure with adjacency list

Date Structure: Graph

Represent graph structure with adjacency list

Basical Structure

/* ---- 邻接表实现图 ---- */
#pragma once
#include "Head.h"
#include "Stack.h"
#include <iostream>

#define MAX_VERTEX_NUM 20// 最大顶点个数
#define VertexType char  //点类型

typedef enum
{
	DG,
	DN,
	UDG,
	UDN
} GraphKind;// 四种图类型

typedef struct ArcNode//边结构体
{
	int adjvex;             // 该弧所指向的顶点的位置
	struct ArcNode* nextarc;//指向下一条弧的指针
	int weight;             //权重
} ArcNode;

typedef struct VNode//顶点结构体
{
	VertexType data;  // 顶点信息
	ArcNode* firstarc;//指向第一条依附该顶点的弧的指针
} VNode, AdjList[MAX_VERTEX_NUM];

typedef struct//图结构体
{
	AdjList vertices;  // 顶点向量
	int vexnum, arcnum;// 图的当前顶点数和弧数
	GraphKind Kind;    // 图的种类标志
} ALGraph;

Create

/*---- 几种不同类型的图的构建 ----*/
void CreateALGraph(ALGraph& ALG);

void CreateDG(ALGraph& ALG);//构造有向图 G

void CreateDN(ALGraph& ALG);//构造有向网 G(即有权的图)

void CreateUDG(ALGraph& ALG);//构造无向图 G

void CreateUDN(ALGraph& ALG);//构造无向网 G(即有权的图)

void CreateALGraph(ALGraph& ALG)
{
	printf("请输入构造图的类型: \n");
	std::string temp;
	std::cin >> temp;
	if (temp == "DG")
		ALG.Kind = DG;
	else if (temp == "DN")
		ALG.Kind = DN;
	else if (temp == "UDG")
		ALG.Kind = UDG;
	else if (temp == "UDN")
		ALG.Kind = UDN;
	switch (ALG.Kind)
	{
	case DG:
		CreateDG(ALG);
		return;//构造有向图 ALG
	case DN:
		CreateDN(ALG);
		return;//构造有向网 ALG(即有权的图)
	case UDG:
		CreateUDG(ALG);
		return;//构造无向图 ALG
	case UDN:
		CreateUDN(ALG);
		return;//构造无向网 ALG(即有权的图)
	}
}

//构造有向网 G(即有权的图)
void CreateDN(ALGraph& ALG)
{
	InitALGraph(ALG);
	int from, to, value;
	ArcNode* q;
	std::cout << "请输入顶点数和边数: \n";
	std::cin >> ALG.vexnum >> ALG.arcnum;
	std::cout << "读入顶点信息,建立顶点表: \n";

	for (int i = 0; i < ALG.vexnum; i++)//读入顶点信息,建立顶点表
		std::cin >> ALG.vertices[i].data;
	std::cout << "输入边(Vi,Vj)上的下标i, 下标j, 权w: \n";

	for (int i = 0; i < ALG.arcnum; i++)
	{
		std::cin >> from >> to >> value;

		ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = to;
		p->weight = value;
		p->nextarc = NULL;

		if (ALG.vertices[from].firstarc)
		{
			for (q = ALG.vertices[from].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[from].firstarc = p;
	}
}

//构造有向图 G
void CreateDG(ALGraph& ALG)
{
	InitALGraph(ALG);
	int from, to;
	ArcNode* q;
	std::cout << "请输入顶点数和边数: \n";
	std::cin >> ALG.vexnum >> ALG.arcnum;
	std::cout << "读入顶点信息,建立顶点表: \n";

	for (int i = 0; i < ALG.vexnum; i++)//读入顶点信息,建立顶点表
		std::cin >> ALG.vertices[i].data;
	std::cout << "输入边(Vi,Vj)上的下标i, 下标j\n";

	for (int i = 0; i < ALG.arcnum; i++)
	{
		std::cin >> from >> to;

		ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = to;
		p->weight = 1;//单纯的有向图权重为1, 表示这两个顶点是连接着的.
		p->nextarc = NULL;

		if (ALG.vertices[from].firstarc)
		{
			for (q = ALG.vertices[from].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[from].firstarc = p;
	}
}

//构造无向图 G, 通过测试
void CreateUDG(ALGraph& ALG)
{
	InitALGraph(ALG);
	int from, to;
	ArcNode* q;
	std::cout << "请输入顶点数和边数: \n";
	std::cin >> ALG.vexnum >> ALG.arcnum;
	std::cout << "读入顶点信息,建立顶点表: \n";

	for (int i = 0; i < ALG.vexnum; i++)//读入顶点信息,建立顶点表
		std::cin >> ALG.vertices[i].data;
	std::cout << "输入边(Vi,Vj)上的下标i, 下标j\n";

	for (int i = 0; i < ALG.arcnum; i++)
	{
		std::cin >> from >> to;

		ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = to;
		p->weight = 1;//单纯的有向图权重为1, 表示这两个顶点是连接着的.
		p->nextarc = nullptr;

		if (ALG.vertices[from].firstarc)
		{
			for (q = ALG.vertices[from].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[from].firstarc = p;

		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = from;
		p->weight = 1;
		p->nextarc = nullptr;

		if (ALG.vertices[to].firstarc)
		{
			for (q = ALG.vertices[to].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[to].firstarc = p;
	}
}

//构造无向网 G(即有权的图)
void CreateUDN(ALGraph& ALG)
{
	InitALGraph(ALG);
	int from, to, value;
	ArcNode* q;
	std::cout << "请输入顶点数和边数: \n";
	std::cin >> ALG.vexnum >> ALG.arcnum;
	std::cout << "读入顶点信息,建立顶点表: \n";

	for (int i = 0; i < ALG.vexnum; i++)//读入顶点信息,建立顶点表
		std::cin >> ALG.vertices[i].data;
	std::cout << "输入边(Vi,Vj)上的下标i, 下标j, 权w: \n";

	for (int i = 0; i < ALG.arcnum; i++)
	{
		std::cin >> from >> to >> value;

		ArcNode* p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = to;
		p->weight = value;
		p->nextarc = NULL;

		if (ALG.vertices[from].firstarc)
		{
			for (q = ALG.vertices[from].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[from].firstarc = p;

		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = from;
		p->weight = value;
		p->nextarc = NULL;

		if (ALG.vertices[to].firstarc)
		{
			for (q = ALG.vertices[to].firstarc; q->nextarc; q = q->nextarc)
				;
			q->nextarc = p;
		}
		else
			ALG.vertices[to].firstarc = p;
	}
}

Predecessor-free vertex-first algorithm

/* ---- [无前趋的顶点优先算法] ---- */
void FindInDegree(ALGraph ALG, int indegree[]);

void FindOutDegree(ALGraph ALG, int outdegree[]);

int TopologicalSort(ALGraph ALG);

//计算各个节点的入度
void FindInDegree(ALGraph ALG, int indegree[])
{
	ArcNode* q;
	for (int i = 0; i < ALG.vexnum; i++)
		for (q = ALG.vertices[i].firstarc; q; q = q->nextarc)
			indegree[q->adjvex]++;
}

//计算各个顶点的出度
void FindOutDegree(ALGraph ALG, int outdegree[])
{
	ArcNode* q;
	for (int i = 0; i < ALG.vexnum; i++)
		for (q = ALG.vertices[i].firstarc; q; q = q->nextarc)
			outdegree[i]++;
}

//无前趋的顶点优先算法
int TopologicalSort(ALGraph ALG)
{
	int indegree[MAX_VERTEX_NUM] = {0};
	FindInDegree(ALG, indegree);//求各顶点入度
#if TEST
	//检查计算各个顶点的入度是否正确
	printf("检查入度是否正确: \n") for (int i = 0; i < ALG.vexnum; i++)
	                std::cout
	        << ALG.vertices[i].data << " " << indegree[i] << std::endl;
	printf("\n");
#endif

	SqStack<int> S{};
	InitStack(S);
	for (int i = 0; i < ALG.vexnum; i++)
		if (!indegree[i])
			Push(S, i);//如果某个顶点的入度为0, 将其入栈

	int temp;
	int count = 0;
	while (!StackEmpty(S))
	{
		Pop(S, temp);
#if TEST
		printf("顶点编号: %d 顶点值: %c\n", temp, ALG.vertices[temp].data);
#endif
		++count;
		for (ArcNode* p = ALG.vertices[temp].firstarc; p; p = p->nextarc)
		{
			temp = p->adjvex;       //修改入度
			if (!(--indegree[temp]))//入度为0, 则入栈
				Push(S, temp);
		}
	}

	if (count < ALG.vexnum)
		return -1;
	else
		return 1;
}

AOE Graph

/* ---- AOE图 ---- */
int TopologicalOrder(ALGraph ALG, SqStack<int>& T, int eventEarly[]);

int CriticalPath(ALGraph ALG);

//并用栈T返回G的一个拓扑序列
int TopologicalOrder(ALGraph ALG, SqStack<int>& T, int eventEarly[])
{
	int indegree[MAX_VERTEX_NUM] = {0};
	FindInDegree(ALG, indegree);//求各顶点入度

	//初始化
	for (int i = 0; i < ALG.vexnum; i++)
		eventEarly[i] = 0;

	SqStack<int> S{};
	InitStack(S);
	for (int i = 0; i < ALG.vexnum; i++)
		if (!indegree[i])
			Push(S, i);//如果某个顶点的入度为0, 将其入栈

	int temp;
	int count = 0;
	int k;
	while (!StackEmpty(S))
	{
		Pop(S, k);
		Push(T, k);//将节点入栈
		//下面有一行代码用于输出序列
		//printf("顶点编号: %d 顶点字符: %c\n", k, ALG.vertices[k].data);
		++count;
		for (ArcNode* p = ALG.vertices[k].firstarc; p; p = p->nextarc)
		{
			temp = p->adjvex;       //修改入度
			if (!(--indegree[temp]))//入度为0, 则入栈
				Push(S, temp);
			eventEarly[temp] = MAX(eventEarly[k] + p->weight, eventEarly[temp]);
		}
	}

#if TEST//检验所求的eventEarly数组的值是否正确
	printf("检验所求的eventEarly数组的值是否正确: \n");
	for (int i = 0; i < ALG.vexnum; i++)
		std::cout << ALG.vertices[i].data << ' ' << eventEarly[i] << std::endl;
#endif
	if (count < ALG.vexnum)
		return -1;
	else
		return 1;
}

//找关键路径.
int CriticalPath(ALGraph ALG)
{
	/** @brief
	 * 求事件vj(即节点 j )的最早发生时间eventEarly[j] \n
	 * eventEarly(0) = 0 \n
	 * eventEarly(j) = max{ eventEarly(i) + dut<i,j> }, i是j的前驱 \n
	 * eventEarly的初始值全部为0 \n
	 * */
	int eventEarly[MAX_VERTEX_NUM] = {0};

	/** @brief
	 * 求事件vj(即节点 j)的最早发生时间eventLast[j] \n
	 * eventLast[n-1] = eventEarly[n-1] \n
	 * eventLast(j) = min{ eventLast(k) - dut<j, k> }, k是j的后继 \n
	 * eventLast的初始值全部为对应的eventEarly \n
	 * */
	int eventLast[MAX_VERTEX_NUM] = {0};

	for (int i = 0; i < MAX_VERTEX_NUM; i++)
		eventEarly[i] = 0;
	SqStack<int> T{};
	TopologicalOrder(ALG, T, eventEarly);

	//寻找出度为0的节点, 其即为AOE的汇点, 并将其eventLast赋值为 对应的eventEarly
	int outdegree[MAX_VERTEX_NUM];
	for (int i = 0; i < ALG.vexnum; i++)
		outdegree[i] = 0;
	FindOutDegree(ALG, outdegree);
	int end;
	for (int i = 0; i < ALG.vexnum; i++)
		if (outdegree[i] == 0)
		{
			end = i;
			break;
		}
	for (int i = 0; i < MAX_VERTEX_NUM; i++)
		eventLast[i] = INF;
	eventLast[end] = eventEarly[end];

	//计算eventLast[]
	int j;
	int k;
	ArcNode* p;
	Pop(T, j);//将end弹出来
	while (!StackEmpty(T))
	{
		Pop(T, j);
		for (p = ALG.vertices[j].firstarc; p; p = p->nextarc)
		{
			k = p->adjvex;
			eventLast[j] = MIN(eventLast[j], eventLast[k] - p->weight);
		}
	}


#if TEST//检验所求的eventLast数组和eventEarly数组是否正确
	printf("\n");
	printf("检查: eventLast 和 eventEarly\n");
	for (int i = 0; i < ALG.vexnum; i++)
		printf("%c eventEarly: %d, eventLsat: %d\n", ALG.vertices[i].data, eventEarly[i], eventEarly[i]);
#endif


	/**@brief
	 * (边)的edgeEarly, edgeLast \n
	 * j -> k, 则这条边 \n
	 * edgeEarly = eventEarly[j] \n
	 * edgeLast = eventLsat[k] - dut<j, k> \n
	 * */
	int dut;
	int edgeEarly, edgeLast;
	char tag;
	for (j = 0; j < ALG.vexnum; j++)
	{
		for (p = ALG.vertices[j].firstarc; p; p = p->nextarc)
		{
			k = p->adjvex, dut = p->weight;
			edgeEarly = eventEarly[j];
			edgeLast = eventLast[k] - dut;
			tag = (edgeEarly == edgeLast) ? '*' : ' ';
			printf("%c -> %c: weight: %d edgeEarly: %d, edgeLast: %d %c\n", ALG.vertices[j].data, ALG.vertices[k].data, dut, edgeEarly, edgeLast, tag);
			//std::cout << j << "->" << k << ' ' << dut << ' ' << edgeEarly << ' ' << edgeLast << ' ' << tag << std::endl;
		}
	}
	return 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值