接着上一期更新图的类容:
1、邻接表:
2、拓扑排序:求解拓扑排序算法找出一个没有入边的顶点,输出该顶点,然后从图中删除该顶点及从它出发的所有边重复上述操作,直到图为空实现需要一个InDegree[]数组,其中存放每个顶点的入度
如:
例题:
编写程序,输入顶点个数,然后输入一个字符串表示顶点数据(顶点数据为字符);输入边的条数,然后以“a>b”的形式从输入多条有向边。读取上述输入,用邻接表存储该有向图。然后,输出该图的拓扑排序结果。例如,有向图如下:
那么应输入:
6
ABCDEF
7
A>B
A>D
B>C
B>E
C>F
D>E
E>F
输出为(有多种可能):
Toposort:ABDECF
3、代码块:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define INFINITY 32767 // 一个极大值,表示无穷
typedef struct EdgeNode {
int VertexIndex; // 顶点下标
int Weight; // 边的权值
struct EdgeNode* Next;
} EdgeNode;
typedef struct VertexEntry {
char VertexData; // 顶点数据类型为char
struct EdgeNode* EdgeList;
}VertexEntry;
typedef struct Graph {
struct VertexEntry* AdjacentList;
int VertexNum, EdgeNum; // 图的顶点数,边数
}Graph;
//创建边节点
EdgeNode* CreateEdgeNode(int VertexIndex, int Weight)
{
EdgeNode* ENode = (EdgeNode*)malloc(sizeof(EdgeNode));
ENode->Next = NULL;
ENode->VertexIndex = VertexIndex;
ENode->Weight = Weight;
return ENode;
}
//邻接表
Graph* CreateAdjacencyList()
{
int V, E,index=0, VertexIndex=0;//index为邻接表顶点下标,VertexIndex为边顶点对应邻接表顶点下标
char VArr[100];//存放顶点
char EArr[4];//存放每组边
printf("请输入顶点个数:\n");
scanf("%d", &V);
//创建空邻接表
Graph* G = (Graph*)malloc(sizeof(Graph));
G->VertexNum = V;
G->AdjacentList = (VertexEntry*)malloc(sizeof(VertexEntry) * V);
G->AdjacentList->EdgeList = (EdgeNode*)malloc(sizeof(EdgeNode));
//建立初代邻接表
printf("输入一个字符串表示顶点数据:\n");
scanf("%s", VArr);
for (int i = 0; i < (int)strlen(VArr); i++)
{
G->AdjacentList[i].VertexData= VArr[i];
G->AdjacentList[i].EdgeList = (EdgeNode*)malloc(sizeof(EdgeNode));
G->AdjacentList[i].EdgeList->Next = NULL;
}
//增加表节点
printf("请输入边个数:\n");
scanf("%d", &E);
G->EdgeNum = E;
printf("请输入对应的边:\n");
for (int i = 0; i < E; i++)
{
scanf("%s", EArr);
//下标为0为图中顶点,下标为2为与顶点相接的顶点
for (int i = 0; i < G->VertexNum; i++)//找顶点下标
{
if (G->AdjacentList[i].VertexData == EArr[0])
{
index = i;
}
if (G->AdjacentList[i].VertexData == EArr[2])
VertexIndex = i;
}
//建立邻接链
//建立边节点
EdgeNode* ENode = CreateEdgeNode(VertexIndex, 1);//权重为1
//将边节点接在邻接表上
EdgeNode* p = G->AdjacentList[index].EdgeList;
while (p->Next != NULL)//找该顶点链表的尾部
{
p = p->Next;
}
p->Next= ENode;
}
return G;
}
//打印邻接表
void print(Graph* G)
{
for (int i = 0; i < G->VertexNum; i++)
{
EdgeNode* p = G->AdjacentList[i].EdgeList;
printf("%c:", G->AdjacentList[i].VertexData);
while (p->Next != NULL)
{
printf("-->%d", p->Next->VertexIndex);
p = p->Next;
}
printf("\n");
}
}
//拓扑排序
void TopSort(Graph* G)
{
int index=-1;//记录入度为0的下标
int* degree = (int*)malloc(sizeof(int) * (G->VertexNum));//建立入度数组存放每个顶点对应的入度且保持定点下标与邻接表中顶点下标一致
char* TopOrder = (char*)malloc(sizeof(char) * G->VertexNum);//用来存放入度为零的顶点
EdgeNode* p;
//初始化入度数组
for (int i = 0; i < G->VertexNum; i++)
{
degree[i] = 0;
}
for (int i = 0; i < G->VertexNum; i++)
{
p = G->AdjacentList[i].EdgeList;
while (p->Next != NULL)
{
p = p->Next;
degree[p->VertexIndex]++;//p->VertexIndex表示该顶点所指向的顶点的下标,对应degree数组的下标
}
}
for (int i = 0; i < G->VertexNum; i++)
{
for (int j = 0; j < G->VertexNum; j++)
{
if (degree[j] == 0)
{
index = j;
break;
}
}
if (index == -1)//当index值没被改变时即图中无度为0的顶点
{
printf("图中有回路\n");
return;
}
TopOrder[i] = G->AdjacentList[index].VertexData;//将度为0的顶点存入代表删除图中该顶点
p = G->AdjacentList[index].EdgeList;
degree[index] = -1;//将删除顶点对应的入度改为-1表示已删除
while (p->Next != NULL)
{
degree[p->Next->VertexIndex]--;//将删除顶点所指向的节点的入度全部减1;
p = p->Next;
}
}
for (int i = 0; i < G->VertexNum; i++)//输出
{
printf("%c", TopOrder[i]);
}
}
int main()
{
Graph* G = CreateAdjacencyList();
printf("打印邻接表\n");
print(G);
printf("***********************************\n");
printf("Toposort:");
TopSort(G);
return 0;
}
4、运行结果:
注意:拓扑排序的结果可能有多种;编译器建议用DVC++