1. 数组表示法(邻接矩阵法):
#include <stdio.h>
#include <limits.h>
#define INFINITY INT_MAX
#define Maxvex 100
typedef struct graph {
int vexs[Maxvex+1]; //顶点
int AdjMatrix[Maxvex+1][Maxvex+1]; //邻接矩阵
int vexsnum, edgenum; //顶点数,边数
}Graph;
void CreateGraph(Graph *G) {
printf("请输入顶点数,边数:");
scanf("%d %d",&G->vexsnum, &G->edgenum);
for (int i = 1; i <= G->vexsnum; i++) {
scanf("%d",&G->vexs[i]);
for (int j = 1; j <= G->vexsnum; j++) {
G->AdjMatrix[i][j] = INFINITY;
}
}
int row, col, w;
for (int i = 1; i <= G->edgenum; i++) {
printf("输入边坐标i,j,权值:");
scanf("%d%d%d",&row, &col, &w);
G->AdjMatrix[row][col] = w;
G->AdjMatrix[col][row] = w;
}
}
int main () {
Graph G;
CreateGraph(&G);
return 0;
}
2.邻接表
#include <stdio.h>
#include <stdlib.h>
#define Vertex_Num 100
typedef int VertexType;
//存储弧的结点
typedef struct ArcNode {
int adjvex; //该弧所指向的顶点的位置
int info; //该弧的权值
struct ArcNode *next; //指向下一条弧的指针
}ArcNode;
//存储顶点的结点
typedef struct VNode {
VertexType data;
ArcNode *first;//指向第一条依附该顶点的弧的指针
}VNode, AdjList[Vertex_Num];
//图
typedef struct {
AdjList vertices;
int vexnum, arcnum; //图的顶点数和弧数
}Graph;
void CreateGraph(Graph *G) {
printf("请输入顶点数,边数:\n");
scanf("%d %d", &G->vexnum, &G->arcnum);
printf("请输入顶点\n");
for (int i = 1; i <= G->vexnum; i++) {
scanf("%d",&G->vertices[i].data);
G->vertices[i].first = NULL;
}
printf("请选择你要建立的存储类型,1表示邻接表,0表示逆邻接表:\n");
int choice;
scanf("%d",&choice);
int vex1, vex2, weight;
if (choice != 1 && choice != 0) {
printf("输入有错,请重新输入\n");
scanf("%d",&choice);
}
if (choice == 1) {
for (int j =1; j <= G->arcnum; j++) {
printf("请输入边的两个顶点以及权值:\n");
scanf("%d%d%d", &vex1, &vex2, &weight);
ArcNode *edge = (ArcNode*)malloc(sizeof(ArcNode));
edge->adjvex = vex2;
edge->info = weight;
edge->next = G->vertices[vex1].first;
G->vertices[vex1].first = edge;
}
}
if (choice == 0) {
for (int j =1; j <= G->arcnum; j++) {
printf("请输入边的两个顶点以及权值:\n");
scanf("%d%d%d", &vex1, &vex2, &weight);
ArcNode *edge = (ArcNode*)malloc(sizeof(ArcNode));
edge->adjvex = vex1;
edge->info = weight;
edge->next = G->vertices[vex2].first;
G->vertices[vex2].first = edge;
}
}
}
int main()
{
Graph G;
CreateGraph(&G);
for(int i = 1; i <= G.vexnum; i++)
{
printf("|%d|->", G.vertices[i].data);
ArcNode *e = G.vertices[i].first;
while(e != NULL)
{
printf("%d->", e->adjvex);
e = e->next;
}
printf("NULL\n");
}
return 0;
}
运行结果:
- 邻接表:
- 逆邻接表:
c++按顺序实现:
//邻接表和逆邻接表的c++表示
//主要表现的为有向图
#include <iostream>
#include <string>
#include <malloc.h>
#include <string.h>
#define Vertex_Num 20
using namespace std;
struct ArcNode {
int adjvex;
ArcNode *nextarc;
};
struct VNode
{
int data;
ArcNode *first;
};
typedef VNode AdjList[Vertex_Num];
struct Graph
{
AdjList vertices;
int vexnum, arcnum; //图的顶点数和弧数
int kind;
};
int findData(AdjList adj, int num, int v) {
for (int i = 0; i < num; i++) {
if (adj[i].data == v) {
return i;
}
}
}
void CreateGraph(Graph *G) {
cout << "请输入顶点数和弧数: " << endl;
cin >> G->vexnum >> G->arcnum;
cout << "请输入顶点: " << endl;
for (int i = 0; i < G->vexnum; i++) {
cin >> G->vertices[i].data;
G->vertices[i].first = NULL;
}
cout << "请输入你要存储的类型: 0表示邻接表, 1表示逆邻接表: " << endl;
cin >> G->kind;
if (G->kind == 0) {
for (int i = 0; i < G->arcnum; i++) {
int v1, v2;
cout << "请输入要存储的弧尾和弧头:" << endl;
cin >> v1 >> v2;
int i0 = findData(G->vertices, G->vexnum, v1);
ArcNode *arc0 = new ArcNode;
arc0->adjvex = v2;
arc0->nextarc = NULL;
if (G->vertices[i0].first == NULL) {
G->vertices[i0].first = arc0;
}
else {
ArcNode *head = G->vertices[i0].first;
while (head->nextarc != NULL) {
head = head->nextarc;
}
head->nextarc = arc0;
}
}
}
else if (G->kind == 1) {
for (int i = 0; i < G->arcnum; i++) {
int v1, v2;
cout << "请输入要存储的弧尾和弧头:" << endl;
cin >> v2 >> v1;
int i0 = findData(G->vertices, G->vexnum, v1);
ArcNode *arc0 = new ArcNode;
arc0->adjvex = v2;
arc0->nextarc = NULL;
if (G->vertices[i0].first == NULL) {
G->vertices[i0].first = arc0;
}
else {
ArcNode *head = G->vertices[i0].first;
while (head->nextarc != NULL) {
head = head->nextarc;
}
head->nextarc = arc0;
}
}
}
else {
cout << "输入错误!" << endl;
}
}
void PrintGraph(Graph G) {
for (int i = 0; i < G.vexnum; i++) {
cout << "|" << G.vertices[i].data << "|" << "->";
ArcNode *head = G.vertices[i].first;
while (head != NULL) {
cout << head->adjvex << "->";
head = head->nextarc;
}
cout << "NULL" << endl;
}
}
int main () {
Graph g;
CreateGraph(&g);
PrintGraph(g);
return 0;
}
3. 十字链表:
#include <stdio.h>
#include <stdlib.h>
// - - - - - 有向图的十字链表存储结构 - - - - -
//相当于把有向图的邻接表和逆邻接表结合到一起得到的一种链表
#define VERTEX_NUM 100
typedef int VertexType;
//弧结点
typedef struct ArcBox {
int tailvex, headvex; //弧头和弧尾的位置
struct ArcBox *hlink, *tlink; //分别指向下一个弧头和弧尾相同的链域
int info; //弧的权值
}ArcBox;
//顶点结点
typedef struct VexNode {
VertexType data;
ArcBox *firstin, *firstout;
}VexNode;
//图
typedef struct {
VexNode xlist[VERTEX_NUM]; //表头向量
int vexnum, arcnum; //有向图的当前顶点数和弧数
}Graph;
void CreateGraph(Graph *G) {
printf("请输入顶点数,弧数:\n");
scanf("%d%d",&G->vexnum, &G->arcnum);
printf("请输入顶点:\n");
for (int i = 1; i <= G->vexnum; i++) {
scanf("%d",&G->xlist[i].data);
G->xlist[i].firstin = NULL;
G->xlist[i].firstout = NULL;
}
int vex1, vex2, weight;
for (int i = 1; i <= G->arcnum; i++) {
printf("请输入弧尾,弧头,弧的权值\n");
scanf("%d%d%d",&vex1, &vex2, &weight);
ArcBox *e = (ArcBox*)malloc(sizeof(ArcBox));
e->tailvex = vex1;
e->headvex = vex2;
e->tlink = NULL;
e->hlink = NULL;
e->tlink = G->xlist[vex1].firstout;
G->xlist[vex1].firstout = e;
e->hlink = G->xlist[vex2].firstin;
G->xlist[vex2].firstin = e;
}
}
4. 邻接多重表:
// - - - - - 图的邻接多重表存储表示 - - - - -
// - - - - - - 更适用于无向图 - - - - - -
// - - 相比邻接表更方便对某一条边进行操作 - -
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define VERTEX_NUM 100
typedef enum {unvisited, visited} VisitIf;
typedef int VertexType;
typedef struct EBox {
VisitIf mark; //访问标记
int ivex, jvex;
struct EBox *ilink, *jlink; //分别指向依附这两个顶点的下一条边
int info; //权值
}EBox;
typedef struct VexBox {
VertexType data;
EBox *firstedge; //指向第一条依附该顶点的边
}VexBox;
typedef struct {
VexBox adjmulist[VERTEX_NUM];
int vexnum, edgenum; //图的顶点数和弧数
}Graph;
void CreateGraph(Graph *G) {
//G = (Graph*)malloc(sizeof(Graph));
printf("请输入点数,弧数\n");
scanf("%d%d",&G->vexnum, &G->edgenum);
printf("请输入顶点\n");
for(int i = 1; i <= G->vexnum; i++) {
scanf("%d",&G->adjmulist[i].data);
G->adjmulist[i].firstedge = NULL;
}
int v1, v2, weight;
for(int k = 1; k <= G->edgenum; k++) {
printf("请输入两个顶点v1,v2以及弧的权值\n");
scanf("%d%d%d",&v1,&v2,&weight);
EBox *edge = (EBox*)malloc(sizeof(EBox));
edge->mark = unvisited;
edge->ivex = v1;
edge->jvex = v2;
edge->info = weight;
edge->ilink = NULL;
edge->jlink = NULL;
EBox *p = G->adjmulist[v1].firstedge;
if (!p) {
G->adjmulist[v1].firstedge = edge;
}
else {
while((p->ilink != NULL && p->ivex == v1) || (p->jlink != NULL && p->jvex == v1)) {
if(v1 == p->ivex)
p = p->ilink;
else
p = p->jlink;
}
if(p->ivex == v1) p->ilink = edge;
else p->jlink = edge;
}
p = G->adjmulist[v2].firstedge;
if (!p) {
G->adjmulist[v2].firstedge = edge;
}
else {
while((p->ilink != NULL && p->ivex == v2) || (p->jlink != NULL && p->jvex == v2)) {
if(v2 == p->ivex)
p = p->ilink;
else
p = p->jlink;
}
if(p->ivex == v2) p->ilink = edge;
else p->jlink = edge;
}
}
}
void PrintGraph(Graph G)
{
EBox *p;
for(int i = 1; i <= G.vexnum; ++i)
{
p = G.adjmulist[i].firstedge;
while(p != NULL)
{
if(p->ivex == i) //判断相等才能知道连接上的是ivex还是jvex;
{
printf("%d--%d\n", G.adjmulist[p->ivex].data, G.adjmulist[p->jvex].data);
p = p->ilink;
}
else
{
printf("%d--%d\n", G.adjmulist[p->jvex].data, G.adjmulist[p->ivex].data);
p = p->jlink;
}
}
}
}
int main () {
Graph G;
CreateGraph(&G);
PrintGraph(G);
return 0;
}
运行结果:
c++实现:
//无向图的邻接多重表
#include <iostream>
using namespace std;
#define MAX_VERTEX_NUM 20
enum VisitIf {unvisited, visited};
class EBox {
public:
VisitIf mark; //访问标记
int ivex, jvex; //该边依附的两个顶点位置
EBox *ilink, *jlink; //分别指向依附这两个顶点的下一条边
};
template <typename T>
class VexBox {
public:
T data;
EBox *firstedge; //指向第一条依附该顶点的边
};
template <typename T>
class AMLGraph {
public:
VexBox<T> adjmulist[MAX_VERTEX_NUM];
int vexnum, edgenum; //无向图的当前顶点数和边数
};
template <typename T>
int LocateVex(VexBox<T> adj[], int num, T v) {
for (int i = 0; i < num; i++) {
if (adj[i].data == v) {
return i;
}
}
}
template <typename T>
void CreateGraph(AMLGraph<T> *G) {
cout << "请输入顶点数和弧数: " << endl;
cin >> G->vexnum >> G->edgenum;
cout << "请输入顶点: " << endl;
for (int i = 0; i < G->vexnum; i++) {
cin >> G->adjmulist[i].data;
G->adjmulist[i].firstedge = NULL;
}
for (int i = 0; i < G->edgenum; i++) {
cout << "请输入边的两个顶点: " << endl;
T v1, v2;
cin >> v1 >> v2;
int i1 = LocateVex(G->adjmulist, G->vexnum, v1);
int i2 = LocateVex(G->adjmulist, G->vexnum, v2);
//cout << i1 << "...." << i2 << endl;
EBox *p = new EBox;
p->mark = unvisited;
p->ivex = i1;
p->jvex = i2;
p->ilink = G->adjmulist[i1].firstedge;
p->jlink = G->adjmulist[i2].firstedge;
G->adjmulist[i1].firstedge = p;
G->adjmulist[i2].firstedge = p;
}
}
template <typename T>
void PrintGraph(AMLGraph<T> G)
{
EBox *p;
for(int i = 0; i < G.vexnum; ++i)
{
p = G.adjmulist[i].firstedge;
while(p != NULL)
{
if(p->ivex == i) //判断相等才能知道连接上的是ivex还是jvex;
{
cout << G.adjmulist[p->ivex].data << "------" << G.adjmulist[p->jvex].data << endl;
//printf("%d--%d\n", G.adjmulist[p->ivex].data, G.adjmulist[p->jvex].data);
p = p->ilink;
}
else
{
cout << G.adjmulist[p->jvex].data << "------" << G.adjmulist[p->ivex].data << endl;
p = p->jlink;
}
}
}
}
int main () {
AMLGraph<string> g;
CreateGraph(&g);
PrintGraph(g);
return 0;
}
总结一下以上所有的表示形式中,邻接矩阵有向无向图都可用,但常用于表现无向图。邻接表也是有向无向都可用,但因为表示无向图会使边重复显得繁琐,所以常用于表示有向图。十字链表是将有向图的邻接表和逆邻接表相结合使用。而邻接多重表相当于无向图的十字链表表示法。无向图我们常用邻接矩阵和邻接多重表表示,尤其邻接多重表可避免双边的重复访问。