- #ifndef _PIC_H
- #define _PIC_H
- #define MAXV 50
- typedef int InfoType;
- typedef char ElemType;
- int visited[MAXV];
- //邻接矩阵的数据类型
- typedef struct
- {
- int no; //顶点编号
- ElemType info; //顶点信息
- }VertexType; //顶点类型
- typedef struct
- {
- int edge[MAXV][MAXV]; //邻接矩阵
- int n,e; //顶点数,边数
- VertexType vexs[MAXV];
- }MGraph; //图的定义
- //邻接表
- typedef struct ANode //边的定义
- {
- int adjvex; //该边的终点位置
- struct ANode *nextarc; //指向下一条边得指针
- InfoType info; //该边得相关信息 例如权
- }ArcNode;
- typedef struct Vnode //头结点的定义
- {
- ElemType data; //顶点的信息
- ArcNode *firstarc; //指向这个顶点的第一条边
- }VNode;
- typedef VNode *AdjList[MAXV];
- typedef struct //图的定义
- {
- AdjList adjlist;
- int n,e;
- }AGraph;
- #endif
- #include <stdio.h>
- #include "stdlib.h"
- #include "pic.h"
- void CreateMat(MGraph *g, int A[][MAXV], int n) //生成图的邻接矩阵
- {
- int i=0,j=0;
- g->n = n;
- g->e = 0;
- for(i=0; i<n; i++)
- for(j=0; j<n; j++)
- {
- g->edge[i][j] = A[i][j];
- if(A[i][j] != 0)
- g->e ++;
- }
- }
- void DispMat(MGraph *g) //输出图的邻接矩阵
- {
- int i,j;
- for(i=0; i<g->n; i++)
- {
- for(j=0; j<g->n; j++)
- {
- printf("%c ",g->edge[i][j]);
- }
- printf("\n");
- }
- }
- void CreateAdj(AGraph *g, int A[][MAXV], int n) //生成图的邻接表
- {
- int i=0, j=0;
- ArcNode *p = NULL;
- g = (AGraph *)malloc(sizeof(AGraph));
- g->n = n;
- g->e = 0;
- for(i=0; i<n; i++) g->adjlist[i]->firstarc = NULL;
- for(i=0; i<n; i++)
- for(j=0; j<n; j++)
- if(A[i][j] != 0)
- {
- p = (ArcNode *)malloc(sizeof(ArcNode));
- p->adjvex = j;
- p->nextarc = g->adjlist[j]->firstarc; //倒着插入 并且数组的第一列为头结点
- g->adjlist[j]->firstarc = p;
- g->e++;
- }
- }
- void DispAdj(AGraph *g) //输出邻接表
- {
- int i=0;
- ArcNode *p = NULL;
- for(i=0; i<g->n; i++)
- {
- printf("%d ",i);
- p = g->adjlist[i]->firstarc; //把p指向每个头结点对应的边的指针
- while(p != NULL)
- {
- printf("%c ",p->adjvex);
- p = p->nextarc; //下一个边的指针
- }
- printf("\n");
- }
- }
- void InDs(AGraph *g) //ru du
- {
- ArcNode *p;
- int A[MAXV],i; // store ru du
- for(i=0; i<g->n; i++) A[i] = 0;
- for(i=0; i<g->n; i++)
- {
- p = (g->adjlist[i]->firstarc);
- while(p != NULL)
- {
- A[i]++;
- p = p->nextarc;
- }
- }
- for(i=0; i<g->n; i++)
- printf("%d ",A[i]);
- }
- void OutDs(AGraph *g) //chu du
- {
- int i,n;
- ArcNode *p;
- for(i=0; i<g->n; i++)
- {
- n=0;
- p = g->adjlist[i]->firstarc;
- while(p != NULL)
- {
- n ++;
- p = p->nextarc;
- printf("%d ",n);
- }
- }
- }
- void Arc(AGraph *g, int i, int j) //if there is line between i and j
- {
- ArcNode *p = NULL;
- p = g->adjlist[i]->firstarc;
- while(p->adjvex != j && p != NULL)
- p = p->nextarc;
- if(p == NULL) printf("不存在");
- else printf("存在");
- }
- void InDs1(MGraph *g) //计算邻接矩阵的入度,对于顶点 j,累计第j列中非零元素的个数即为入度
- {
- int i,j,n;
- for(j=0; j<g->n; j++)
- {
- n = 0;
- for(i=0; i<g->n; i++)
- {
- if(g->edge[i][j] != 0)
- n++;
- }
- printf("%d ",n);
- }
- }
- void OutDs2(MGraph *g) //计算出度只要计算那一行中非零的个数即可
- {
- int i=0,j=0,n=0;
- for(i=0; i<g->n; i++)
- { n=0;
- for(j=0; j<g->n; j++)
- if(g->edge[i][j] != 0)
- n++;
- printf("%d ",n);
- }
- }
- void ListToMat(AGraph *g1, MGraph *g2) //把邻接表转换为邻接矩阵
- {
- int i=0, j=0;
- ArcNode *p = NULL;
- g2 = (MGraph *)malloc(sizeof(MGraph));
- g2->n = g1->n;
- for(i=0; i<g1->n; i++)
- for(j=0; j<g1->n; j++)
- g2->edge[i][j] = 0;
- for(i=0; i<g1->n; i++)
- {
- p = g1->adjlist[i]->firstarc;
- while(p != NULL)
- {
- g2->edge[i][p->adjvex] = 1; //此处通过p->adjvex来决定第二维的坐标
- p = p->nextaec;
- }
- }
- }
- //深度优先遍历
- void DFS(AGraph *g, int v) //v表示第几个节点
- {
- ArcNode *p = NULL;
- visited[v] = 1;
- p = g->adjlist[v]->firstarc; //p代表第v个节点
- while(p != NULL)
- {
- if(visited[p->adjvex] == 0) //此处表示此节点未被访问过
- DFS(g,p->adjvex);
- p = p->nextarc ;
- }
- }
- /*
- * * * *
- * * * *
- * * * *
- * * * *
- 两者的差别是 深度遍历遇到一个可以访问的节点就会以它为头结点跳到相应的 行 继续重复前面类似的访问
- 而广度遍历则是一直遍历完一行后 才开始下一行
- */
- //广度优先遍历 需要借助队列
- void BFS(AGraph *g,int v)
- {
- ArcNode *p = NULL;
- int w,i,front =0, rear = 0;
- int queue[MAXV];
- rear = (rear + 1) % MAXV;
- queue[rear] = v;
- for(i=0; i<g->n ; i++) visited[i] = 0;
- visited[v] = 1;
- while(front != rear)
- {
- front = (front + 1) % MAXV;
- w = queue[front];
- p = g->adjlist[w]->firstarc;
- while(p != NULL) //此处的作用是把那一行的节点如队列
- {
- if(visited[p->adjvex] == 0)
- {
- visited[p->adjvex] = 1;
- rear = (rear + 1) % MAXV;
- queue[rear] = p->adjvex;
- }
- p = p->nextarc ; //在深度遍历的时候,也用到了它,不过在深度遍历后指针跳到其他行了,而此处仍然在那一行
- }
- }
- }
- //非连通图的遍历 需要选择不同的节点重复进行遍历
- void DFS1(AGraph *g)
- {
- int i=0;
- for(i=0; i<g->n; i++)
- if(visited[i] == 0)
- DFS(g,i);
- }
- void BFS1(AGraph *g)
- {
- int i=0;
- for(i=0; i<g->n; i++)
- if(visited[i] == 0)
- BFS(g,i);
- }
- //深度遍历的非递归的思想是 采用一个栈
- //把节点的那一行 di yi ge 没有访问过的全部入栈,通过一个while循环,然后就像广度优先遍历采用队列的判断条件类似,此处的判断条件是栈不空
- void DFS2(AGraph *g, int v)
- {
- ArcNode *p = NULL;
- ArcNode *st[MAXV] ;
- int i ,top = -1;
- for(i=0; i<g->n; i++) visited[i] = 0;
- top++;
- st[top] = g->adjlist[v]->firstarc;
- i = st[top]->adjvex;
- while(top > -1)
- {
- p = st[top]; top--;
- while(p != NULL)
- {
- i = st[top]->adjvex;
- if(visited[i] == 0)
- {
- visited[i] = 1;
- top++;
- st[top] = g->adjlist[i]->firstarc;
- break; // 因为是只让第一个节点入栈,所以指向仍然是跳到 头结点
- }
- p = p->nextarc;
- }
- }
- }
- //判断从i节点到j节点是否有路径
- int DFSTrave(AGraph *g, int i,int j)
- {
- int k=0;
- for(k=0; k>g->n; k++) visited[k] = 0;
- DFS(g,i); //通过调用DFS函数来改变数组visited的值
- if(visited[j] == 0) return 0;
- else return 1;
- }
- int BFSTrave(AGraph *g, int i,int j)
- {
- int k=0;
- for(k=0; k>g->n; k++) visited[k] = 0;
- BFS(g,i);
- if(visited[j] == 0) return 0;
- else return 1;
- }
- //判断一个图是否为一个树,则必须是无回路的连通图,或者有n-1条边的连通图,对于连通的判断,可用能否遍历全部顶点来实现
- void DFS3(AGraph *g, int v)
- {
- ArcNode *p;
- int vn=0;
- visited[v] = 1;
- }
- #include <stdio.h>
- typedef struct
- {
- int u; //边的起始顶点
- int v; //边的终止顶点
- int w; //边的权值
- }EdgeType;
- void Prim(MGraph g, int v0)
- {
- int lowcost[MAXV], vset[MAXV],v; //其中新加入的节点放在vset数组内,lowcost数组盛放的权值的最小值
- int i,j,k,min;
- v =v0;
- vset[v0] = 1;
- for(i=0; i<g.n; i++) //此循环的目的是为了初始化表示新加入节点的vset数组,还有表示权值大小的lowcost数组
- if(i != v0)
- {
- lowcost[i] = g.edge[v0][i];
- vset[i] = 0;
- }
- for(j=1; j<g.n; j++) //次循环是为了找到其他n-1个节点
- {
- min = INF;
- for(k=0; k<g.n; k++) //此循环是为了找到 与v0邻接的节点的权值最小值
- {
- if(vset[k] != 0 && lowcost[k] < min)
- {
- min = lowcost[k];
- k = j;
- }
- }
- printf(" 边(%d, %d)权为: %d\n", v,k,min);
- v=k; //v表示刚刚找到的一个与v0相邻的点,然后下面就会以v为点 查找相应的候选边
- vset[k] = 1;
- for(j=0; j<g.n; j++) //此循环的作用是为了修正候选边
- if(vset[v][j] == 0 && g.edge[v][j] < lowcost[j])
- lowcost[j] = g.edge[v][j];
- }
- }
- void InsetSort(EdgeType E[], int n)
- {
- int i,j;
- EdgeType temp;
- for(i=0; i<n; i++)
- {
- temp = E[i];
- j = i-1; //此处取前一个节点
- while(j>=0 && E[j].w > temp.w) //此循环的目的是把比 E[i] 大的元素移送到后面
- {
- E[j+1] = E[j];
- j--;
- }
- E[j+1] = temp;
- }
- }
- void Kruskal(MGraph g)
- {
- EdgeType E[MAXV];
- int i,j,m1,m2,sn1,sn2,k;
- int vset[MAXV];
- k=0;
- for(i=0; i<g.n; i++) //将各个边存到E[]数组中
- for(j=0; j<g.n; j++)
- if(g.edge[i][j] != 0 && g.edge[i][j] != INF)
- {
- E[k].u = i; E[k].v = j; E[k].w = g.edge[i][j];
- k++;
- }
- InseSort(E,g.e);
- for(i=0; i<g.n; i++) vset[i] = i;
- k=1; j=0; //k最后应为 n-1 表示把其余的节点都加入到了数组,j只是为了遍历边的需要
- while(k<g.n)
- {
- m1= E[j].u; m2 = E[j].v;
- sn1 = vset[m1]; sn2 = vset[m2];
- if(sn1 != sn2) //判断选取的边是否与生成树中已保留的边构成回路 通过vset数组
- {
- printf("边(%d, %d) :%d",m1,m2,E[j].w);
- k++;
- for(i=0; i<g.n; i++)
- if(vset[i] == sn2)
- vset[i] = sn1;
- }
- j++;
- }
- }
- //遍历路径中是否包括某节点
- #include <stdio.h>
- int path[MAXV];
- int v1[MAXV],v2[MAXV];
- int vn,vm; //vn保存的是必经节点的个数,v1数组保存的是必经节点,vm 对应的是 必避 节点
- int cond(int path[],int d) //d保存的是path数组里的 元素个数
- {
- int i,j;
- int flag1=0, f1, flag2=0, f2;
- for(i=0; i<vn; i++)
- {
- f1=1;
- for(j=0; j<=d; j++)
- if(path[j] == v1[i])
- {
- f1=0;
- break;
- }
- flag1 += f1;
- }
- for(i=0; i<vm; i++)
- {
- f2=0;
- for(j=0; j<=d; j++)
- if(path[j] == vm[i])
- {
- f2=1;
- break;
- }
- flag2 += f2;
- }
- if(flag1 == 0 && flag2 == 0) return 1;
- else return 0;
- }
- //搜索从vi到vj的路径 采用深度优先算法
- void TravPath(AGraph *g, int vi, int vj, int d)
- {
- int v,i;
- ArcNode *p;
- d++;
- visited[vi] = 1;
- path[d] = vi; //此处进行设置 路径的值 和 visited数组
- if(vi == vj && Cond(path,d) == 1)
- {
- for(i=0; i<=d; i++) printf("%d ",path[i]);
- printf("\n");
- }
- p = g->adjlist[vi]->firstarc;
- while(p != NULL)
- {
- v = p->adjvex;
- if(visited[v] == 0)
- TravPath(g,v,vj,d);
- p = p->nextarc ;
- }
- visited[vi] = 0; //这两步取消标记,使该顶点重新可用
- d--;
- }
- //求邻接矩阵的根,通过遍历每个节点逐个遍历是否满足条件
- //也就是求从一个顶点遍历是否能够到达全部其他顶点,标志量是visited数组的值全部为1
- void MDFS(MGraph g, int v)
- {
- int j;
- visited[v] = 1; //此visited数组的更改在此进行
- for(j=0; j<g.n; j++)
- if(g.edge[v][j] != 0 && g.edge[v][j] != INF && visited[j] == 0)
- MDFS(g,j);
- }
- int DGRoot1(MGraph g)
- {
- int i,j,k,n;
- for(i=0; i<g.n; i++)
- {
- for(j=0; j<g.n; j++) visited[j] = 0;
- MDFS(g,i);
- n = 0;
- for(k=0; k<g.n; k++)
- if(visited[k] == 1) n++;
- if(n == g.n) return i;
- }
- }
- void MBFS(MGraph g, int v)
- {
- int qu[MAXV], front =0, rear = 0;
- int i,j;
- visited[v] = 1;
- rear = (rear + 1) % MAXV;
- qu[rear] = v;
- while(front != rear)
- {
- front = (front + 1) % MAXV;
- i = qu[front];
- for(j=0; j<g.n; j++) //因为此种方法是基于广度的搜索法,所以此处的目的是为了进行一行的计算i表示的具体的行数
- {
- if(g.edge[i][j] != 0 && g.edge[i][j] != INF)
- {
- if(visited[j] == 0)
- {
- visited[j] = 1;
- rear = (rear + 1) % MAXV;
- qu[rear] = j;
- }
- }
- }
- }
- }
- int DGRoot2(MGraph g)
- {
- int i,j,k,n;
- for(i=0; i<g.n; i++)
- {
- for(j=0; j<g.n; j++) visited[j] = 0;
- BDFS(g,i);
- n=0;
- for(k=0; k<g.n; k++)
- if(visited[k] == 1) n++;
- if(n == g.n) return 1;
- else return 0;
- }
- }