目录
一、邻接矩阵法
1.结构体
typedef struct{
VertexType Vex[MaxVertexNum]; //顶点表
int Edge[MaxVertexNum][MaxVertexNum]; //邻接矩阵,边表 如果带权图,就使用int类型
int vexnum,arcnum;//当前的顶点数和边数
}MGraph;
2.操作函数
1)邻接矩阵法创建图
void CreatMGraph(MGraph &G,int i) //i:0 无向图不带权值 1 无向带权 2 有向不带权 3 有向带权
{
int v,e;
cout<<"请输入顶点数和边数"<<endl;
cin>>v>>e;
G.vexnum=v;
G.arcnum=e;
cout<<"请输入顶点信息"<<endl;
for (int i=0;i<G.vexnum;i++) {
cin>>G.Vex[i];
}
for (int i=0;i<G.vexnum;i++) {
for(int j=0;j<G.vexnum;j++){
G.Edge[i][j]=INF;
}
}
if(i==0){
cout<<"请输入边的两端顶点值"<<endl;
for (int i=0;i<G.arcnum;i++) {
VertexType v1,v2;
cin>>v1>>v2;
int a1=GetIndexByElem(G,v1);
int a2=GetIndexByElem(G,v2);
G.Edge[a1][a2]=1;
G.Edge[a2][a1]=1;
}
if(i==1){
cout<<"请输入边的两端顶点值和权值"<<endl;
for (int i=0;i<G.arcnum;i++) {
VertexType v1,v2;
int cost;
cin>>v1>>v2>>cost;
int a1=GetIndexByElem(G,v1);
int a2=GetIndexByElem(G,v2);
G.Edge[a1][a2]=cost;
G.Edge[a2][a1]=cost;
}
}
}
if(i==2){
cout<<"请输入弧尾到弧头"<<endl;
for (int i=0;i<G.arcnum;i++) {
VertexType v1,v2;
cin>>v1>>v2;
int a1=GetIndexByElem(G,v1);
int a2=GetIndexByElem(G,v2);
G.Edge[a1][a2]=1;
}
}
if(i==3){
cout<<"请输入弧尾到弧头以及权值"<<endl;
for (int i=0;i<G.arcnum;i++) {
VertexType v1,v2;
int w;
cin>>v1>>v2>>w;
int a1=GetIndexByElem(G,v1);
int a2=GetIndexByElem(G,v2);
G.Edge[a1][a2]=w;
}
}
}
2)获取内容为e的结点下标
int GetIndexByElem(MGraph G,VertexType e)
{
//只用去顶点表遍历即可
for (int i=0;i<G.vexnum;i++) {
if(e==G.Vex[i]){
return i;
}
}
return -1;
}
3)插入顶点
bool InsertVex(MGraph &G)
{
cout<<"请输入你要插入的顶点信息以及与其相关的边条数"<<endl;
VertexType v;
int e;
cin>>v>>e;
G.vexnum++;
G.arcnum+=e;
//vexnum-1为下标
G.Vex[G.vexnum-1]=v;
for (int i=0;i<G.vexnum;i++) {
//行初始为0
G.Edge[G.vexnum-1][i]=0;
//列初始为0
G.Edge[i][G.vexnum-1]=0;
}
cout<<"请输入该顶点相邻的顶点值"<<endl;
for (int i=0;i<e;i++) {
VertexType v1,v2;
cin>>v1>>v2;
int index1 = GetIndexByElem(G,v1);
int index2 = GetIndexByElem(G,v2);
G.Edge[index1][index2]=1;
G.Edge[index2][index1]=1;
}
return true;
}
4)删除顶点v
bool DeleteVex(MGraph &G,VertexType v)
{
//更新边表
for (int i=GetIndexByElem(G,v);i<G.vexnum-1;i++) {
for (int j=0;j<G.vexnum;j++) {
G.Edge[i][j]=G.Edge[i+1][j];
G.Edge[j][i]=G.Edge[i][j];
}
}
//更新顶点表
for (int i=GetIndexByElem(G,v);i<G.vexnum-1;i++) {
G.Vex[i]=G.Vex[i+1];
}
G.vexnum--;
return 1;
}
5)找到v的第一个邻接点
int FirstNeighbor(MGraph G, int v)
{
int k;
for(k=1;k<=G.vexnum;k++)
{
if(G.Edge[v][k]==1)
break;
}
if(k<=G.vexnum)
return k;
else
return -1;
}
6)找到v除了w后第一个邻接点
int NextNeighbor(MGraph G, int v, int w)
{
int j;
for(j=w+1;j<=G.vexnum;j++)
{
if(G.Edge[v][j]==1)
break;
}
if(j<=G.vexnum)
return j;
else
return -1;
}
7)图的遍历
a.深度优先遍历
void DFS(MGraph G, int i)
{
visit(G,i);
visited[i]=1;
for (int w=FirstNeighbor(G,i);w>=0;w=NextNeighbor(G,i,w)) {
if(!visited[w])
DFS(G,w);
}
}
void DFSTraverse(MGraph G)
{
for (int i = 0; i < G.vexnum; i++)
visited[i] = 0; //初始化所有顶点都为未访问
for (int i = 0; i < G.vexnum; i++)
if (!visited[i])
DFS(G, i);
}
b.广度优先搜索,使用队列
void BFS(MGraph G, int v)
{
visit(G,v);
visited[v]=1;
EnLinkQueue(Q,v);
while (!LinkQueueEmpty(Q)) {
DeLinkQueue(Q,v);
for (int w = FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) {
if(!visited[w]){
visit(G,w);
visited[w]=1;
EnLinkQueue(Q,w);
}
}
}
}
void BFSTraverse(MGraph G)
{
for(int i=0;i<G.vexnum;i++){
visited[i]=0;
}
InitLinkQueue(Q);
for(int i=0;i<G.vexnum;i++){
if(!visited[i])
BFS(G,i);
}
}
8)基于BFS的单源最短路径
int D[];
int path[];
void BFS_MIN_Distance(MGraph G, int u)
{
for(int i=0;i<G.vexnum;i++){
D[i]=INF;
path[i]=-1;
}
visited[u]=true;
D[u]=0;
EnLinkQueue(Q,u);
while (!LinkQueueEmpty(Q)) {
DeLinkQueue(Q,u);
for (int w = FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)) {
if(!visited[w]){
visit(G,w);
visited[w]=1;
D[w]=D[u]+1;
path[w]=u;
EnLinkQueue(Q,w);
}
}
}
}
9)prim算法
void Prim(MGraph G, int v, int &sum)
{
int *lowcost=(int *)malloc(sizeof(int)*G.vexnum);
int *vset=(int *)malloc(sizeof(int)*G.vexnum);
int i,j,k,min;
for (i=0;i<G.vexnum;i++) {
lowcost[i]=G.Edge[v][i];
vset[i]=0;
}
vset[v]=1;
sum=0;
for (i=0;i<G.vexnum-1;i++) {
min=999999;
for (j=0;j<G.vexnum;j++) {
if(vset[j]==0&&lowcost[j]<min){
min=lowcost[j];
k=j;
}
}
vset[k]=1;
sum+=min;
for (j=0;j<G.vexnum;j++) {
if(vset[j]==0&&G.Edge[k][j]<lowcost[j]){
lowcost[j]=G.Edge[k][j];
}
}
}
}
10)kruskal算法
void getroad(MGraph g)
{
int index = 0;
for (int i=0;i<g.vexnum;i++) {
for (int j=0;j<i;j++) {
if(g.Edge[i][j]!=INF){
roads[index].a=i;
roads[index].b=j;
roads[index].w=g.Edge[i][j];
index++;
}
}
}
}
void kruskal(MGraph G, int &sum, Road1 *road)
{
for (int i=0;i<G.vexnum;i++) {
v[i]=i;
}
sum=0;
quicksort(road,0,G.arcnum-1);
for (int i=0;i<G.arcnum;i++) {
int av=getroot(road[i].a);
int bv=getroot(road[i].b);
if(av!=bv){
v[av]=bv;
sum+=road[i].w;
}
}
}
11)dijkstra求单源最短路径
void dijkstra(MGraph G, int v, int *dist, int* path1)
{
int *set=(int*)malloc(sizeof(int)*G.vexnum);
for (int i=0;i<G.vexnum;i++) {
dist[i]=G.Edge[v][i];
set[i]=0;
if(G.Edge[v][i]!=INF){
path1[i]=v;
}
else {
path1[i]=-1;
}
}
set[v]=1;
path1[v]=-1;
int u;
for (int i=0;i<G.vexnum-1;i++) {
int min=INF;
u=-1;
for (int j=0;j<G.vexnum;j++) {
if(set[j]==0&&min>dist[j])
min=dist[j],u=j;
}
}
set[u]=1;
for (int j=0;j<G.vexnum;j++) {
if(set[j]==0&&dist[j]>dist[u]+G.Edge[u][j]){
dist[j]=dist[u]+G.Edge[u][j];
path1[j]=u;
}
}
free(set);
}
12)floyd算法最短路径
void floyd(MGraph G, int path[][20], int dist[][20])
{
for (int i=0;i<G.vexnum;i++) {
for (int j=0;j<G.vexnum;j++) {
dist[i][j]=G.Edge[i][j];
path[i][j]=-1;
}
}
for (int k=1;k<G.vexnum;k++) {
for (int i=0;i<G.vexnum;i++) {
for (int j=0;j<G.vexnum;j++) {
if(dist[i][j]>dist[i][k]+dist[k][j]){
dist[i][j]=dist[i][k]+dist[k][j];
path[i][j]=k;
}
}
}
}
}
13)拓扑排序
int * GetIndegree(MGraph &G)
{
int *indegree=(int*)malloc(sizeof (int)*G.vexnum);
for (int i=0;i>G.vexnum;i++) {
indegree[i]=0;
}
for (int i=0;i<G.vexnum;i++) {
for (int j=0;j<G.vexnum;j++) {
if(G.Edge[i][j]!=0)
indegree[i]++;
}
}
return indegree;
}
SqStack s;
bool topSort(MGraph &G)
{
int count;
int *indegree=GetIndegree(G);
InitStack(s);
for (int i=0;i<G.vexnum;i++) {
if(indegree[i]==0)
push(s,i);
}
while (StackEmpty(s)) {
count++;
int v;
pop(s,v);
cout<<v+1<<" ";
for (int i=0;i<G.vexnum;i++) {
if(G.Edge[v][i]==1)
indegree[i]--;
if(indegree[i]==0)
push(s,i);
}
}
free(indegree);
return count==G.vexnum;
}
二、邻接表法
1.结构体
//边
typedef struct ArcNode{
int adjvex; //邻接点在数组的下标
ArcNode *next;//下一个邻接点
int weight;
}ArcNode;
//顶点
typedef struct VNode{
VertexType data; //顶点的数据
ArcNode *first; //第一条边
int count; //记录
}VNode,AdjList[MaxVertexNum];
//图
typedef struct{
AdjList vertices;
int vexnum,arcnum;
int kid;
}ALGraph;
2.操作函数
1)返回顶点u的下标
int LocateVex(ALGraph G, VertexType u)
{
int i;
for (i = 0; i < G.vexnum && G.vertices[i].data != u; i++);
if (i == G.vexnum) return -1; //不存在该顶点
else return i;
}
2)创建邻接表
bool CreatALGraph(ALGraph &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;
G.vertices[i].count=0;
}
cout<<"请输入一条边依附的两个顶点值"<<endl;
for (int j=0;j<G.arcnum;j++) {
VertexType v1,v2;
cin>>v1>>v2;
int a=LocateVex(G,v1);
int b=LocateVex(G,v2);
ArcNode *p1=(ArcNode *)malloc(sizeof (ArcNode));
p1->adjvex=b;
p1->next=G.vertices[a].first;
G.vertices[b].count++;
G.vertices[a].first=p1;
ArcNode*p2=(ArcNode *)malloc(sizeof (ArcNode));
p2->adjvex=a;
p2->next=G.vertices[b].first;
G.vertices[b].first=p2;
}
return true;
}
3)求顶点x的第一个邻接点
int FirstNeighbor(ALGraph G, VertexType x)
{
if(x != -1){
ArcNode *p = G.vertices[x].first; //对应边链表的第一个结点
if(p!=NULL){
return p->adjvex;
}
}
}
4)顶点v除去w后第一个邻接点
int NextNeighbor(ALGraph G, VertexType v, VertexType w)
{
if(v!=-1 && w!=-1){
ArcNode *p = G.vertices[v].first; //对应边链表的第一个结点
while(p!=NULL && p->adjvex!=w)
p=p->next; //找到v的邻接点w
if(p!=NULL && p->next!=NULL) //w存在且w的邻接点存在
return p->next->adjvex;
}
return -1;
}
5)拓扑排序
int topSort(ALGraph *G)
{
int i,j,count=0;
ArcNode *p;
InitStack(s);
for (int i=0;i<G->vexnum;i++) {
if(G->vertices[i].count==0)
push(s,i);
}
while (StackEmpty(s)) {
pop(s,i);
++count;
cout<<i+1<<",";
p=G->vertices[i].first;
while (p!=NULL) {
j=p->adjvex;
--G->vertices[j].count;
if(G->vertices[j].count==0)
push(s,j);
}
p=p->next;
}
return count==G->vexnum?1:0;
}
6)图的遍历
a.广度优先遍历
void BFS(ALGraph G, int v)
{
visit(G,v);
visited[v]=1;
EnLinkQueue(Q,v);
while (!LinkQueueEmpty(Q)) {
DeLinkQueue(Q,v);
for (int w = FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) {
if(!visited[w]){
visit(G,w);
visited[w]=1;
EnLinkQueue(Q,w);
}
}
}
}
void BFSTraverse(ALGraph G)
{
for(int i=0;i<G.vexnum;i++){
visited[i]=0;
}
InitLinkQueue(Q);
for(int i=0;i<G.vexnum;i++){
if(!visited[i])
BFS(G,i);
}
}
b.深度优先遍历
void DFS(ALGraph G, int v)
{
visit(G,v);
visited[v]=true;
for (int w = FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w)) {
if(!visited[w]){
DFS(G,w);
}
}
}
void DFSTraverce(ALGraph G)
{
for (int v=0;v<G.vexnum;v++) {
visited[v]=false;
}
for(int v=0;v<G.vexnum;v++){
if(!visited[v])
DFS(G,v);
}
}
三、其他存储结构
1.十字链表法 ------只针对有向图
//十字链表法 --- 有向图
typedef struct AcrNode{
int tailvex,headvex;
AcrNode *hlink,*tlink;//指向弧尾和弧头相同的结点。
int info;
}ArcNode;
//顶点表结点
typedef struct VNode{
VertexType data;
AcrNode *firstin,*firstout;//第一条入弧和出弧
}VNode;
typedef struct{
VNode xlist[MaxVertexNum];
int vexnum,arcnum;
}Graph;
2.邻接多重表 ---只针对无向图
//邻接多重表---无向图
typedef struct ArcNode{
bool mark;
int ivex,jvex;
ArcNode *ilink,*jLink; //依附于顶点i,j的下一条边
}ArcNode;
typedef struct VNode{
VertexType data;
ArcNode *firstEdge;
}VNode;
typedef struct {
VNode adjMuList[MaxVertexNum];
int acrnum,vexnum;
}Graph;