1、十字链表代码实现:
crossLinkGraph.h
#ifndef CROSS_LINK_GRAPH_H
#define CROSS_LINK_GRAPH_H
/* 十字链表的图表示法,将邻接表和逆邻接表整合在一个顶点描述的结构上
* 方便查找图中出度和入度
* */
// 十字链表的边的结构
typedef struct arcBox {
int tailVertex; // 弧尾编号,出度的信息
struct arcBox *tailNext; // 下一个弧尾,下一个出度
int headVertex; // 弧头编号,入度的信息
struct arcBox *headNext; // 下一个弧头,下一个入度
int weight; // 弧的权重
}ArcBox;
// 十字链表的顶点结构
typedef struct {
int no; //顶点的编号
const char *show; //图中顶点的显示数据(比如V1,V2,V3),指针指向了一个常量空间,考试时可以不用写
ArcBox *firstIn; // 该节点的入度
ArcBox *firstOut; // 该节点的出度
}CrossVertex;
// 十字链表的图结构
typedef struct {
CrossVertex *nodes; //顶点集
int numVertex; //顶点数
int numEdge; //边数
}CrossGraph;
// 产生n个节点的十字链表
CrossGraph *createCrossGraph(int n);
void releaseCrossGraph(CrossGraph *graph);
// 初始化图,设置节点信息
void initCrossGraph(CrossGraph *graph, int num, char *names[]);
// 添加边,从tail走向head
void addCrossArc(CrossGraph *graph, int tail, int head, int w);
// 计算no编号节点的入度
int inDegreeCrossGraph(CrossGraph *graph, int no);
// 计算no编号节点的出度
int outDegreeCrossGraph(CrossGraph *graph, int no);
#endif
crossLinkGraph.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "crossLinkGraph.h"
// 产生n个节点的十字链表
CrossGraph *createCrossGraph(int n) {
CrossGraph *graph = (CrossGraph *) malloc(sizeof(CrossGraph));
graph->nodes = (CrossVertex *) malloc(sizeof(CrossVertex) * n);
graph->numVertex = n;
graph->numEdge = 0;
return graph;
}
//释放十字链表
void releaseCrossGraph(CrossGraph *graph) {
int numEdges = 0;
if (graph) {
if (graph->nodes) {
for (int i = 0; i < graph->numVertex; ++i) { // 遍历所有节点,释放出度
ArcBox *box = graph->nodes[i].firstOut;
ArcBox *tmp; //备份思想
while (box) {
tmp = box;
box = box->tailNext;
free(tmp);
numEdges++;
}
}
printf("release %d edge!\n", numEdges);
free(graph->nodes);
}
free(graph);
}
}
初始化图,设置节点信息
void initCrossGraph(CrossGraph *graph, int num, char **names) {
for (int i = 0; i < num; ++i) {
graph->nodes[i].no = i;
graph->nodes[i].show = names[i];
graph->nodes[i].firstOut = graph->nodes[i].firstIn = NULL;
}
}
// 添加边,从tail走向head
void addCrossArc(CrossGraph *graph, int tail, int head, int w) {
ArcBox *box = (ArcBox *) malloc(sizeof(ArcBox));
box->weight = w;
// 使用头插法,出度(先处理新节点,再处理老节点)
box->tailVertex = tail;
box->tailNext = graph->nodes[tail].firstOut;
graph->nodes[tail].firstOut = box;
// 使用头插法,入度
box->headVertex = head;
box->headNext = graph->nodes[head].firstIn;
graph->nodes[head].firstIn = box;
}
// 计算no编号节点的入度
int inDegreeCrossGraph(CrossGraph *graph, int no) {
int count = 0;
ArcBox *box = graph->nodes[no].firstIn;
while (box) {
count++;
box = box->headNext;
}
return count;
}
// 计算no编号节点的出度
int outDegreeCrossGraph(CrossGraph *graph, int no) {
int count = 0;
ArcBox *box = graph->nodes[no].firstOut;
while (box) {
count++;
box = box->tailNext;
}
return count;
}
main.c
#include <stdio.h>
#include "crossLinkGraph.h"
static void setupGraph(CrossGraph *graph) {
char *nodeName[] = {"V0", "V1", "V2", "V3"};
initCrossGraph(graph, sizeof(nodeName) / sizeof(nodeName[0]), nodeName);
addCrossArc(graph, 0, 3, 1);
addCrossArc(graph, 1, 0, 1);
addCrossArc(graph, 1, 2, 1);
addCrossArc(graph, 2, 0, 1);
addCrossArc(graph, 2, 1, 1);
}
int main() {
int n = 4;
CrossGraph *graph = createCrossGraph(n);
if (graph == NULL) {
return -1;
}
setupGraph(graph);
printf("V0的入度为: %d\n", inDegreeCrossGraph(graph, 0));
printf("V0的出度为: %d\n", outDegreeCrossGraph(graph, 0));
releaseCrossGraph(graph);
return 0;
}
运行结果:
2、 邻接多重表代码实现:
adjacencyMultiList.h
#ifndef ADJACENCY_MULTI_LIST_H
#define ADJACENCY_MULTI_LIST_H
/* 邻接多重表,使用于无向图,边的删除操作
* 无向图如果用邻接表存储的话,一条边处理了2次,删除较为复杂
* */
// 邻接多重表的边结构
typedef struct amlEdge {
int iVex; // 边的顶点i编号
struct amlEdge *iNext; // 顶点i编号的下一个边
int jVex; // 边的顶点j编号
struct amlEdge *jNext; // 顶点j编号的下一条边
int weight; // 边的权重
}MultiListEdge;
// 邻接多重表的顶点结构
typedef struct {
int no; //顶点的编号
char *show; //图中顶点的显示数据(比如V1,V2,V3),指针指向了一个常量空间
MultiListEdge *firstEdge; //第一条边
}MultiListVertex;
// 邻接多重表
typedef struct {
MultiListVertex *nodes; //顶点集
int vertexNum; //顶点数
int edgeNum; //边数
}AdjacencyMultiList;
//生成邻接多重表
AdjacencyMultiList *createMultiList(int n);
//释放邻接多重表
void releaseMultiList(AdjacencyMultiList *graph);
//初始化图的顶点集
void initMultiList(AdjacencyMultiList *graph, int n, char *names[]);
// 插入边
int insertMultiListEdge(AdjacencyMultiList *graph, int a, int b, int w);
// 删除边
int deleteMultiListEdge(AdjacencyMultiList *graph, int a, int b);
#endif
adjacencyMultiList.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "adjacencyMultiList.h"
//生成n个顶点的邻接多重表
AdjacencyMultiList *createMultiList(int n) {
AdjacencyMultiList *multiList = (AdjacencyMultiList *) malloc(sizeof(AdjacencyMultiList));
multiList->nodes = (MultiListVertex *) malloc(sizeof(MultiListVertex) * n);
multiList->vertexNum = n;
multiList->edgeNum = 0;
return multiList;
}
//初始化图及其顶点集
void initMultiList(AdjacencyMultiList *graph, int n, char **names) {
for (int i = 0; i < n; ++i) {
graph->nodes[i].no = i;
graph->nodes[i].show = names[i];
graph->nodes[i].firstEdge = NULL;
}
}
//插入边
int insertMultiListEdge(AdjacencyMultiList *graph, int a, int b, int w) {
// 先产生这条边
MultiListEdge *edge = (MultiListEdge *) malloc(sizeof(MultiListEdge));
edge->weight = w;
// 处理a节点的连接关系,使用头插法
edge->iVex = a;
edge->iNext = graph->nodes[a].firstEdge;
graph->nodes[a].firstEdge = edge;
// 处理b节点的连接关系,使用头插法
edge->jVex = b;
edge->jNext = graph->nodes[b].firstEdge;
graph->nodes[b].firstEdge = edge;
graph->edgeNum++; //边数加一
return 0;
}
int deleteMultiListEdge(AdjacencyMultiList *graph, int a, int b) {
// 找到a编号的前一个节点
MultiListEdge *aPreEdge = NULL; //前置边的节点
MultiListEdge *aCurEdge = graph->nodes[a].firstEdge; //当前节点为图中a节点的第一条边
while (aCurEdge &&
!((aCurEdge->iVex == a && aCurEdge->jVex == b) || (aCurEdge->jVex == a && aCurEdge->iVex == b))) {
aPreEdge = aCurEdge;
if (aCurEdge->iVex == a) {
aCurEdge = aCurEdge->iNext;
} else {
aCurEdge = aCurEdge->jNext;
}
}
if (aCurEdge == NULL)
return -1; //当前节点为空时,没找到,不用删,返回-1
// 找到b编号的前一个节点
MultiListEdge *bPreEdge = NULL;
MultiListEdge *bCurEdge = graph->nodes[b].firstEdge;
while (bCurEdge &&
!((bCurEdge->iVex == a && bCurEdge->jVex == b) || (bCurEdge->jVex == a && bCurEdge->iVex == b))) {
bPreEdge = bCurEdge;
if (bCurEdge->iVex == b) {
bCurEdge = bCurEdge->iNext;
} else {
bCurEdge = bCurEdge->jNext;
}
}
if (bCurEdge == NULL)
return -1;
// 再删除
// 先处理a顶点的关系
if (aPreEdge == NULL) { // 前置边的节点为空,是从头节点处开始删除,即是第一条边
if (aCurEdge->iVex == a) { // 假如是从i方向找到a的
graph->nodes[a].firstEdge = aCurEdge->iNext;
} else { // 假如是从j方向找到a的
graph->nodes[a].firstEdge = aCurEdge->jNext;
}
} else { //总共四种情况
if (aPreEdge->iVex == a && aCurEdge->iVex == a) { //Pre和Cur都是i方向
aPreEdge->iNext = aCurEdge->iNext;
}else if(aPreEdge->iVex == a && aCurEdge->jVex == a){ //Pre是i方向,Cur是j方向
aPreEdge->iNext = aCurEdge->jNext;
}else if(aPreEdge->jVex == a && aCurEdge->iVex == a){ //Pre是j方向,Cur是i方向
aPreEdge->jNext = aCurEdge->iNext;
}else{ //Pre和Cur都是j方向
aPreEdge->jNext = aCurEdge->jNext;
}
}
// 再处理b顶点的关系
if (bPreEdge == NULL) {
if (bCurEdge->iVex == b) {
graph->nodes[b].firstEdge = bCurEdge->iNext;
} else {
graph->nodes[b].firstEdge = bCurEdge->jNext;
}
} else {
if (bPreEdge->iVex == b && bCurEdge->iVex == b) {
bPreEdge->iNext = bCurEdge->iNext;
}else if(bPreEdge->iVex == b && bCurEdge->jVex == b){
bPreEdge->iNext = bCurEdge->jNext;
}else if(bPreEdge->jVex == b && bCurEdge->iVex == b){
bPreEdge->jNext = bCurEdge->iNext;
}else{
bPreEdge->jNext = bCurEdge->jNext;
}
}
// 释放cur
free(aCurEdge);
graph->edgeNum--; //边数减一
return 0;
}