邻接矩阵需要提前预先分配空间,容易造成空间上的浪费
而且在遇到两个顶点之间没有边时,邻接矩阵是不能解决的。
邻接表的出现 是结合了数组和链表的存储方式(当然 也可以是链表+链表)
数组+链表形式的邻接表
一维数组用来存储顶点元素,每个顶点的所有邻接点构成一个线性表
特点:
邻接表不唯一
若无向图中有 n 个顶点、e 条边,则其邻接表需n 个头结点和 2e 个表结点。适宜存储稀疏图
无向图中顶点 vi 的度为第 i 个单链表中的结点数
邻接表特点:
顶点 vi 的出度为第 i 个单链表中的结点个数
顶点 vi 的入度为整个单链表中邻接点域值为 i-1 的结点个数
逆邻接表特点:
顶点 vi 的入度为第 i 个单链表中的结点个数
顶点 vi 的出度为整个单链表中邻接点域值为 i-1 的结点的个数
无向图实现
#include<iostream>
using namespace std;
#define MAX 25
typedef char Vertype;
typedef int Edgetype;
typedef int Status;
typedef struct EdgeNode//边表结点 存放每个顶点的邻接点
{
int adjvex;//边表下标
Edgetype weight;//边表权重 若边不存在时即无NULL
struct EdgeNode *next;//指向下一个邻接点
}EdgeNode;
typedef struct VerNode//顶点表 存放顶点
{
Vertype data;//顶点元素
EdgeNode *firstedge;
}VerNode, AdjList[MAX];//邻接表的 顶点元素 和指向邻点的指针
typedef struct
{
AdjList adjList;//邻接表
int numVer,numEdge;//顶点数目和边的数目
}GraphAdjList;
Status CreatGraph(GraphAdjList &G)
{
int i, j, k;
Edgetype w;
EdgeNode *e;
cout << "Enter the number of vertices :"<< endl;
cin >> G.numVer;
cout << "Enter the number of Edges :" << endl;
cin >> G.numEdge;
cout << "Input vertex content :" << endl;
for (i = 0; i < G.numVer; i++)
{
cin >> G.adjList[i].data;//输入顶点元素
G.adjList[i].firstedge = NULL;//初始化邻边表为NULL;
}
for (k = 0; k < G.numEdge; k++)
{
cout <<"Enter the vertex number of the edge (Vi, Vj)" << endl;
cin >> i;
cin >> j;
cout << "Enter the weight of edge" << i << "-" << j << endl;
cin >> w;
e = new EdgeNode;//将两个顶点相结即可。
e->adjvex = j;// 邻接序号为j
e->next = G.adjList[i].firstedge;//i的第一个邻接指针 为e的指针
e->weight = w;
G.adjList[i].firstedge = e;
//有向图则只有生成一次即可
e = new EdgeNode;
e->adjvex = i;//无向图 重复一遍
e->next = G.adjList[j].firstedge;
G.adjList[j].firstedge = e;
e->weight = w;
}
return 0;
}
//输出无向图
Status DispGraph(GraphAdjList &G)
{
int i, j, k;
cout <<"Output element of ver" << endl;
for (i = 0; i < G.numVer; i++)
{
cout << G.adjList[i].data << '\t';
}
cout << "Output weight"<< endl;
for (k = 0; k < G.numVer; k++)
{
EdgeNode *p = G.adjList[k].firstedge;//中间指针
cout <<"xaibiao"<< k <<"constent"<< G.adjList[k].data << "jiedian:" << endl;
while (p != NULL)
{
cout <<G.adjList[k].data<< "->" << p->adjvex << '\t' << p->weight << '\t' << endl;
p = p->next;
}
}
/*
for (k = 0; k < G.numEdge; k++)
{
//cout << G.adjList[k].firstedge->adjvex << '\t' << G.adjList[k].firstedge->weight << '\t'<<G.adjList[k].firstedge->next->adjvex<<endl;
cout << G.adjList[k].firstedge->weight << '\t';
}
*/
return 0;
}
//返回一个顶点的位置 和其邻接表内容
Status OutGraph_x(GraphAdjList &G)
{
cout <<"请输入需要找的顶点内容: " << endl;
Vertype x;
cin >> x;
for (int i = 0; i < G.numVer; i++)
{
if(G.adjList[i].data == x)
{
cout << "该元素在图中的位置为: " <<i<<"。 相关邻接表为"<<endl;
EdgeNode *p = G.adjList[i].firstedge;
while (p != NULL)
{
cout << p->adjvex << '\t' << p->weight << '\t' << endl;
p = p->next;
}
}
}
return 0;
}
//新增一个顶点和对应边
Status AddGraph_x(GraphAdjList &G)
{
Vertype x;
Edgetype edg_num;
int w;
int i;
EdgeNode *p;
if (G.numVer >= MAX)
{
cout << "Graph memory is full and cannot be expanded "<< endl;
return NULL;
}
else
{
cout << "请输入需要插入的新顶点内容: " << endl;
cin >> x;
G.numVer++;
G.adjList[G.numVer - 1].data = x;//顶点内容赋值
G.adjList[G.numVer - 1].firstedge = NULL;//顶点指针NULL初始化
cout << "Please enter the number of new edges" << endl;//新增边的数目
//如果不成边呢
cin >> edg_num;
G.numEdge = G.numEdge+ edg_num;
p = new EdgeNode;
for (int j = 0; j < edg_num; j++)
{
cout << "请输入与其成边的顶点位置" << endl;
cin >> i;
cout << "请输入权重" << endl;
cin >> w;
/*while (p != NULL)
{
p = p->next;//找到最后一个结点为空时
}*/
//p = new EdgeNode;
p->adjvex = G.numVer - 1;
p->next = G.adjList[i].firstedge;
G.adjList[i].firstedge = p;
p->weight = w;
//p = new EdgeNode;
p->adjvex = i;
p->next = G.adjList[G.numVer - 1].firstedge;
G.adjList[G.numVer - 1].firstedge = p;
p->weight = w;
}
}
return 0;
}
//删除一个顶点
Status DelGraph_x(GraphAdjList &G)
{
Vertype x;
cout <<"请输入需要删除的顶点:" << endl;
cin >> x;
for (int i = 0; i < G.numVer; i++)
{
if (G.adjList[i].data == x)
{
G.adjList[i].data = NULL;//因为是数组类型 其结构必定存在 所以将其置为空
//free((void *)G.adjList[i].data); //释放顶点
G.adjList[i].firstedge=NULL;
}
}
return 0;
}
int main()
{
GraphAdjList G;
CreatGraph(G);
DispGraph(G);
OutGraph_x(G);
AddGraph_x(G);
DispGraph(G);
DelGraph_x(G);
DispGraph(G);
return 0;
}
有向图的实现
#include<iostream>
using namespace std;
#define MAX 25
typedef char Vertype;
typedef int Edgetype;
typedef int Status;
typedef struct EdgeNode//边表结点 存放每个顶点的邻接点
{
int adjvex;//边表下标
Edgetype weight;//边表权重 若边不存在时即无NULL
struct EdgeNode *next;//指向下一个邻接点
}EdgeNode;
typedef struct VerNode//顶点表 存放顶点
{
Vertype data;//顶点元素
EdgeNode *firstedge;
}VerNode, AdjList[MAX];//邻接表的 顶点元素 和指向邻点的指针
typedef struct
{
AdjList adjList;//邻接表
int numVer, numEdge;//顶点数目和边的数目
}GraphAdjList;
Status CreatGraph(GraphAdjList &G)
{
int i, j, k;
Edgetype w;
EdgeNode *e;
cout << "Enter the number of vertices :" << endl;
cin >> G.numVer;
cout << "Enter the number of Edges :" << endl;
cin >> G.numEdge;
cout << "Input vertex content :" << endl;
for (i = 0; i < G.numVer; i++)
{
cin >> G.adjList[i].data;//输入顶点元素
G.adjList[i].firstedge = NULL;//初始化邻边表为NULL;
}
for (k = 0; k < G.numEdge; k++)
{
cout << "Enter the vertex number of the edge (Vi->Vj)" << endl;
cin >> i;
cin >> j;
cout << "Enter the weight of edge" << i << "-" << j << endl;
cin >> w;
e = new EdgeNode;//将两个顶点相结即可。
e->adjvex = j;// 邻接序号为j
e->next = G.adjList[i].firstedge;//i的第一个邻接指针 为e的指针
e->weight = w;
G.adjList[i].firstedge = e;
//有向图则只有生成一次即可
/*
e = new EdgeNode;
e->adjvex = i;//无向图 重复一遍
e->next = G.adjList[j].firstedge;
G.adjList[j].firstedge = e;
e->weight = w;*/
}
return 0;
}
Status DispGraph(GraphAdjList &G)
{
int i, j, k;
cout << "Output element of ver" << endl;
for (i = 0; i < G.numVer; i++)
{
cout << G.adjList[i].data << '\t';
}
cout << "Output weight" << endl;
for (k = 0; k < G.numVer; k++)
{
EdgeNode *p = G.adjList[k].firstedge;//中间指针
cout << "xaibiao" << k << "constent" << G.adjList[k].data << "jiedian:" << endl;
while (p != NULL)
{
cout << G.adjList[k].data << "->" << p->adjvex << '\t' << p->weight << '\t' << endl;
p = p->next;
}
}
return 0;
}
int main()
{
GraphAdjList G;
CreatGraph(G);
DispGraph(G);
return 0;
}