邻接矩阵
存储结构
#define MaxVertexNum 100//顶点数目的最大值
typedef char VertexType ;//顶点的数据类型 不同情况不一样
typedef int EdgeType ;//整数表示权值或者连通性
typedef struct
{
VertexType Vex[MaxVertexNum];//顶点表
EdgeType Edge[MaxVertexNum][MaxVertexNum] ;//邻接矩阵(二维数组),边表
int vexnum , arcnum ;//图的当前顶点数和弧数
}MGraph;
基本操作
顶点插入
//插入顶点
void InsertVertex(MGraph *g,char x)
{
//printf("开始插入");
if(g->vexnum<100){
g->Vex[g->vexnum]=x;
g->vexnum++;
}
else{
printf("顶点存储已满,无法插入");
}
}
删除操作
在删除操作时需要注意,与该顶点有关的边要全部删除,例如要删除b相关的边,则需要先删除与b相关的行再删除与其相关的列
//删除顶点(也会删除该顶点关联的边)
void DeleteVertex(MGraph *g,char x){
MGraph gr=*g;
int i=getVex(gr,x); //获取顶点对应的顶点表中的标号
if(i==-1){
printf("\n不存在这样的点,无法删除!\n");
return;
}else{
for(int s=0;s<g->vexnum;s++){
if(g->Edge[i][s]!=0){
g->arcnum--;
//printf("\nEdge[%d][%d],边数:%d",i,s,g->arcnum);
}
if(g->Edge[s][i]!=0){
g->arcnum--;
//printf("\nEdge[%d][%d],边数:%d",s,i,g->arcnum);
}
}//先进行相关联边的遍历,然后对总边数进行修改
for(int j=i;j<g->vexnum;j++){
g->Vex[j]=g->Vex[j+1];//对顶点表的修改
for(int m=0;m<g->vexnum;m++){
g->Edge[j][m]=g->Edge[j+1][m];
}
}//删除一行操作
for(int n=i;n<g->vexnum;n++){
for(int m=0;m<g->vexnum-1;m++){
g->Edge[m][n]=g->Edge[m][n+1];
}
}//删除一列操作
g->vexnum--;//顶点数进行修改
printf("\n点%c删除完成\n",x);
}
}
边的插入、删除和判断两点之间是否有边操作
Adjacent函数这里只用于有向图的判断,如果使用无向图的判断,那么需要多加一个或判断g.Edge[j][i]!=0
//增加边
void AddEdge(MGraph *g,char x,char y){
MGraph gr=*g;
int i=getVex(gr,x); //获取顶点对应的顶点表中的标号
int j=getVex(gr,y);//获取顶点对应的顶点表中的标号
if(i==-1||j==-1){
printf("\n不存在这样的顶点可以插入边!\n");
return;
}else{
if(g->Edge[i][j]==0){
g->Edge[i][j]=1;
g->arcnum++;
}
else{
printf("这两点已存在边,插入边失败!");
}
}
}
//判断x和y中是否有边
bool Adjacent(MGraph g,char x,char y){
int i=getVex(g,x);
int j=getVex(g,y);
if(i==-1||j==-1){
printf("\n不存在这样的顶点!\n");
return false;
}else if(g.Edge[i][j]!=0){
return true;
}
return false;
}
//删除边<x,y>(如果存在)
void RemoveEdge(MGraph *g,char x,char y){
MGraph gr=*g;
if(Adjacent(gr,x,y)){//Adjacent判断x和y中是否存在边,存在即返回true
int i=getVex(gr,x);
int j=getVex(gr,y);
g->Edge[i][j]=0;
g->arcnum--;
}else{
printf("\n所要删除的边不存在");
}
}
边的设置权值和获取权值操作
//获得<x,y>对应的权值
int Get_edge_value(MGraph g,char x,char y){
if(Adjacent(g,x,y)){
int i=getVex(g,x);
int j=getVex(g,y);
return g.Edge[i][j];
}else{
printf("两点之间没有边\n");
return -1;
}
return -1;
}
//设置<x,y>之间的权值
bool Set_edge_value(MGraph *g,char x,char y,int v){
MGraph gr=*g;
if(Adjacent(gr,x,y)){
int i=getVex(gr,x);
int j=getVex(gr,y);
g->Edge[i][j]=v;
return true;
}else{
printf("\n两点之间没有边,无法设置权值!\n");
return false;
}
return false;
}
获取第一个邻接点和下一个邻接点操作
//求顶点的第一个邻接点
int FirstNeighbor(MGraph g,char x){
int i=getVex(g,x);
if(i!=-1){
for(int j=0;j<g.vexnum;j++){
if(g.Edge[i][j]!=0||g.Edge[j][i]!=0){
return j;
}
}
}
return -1;
}
//求顶点x在y之后的邻接点
int NextNeighbor(MGraph g,char x,char y){
if(!Adjacent(g,x,y)){
printf("%c和%c不是邻接点 ",x,y);
return -1;
}else{
int i=getVex(g,x);
int j=getVex(g,y);
if(i!=-1&&j!=-1){
for(j=j+1;j<g.vexnum;j++){
if(g.Edge[i][j]!=0||g.Edge[j][i]!=0){
return j;
}
}
}
}
return -1;
}
邻接法
存储结构
#define MaxVertexNum 100 //图中顶点数目的最大值
typedef struct ArcNode{ //边表结点
int djvex; //该弧指向的顶点位置
struct ArcNode *next; //指向下一条弧的指针
//InfoType info //边的边权值
}ArcNode;
typedef struct VNode { //顶点表结点
VertexType data; //顶点信息
ArcNode *first; //指向第一条依附该顶点的弧的指针
}VNode , AdjList[MaxVertexNum];
typedef struct {
AdjList vertice; //邻接表
int vexnum , arcnum; //图的顶点和弧数
}ALGraph; //ALGraph是以邻接表存储的图类型
基本操作:
建立有向图
//建立有向图
void CreateDGGraph(ALGraph &G)
{
int m, n; //边<Vm,Vn>的下标
ArcNode *vm, *vn;//构成边<Vm,Vn>的两个顶点
cout << "请输入顶点数和边数:";
cin >> G.vexnum >> G.arcnum;
cout << "请输入顶点的信息:" << endl;
//获取顶点信息
for(int i=0; i<G.vexnum; i++)
{
cin >> G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
//建立邻接表,采用头插法
for(int i=0; i<G.arcnum; i++)
{
cout << "请输入<Vi,Vj>的下标:";
cin >> m >> n;
vm(ArcNode*)malloc(sizeof(ArcNode));
vm->adjvex=n;
vm->nextarc=NULL;
if(G.vertices[m].firstarc==NULL)
{
vn=G.vertices[m].firstarc=vm;
}
else{
vn=vn->nextarc=vm;
}
}
}
建立无向图
//建立无向图
void CreateUDGGraph(ALGraph &G)
{
int m, n; //边<Vm,Vn>的下标
ArcNode *pe;
cout << "请输入顶点数和边数:";
cin >> G.vexnum >> G.arcnum;
cout << "请输入顶点的信息:" << endl;
//获取顶点信息
for(int i=0; i<G.vexnum; i++)
{
cin >> G.vertices[i].data;
G.vertices[i].firstarc=NULL;
}
//建立邻接表,采用头插法
for(int i=0; i<G.arcnum; i++)
{
cout << "请输入<Vi,Vj>的下标:";
cin >> m >> n;
pe=(ArcNode*)malloc(sizeof(ArcNode));
pe->adjvex=n;
pe->nextarc=G.vertices[m].firstarc;
G.vertices[m].firstarc=pe;
pe=(ArcNode*)malloc(sizeof(ArcNode));
pe->adjvex=m;
pe->nextarc=G.vertices[n].firstarc;
G.vertices[n].firstarc=pe;
}
}
输出邻接表
void PrintALGraph(ALGraph &G)
{
ArcNode *p;
for (int i=0;i<G.vexnum;i++)
{
cout << "顶点" << i << "(" << G.vertices[i].data << ") "": ";
for (p=G.vertices[i].firstarc; p!=NULL;p=p->nextarc)
cout << p->adjvex << "(" << G.vertices[p->adjvex].data << ") ";
if (p==NULL)
cout << endl;
}
}
顶点v的第一个邻接点
//求图中顶点v的第一个邻接点,若有则返回顶点下标。若v没有邻接点或图中不存在v,则返回-1
int FirstNeighbor(ALGraph G, int v)
{
ArcNode *next=G.vertices[v].firstarc;
if(next)
{
return next->adjvex;
}
return -1;
}
顶点v的下一个邻接点
//返回除顶点v外的下一个顶点w
int NextNeighbor(ALGraph G, int v, int w)
{
ArcNode *next=G.vertices[v].firstarc;
while(next)
{
if(next->adjvex==w)break;
next=next->nextarc;
}
if(next)
{
ArcNode *nextNode=next->nextarc;
if(nextNode)
{
return nextNode->adjvex;
}
}
return -1;
}
访问结点v
void visit(ALGraph G, int v)
{
cout << G.vertices[v].data << " ";
}
主函数编写
int main()
{
ALGraph G;
//CreateALGraph(G);
int tag; //有向无向图标志
cout << "请输入1(有向图),2(无向图):";
cin >> tag;
if(tag==1)
{
G.kind=DG;
CreateDGGraph(G); //建立有向图
}
else
{
G.kind=UDG;
CreateUDGGraph(G); //建立无向图
}
cout << "===========================" << endl;
PrintALGraph(G);
cout <<endl;
cout << "广度遍历:";
BFSTraverse(G);
cout << endl;
cout << "深度遍历:";
DFSTraverse(G);
return 0;
}
遍历
广度优先搜索遍历(BFS)
类属于二叉树的层序遍历算法,借助队列+辅助标记数列
int visit[100]; //标记数组
void BFS(Graph G ,int v){
visit(v); //访问初始节点v
visited[v] = 1; //标记
EnQueue(Q ,v); //入队起点
while( ! is Empty(Q)){
DeQueue(Q , v); //出队,v去接受出队的值
for(w = FirstNeighbor (G , v) ; w >= 0 ; w = NextNeighbor(G , v ,w)){
//检测v所有邻接点
if( !visited[w]){ //未被标记的邻接入队
visit(w); //访问顶点w
visited[w] = 1; //标记
EnQueue(Q ,w); //入队
}
}
}
}
void BFSTrarerse(Graph G){
for( int i = 0 ; i <G.vexnum ; i++){//对访问数组初始化
visit(i) = 0;
}
InitQueue(Q); //初始化辅助队列Q
for(int i = 0 ; i <G.vexnum ; i++){ //从0号顶点开始遍历
if( !visited[i]){ //对每个连接分量调用一次BFS
BFS(G , i);
}
}
}
BFS应用:单源非带权图最短路径
void BFS_MIN_Distance(Graph G, int u){
for(i=0;i<G.vexnum;++i) d[i] = ∞ ;//d[i]表示从u到i结点的最短路径
visited[u] = TRUE ;
d[u] = 0 ;
EnQueue(Q,u) ;
while(!IsEmpty(Q)){
DeQueue(Q,u) ;
ArcNode *p = G->adjList[u].firstedge;
while(p){
if(!visited[p->adjvex]){
visited[p->adjvex] = TRUE ;
d[p->adjvex] = d[u]+1 ;//路径长度加1
EnQueue(Q,p->adjvex) ;
}
p=p->next;
}
}
}
//王道伪代码
void BFS_MIN_Distance(Graph G, int u){
for(i=0;i<G.vexnum;++i) d[i] = ∞ ;//d[i]表示从u到i结点的最短路径
visited[u] = TRUE ;
d[u] = 0 ;
EnQueue(Q,u) ;
while(!IsEmpty(Q)){
DeQueue(Q,u) ;
for(w = FirstNeighbor( Q , r ) ; w >= 0 ; w = NextNeighbor( Q , u , w ) ){
if(!visited[w]){
visited[w] = TRUE ;
d[w] = d[u]+1 ;//路径长度加1
EnQueue(Q,w) ;
}
}
}
}
图的深度优先遍历(DFS)
#define MaxSize 100
bool visited[MaxSize] ;
void DFS(Graph G, int v){
ArcNode *p ; //工作指针p
visit(v); //访问顶底v(一般是打印,printf)
visited[v] = TRUE ;//修改访问标记
p = G->djList[v].firstarc;//指针p开始指向该顶点的第一条边
while(p!=NULL){//没遍历完顶点的所有邻接顶点
if(!visited[p->djvex]){//如果该顶点没被访问
DFS(G,p->djvex);//递归访问该顶点
}
p=p->nextarc ;//看还有没有其他未访问的顶点
}
}
void DFSTraverse(Graph G){
int i ;//单独定义是为了方便多个循环中使用
for (i=0;i<G->vexnum ; i++){
visited[i] = false ;//将标志数组初始化 (全局数组)
}
for (i=0;i<G->vexnum ; i++){
if(!visited[i])
DFS(G,i);//对所有
}
}
算法
判断图是否联通
bool visited[MaxVertexNum]; //访问标记数组
//从顶点v出发,采用递归,深度遍历图G
void DFS(ALGraph G, int v)
{
visit(G, v); //访问v
visited[v]=true; //设已访问标记
for(int w=FirstNeighbor(G, v); w>=0; w=NextNeighbor(G, v, w))
{ //w为v的尚未访问的邻接顶点
if(!visited[w])
{
DFS(G, w);
}
}
}
//判断一个图是否连通
bool Judge(ALGraph G)
{
for(int v=0; v<G.vexnum; v++)
{
visited[v]=false;
}
DFS(G, 0); //从任意一点遍历,这里从下标为0的点开始
for(int v=0; v<G.vexnum; v++)
{
if(!visited[v])
{
return false;
}
}
return true;
}
邻接表转换成邻接矩阵
思想:设图的顶点分别储存在v[n]中。所以需要先初始化邻接矩阵,再遍历邻接表,依次修改邻接矩阵的第i行的元素值。
若链表边结点为j,则设置arcs[i][j] = 1。当遍历完邻接表时,转换过程也结束了
void Convert(ALGraph &G ,int arcs[M][N]){
//此算法将邻接表方式表示的图G转换为邻接矩阵arcs
for( i=0 ; i<n ; i++){ //依次遍历各顶点表结点为头的边链表
p = ( G->v[i]).firstarc; //取出顶点i的第一条出边
while( p != NULL){ //遍历边链表
arcs[i][p->data] = 1;
p = p->nextarc; //取下一条出边
}
}
}
检验无向图G时否是树
若是一棵树,返回true;不是则返回false
思想:因为G是一棵树必须有n-1条边的连通图,则用深度优先探索算法遍历可能访问到的顶点个数和边个数,若一次就能访问到n个顶点和n-1条边,则是一棵树
bool isTree(Graph &G){
for(int i = 0 ; i < G.vexnum ; i++)
visited[i] = false;
int Vnum=0 , Enum = 0; //记录顶点数和边数
if(Vnum == G ,vexnum && Enum == 2*(G.vexnum-1))
return true; //符合树的条件
else
return false; //不符合树的要求
}
void DFS(Graph &G , int v, int &Vnum , int &Enum , int visited[]){
//深度遍历图G,统计访问过的定点数和边数,通过Vnum和Enum返回
visited[v] = true; //作为标记,顶点计数
Vnum++;
int w = FirstNeighbor(G , v); //取v的第一个邻接顶点
while( w!= -1){ //当邻接顶点存在时
Enum++; //则边存在,计数
if( !visited[w]) //当邻接顶点未被访问
DFS(G , w , Vnum , Enum , visited);
w = NextNeighbor(G ,v, w);
}
}
深度优先遍历算法DFS的非递归方法
利用栈来实现,记忆下一步可能访问的顶点,用visited[ i ]数组来记录第 i 个顶点是否在栈内或曾经再栈内。图用邻接表形式。
void DFS_Non_RC(AdGraph &G , int v){
//从顶点v开始一个个进行深度优先搜索,一次遍历一个连通分量的所有顶点
int w; //顶点序号
InitStack( S ); //初始化栈S
for( i = 0 ; i < G.vexnum ; i++)
visited[i] = false;
Push( S , v);
visited[ v ] = true;
while ( !IsTmpty(S)){
k = Pop(S); //从栈推出一个顶点
visit(k); //先访问,再将其子节点入栈
for( w = FirstNeighbor(G , k) ; w < G.vexnum ; w= NextNeighbor(G , k ,w)){
if( !visited[w]){ //若没有进栈则进栈,再标记
Push( S , w);
visited[w] = true;
}
}
}
}
检测是否存在结点 I 到结点 J 的路径
广度优先遍历BFS:
int visited[MaxSize] = {0}; //访问标记数组
int BFS(ALGraph &G , int i .int j){
InitQueue(Q);
EnQueue(Q , i);
while( !isTmpty(Q)){
DeQueue(Q , U); //队头顶点出队
visited[u] = 1; //置访问标记
if( u== j)
return 1;
for( int p = FirstNeighbor(G , i) ; p ; p = NextNeighbor( G , u , p)){
if(p == j)
return 1;
if( !visited[p]){
EnQueue( Q , p);
visited[p] = 1;
}
}
}
}
深度优先遍历DFS:
int visited[ MaxSize ] = {0};
void DFS(ALGraph &G , int i ,int j , bool &can_reach){
//遍历全部结点,检测是否有路径,用can_reach来标识
if( i == j){
can_reach = true;
return;
}
visited[i] = 1; //放置访问标记
for( int p = FirstNeighbor( G , i) ; p >0 ; p = NextNeighbor(G ,i, p )){
if( !IsEmpty( p ) && !can_reach )
DFS( G , p , j , can_reach);
}
}
输出顶点 i 到 顶点 j 的所有简单路径
思路:用递归的深度优先遍历算法,从结点u出发递归深度遍历图中的结点,若访问到结点v,则输出该搜索路径上的结点。
设置一个path数组来存放路径节点,d为路径长度(开始为-1),用邻接表来表示图G
void FinePath(ALGraph &G , int i , int j , int path[] , int d){
//设置path数组来存放路径上的结点,d表示路径长度
int a , b;
ArcNode *p;
d++;
path[d] = i; //让第一个i添加到路径上
visited[i] = 1; //标记
if( i == j)
printf(path[]); //输出路径上的结点
p = G->adjlist[i].firstarc; //p指向i的第一个相邻点
while( p!= NULL){
a = p->adjvex; //若a没有被访问,则访问他
if( visited[a] == 0)
FinPath(G , a ,j .path ,d);
p = p->nextarc; //指向下一个相邻点
}
visited[i] = 0; //回复环境,使得该顶点可重复使用
}
利用DFS法实现有向无环图拓扑排序
设有向无环图G中的任意结点u,v,则u和v存在三种关系
1.u是v的祖先:访问u的时候,必须先递归一次v,也就是对v结束的时间要先于u;可以设置一个时间坐标time以记录
2.u是v的子孙,则如1一样,u要比v快
3,u和v无关系,则关系任意
bool visited[ MaxSize ];
void DFSTraverse( Graph &G ){
for(i = 0 ; i < G.vexnum ; i++)
visited[i] = false;
time = 0;
for( i = 0 ; i < G.vexnum ; i++){
if( !visited[i] )
DFS(G , i)
}
}
void DFS(Graph &G , int i ){
visited[i] = true;
visit(i);
for( w = FirstNeighbor ; w < G.vexnum ; w = NextNeihbor){
if( !vsited[w] ) //以w为u的尚未访问的邻接结点
DFS(G , w);
}
time = time+1;
finishTime[v] = time;
}
最小生成树
素数算法Prime
思路:
1.初始化,将第一个顶点连接的边都列入weight中
2.找到目前与i相邻最小的边
3.//找到与i相连的其他边中的最小顶点,若比原本的min_arc小则上位
void MST_Prim(Graph G){
int min_weight[G.vexnum]; //存放顶点到其他顶点的权值
int adjvex[G.vexnum]; //记录结点数是被谁引用的
for( int i = 0 ; i <G.vexnum ; i++){ //初始化,将第一个顶点连接的边都列入weight中
min_weight[i] = G.edge[0][1]; //第一个顶点到每一条边的距离
adjvex[i]=0;
}
int min_vex; //最小顶点下标
int min_arc; //最小边
for(int i = 1 ; i<G.vexnum ; i++){ //找到目前与i相邻最小的边
min_arc = MAX; //令最小变最大,放便找最小值
for( int j = 1 ; j < G.vexnum ; j++ ){
if( min_weight[j] != 0 && min_weight[j] < min_arc ){
min_arc = min_weight[j]; //专门找最小的边
min_vex = j; //记录最小边的下标
}
}
min_weight[min_vex] = 0; //使其准备入结果树
for( int j = 0 ; j < G.vexnum ; j++ ){ //找到与i相连的其他边中的最小顶点,若比原本的min_arc小则上位
if( min_weight[j] != 0 && min_weight[j] < min_arc ){
min_weight[j] = G.edge[min_arc][j];
adjvex[j]=min_arc;
}
}
}
}
克鲁斯卡尔算法Kruskal
typedef struct{
int u; //边的起始顶点
int v; //边的终止顶点
int w; //边的权值
}Edge;
void Kruskal( MGraph G){
int i , j , u1 , v1 , s1 , s2 , k;
int vest[MAX];
Edge E[MAX]; //存放所有边
k = 0; //E数组下标从0开始计数
for(i = 0 ; i < G->vexnum ; i++){ //从G产生的边集E
for( j = 0 ; j < G->vexnum ; j++){
if( G.edges[i][j] != 0 && G.edges[i][j] != INF){
E[k].u = i;
E[k].v = j;
E[k].w = G.edges[i][j];
k++;
}
}
}
InitSort( E , G.e); //用直接插入排序对E数组进行权值递增排序
for( i = 0 ; i < G.n ; i++){ //初始化辅助数组
vest[i] = i;
k = 1; //k表示当前构造生成树的第几条边,初值为1
j = 0; //E中边的下标,初值为0
while( k < G.n ){ //生成的边数小于n时循环
u1 = E[j].u; //取一条边的头尾节点
v1 = E[j].v;
s1 = vest[u1]; //分别得到两个顶点所属的集合编号
s2 = vest[v1];
if( s1 != s2 ){ //两顶点属于不同的集合
printf("(%d,%d):%d\n" , u1,v1,E[j].w);
k++; //生成边数+1
for( i = 0 ; i < G.n ; i++ ){
if(vest[i] == s2 )
vest[i] = s1;
}
}
j++; //扫描下一条边
}
}
最短路径问题
迪杰斯特拉算法(Dijkstra)
#define INF 32767 //INF表示无穷
//迪杰斯特拉算法(Dijkstra)
void Dijkstra( MGraph G , int v){
int dist[MaxVerterNum],path[MaxVerterNum]; //path[]表示从顶点v到顶点u的最短路径
int s[MaxVerterNum];
int mindis , i , j ,u;
for( i = 0 ; i < G.vexnum ; i++ ){
dist[i] = G.Edge[v][i]; //距离初始化
s[i] = 0; //s[]置空
if(G.Edge[v][i] == NULL) //路径初始化
path[i] = v; //从顶点v到i有边时,置顶点i之前的顶点为v
else
path[i] = -1; // 从顶点v到i有边时,置顶点i之前的顶点为-1
}
s[v] = 1; //原点编号v放入s中
path[v] = 0;
for(i = 0 ; i < G.vexnum ; i++){ //循环直到所有顶点的最短路径求粗
mindis = NULL; //mindis置最小长度初值
for(j = 0 ; j < G.vexnum ; j++){ //选取不在s中且具有最小距离的顶点u
if(s[j] == 0 && dist[j] < mindis){
u = j;
mindis = dist[j];
}
s[u] = 1; //顶点u加入s中
for( j = 0 ; j < G.vexnum ; j++){ //修改不在s中的顶点的举例
if(s[j] == 0){
if(G.Edge[u][j] < INF && dist[u]+G.Edge[u][j] < dist[j]){
dist[j] = dist[u]+G.Edge[u][j];
path[j] = u;
}
}
}
}
}
Dispath(dist , path , s , G.vexnum , v); //输出最短路径
}
弗洛伊德算法(Floyd)
void Floyd(AdjMatrix *G)
{
int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];
int i,j,k;
//初始化
for (i=0;i<G->vexnum;i++)
{
for (j=0;j<G->vexnum;j++)
{
A[i][j]=G->Edge[i][j];
path[i][j]=-1;
}
}
//三重循环,floyd算法核心
for (k=0;k<G->vexnum;k++)
{
for (i=0;i<G->vexnum;i++)
{
for (j=0;j<G->vexnum;j++)
{
if (A[i][j]>A[i][k]+A[k][j])
{
A[i][j]=A[i][k]+A[k][j];
path[i][j]=k;
}
}
}
}
Dispath(A,path,G->vexnum);//输出函数
}
拓扑排序
//拓扑排序
typedef struct{
int data; //顶点信息
int count; //存放顶点入度
ArcNode*first; //指向第一条弧
}VNode;
void TopSort (VNode adj[] , int n){
int i , j;
int S[MaxVerterNum];
int top = -1; //栈S的指针为top
ArcNode *p;
for( i = 0 ; i <n ; i++){
if(adj[i].count == 0){ //入度为0的顶点入栈
top++;
S[top]=i;
}
}
while(top >-1){ //栈不为空则循环
i = S[top]; //出栈
top--;
printf("%d" , i);
p = adj[i].first;
while( p!= NULL ){
j = p->adjvex;
adj[j].count--;
if(adj[j].count == 0){
top++;
S[top] = j;
}
p = p->next; //找下一个相邻顶点
}
}
}
邻接表转化为逆邻接表
void Reverse(ALGraph A,ALGraph &B)
{
int i,k;
ArcNode *p1,*p2;
B.vn=A.vn;
B.en=A.en;
for(i=1; i<=A.vn; i++)
{
scanf("%c",&B.adjlist[i].data);
B.adjlist[i].firstarc=NULL;
}
for(i=1; i<=A.vn; i++)
{
p1=A.adjlist[i].firstarc;
while(p1)
{
k=p1->adjvex;
p2=(ArcNode *)malloc(sizeof(ArcNode));
p2->adjvex=i;
p2->nextarc=B.adjlist[k].firstarc;
B.adjlist[k].firstarc=p2;
p1=p1->nextarc;
}
}
}
无向图邻接矩阵转换为邻接表
//以下定义邻接矩阵类型
typedef struct
{
int vexs[MAXV];
int arcs[MAXV][MAXV];
int vexnum,arcnum;
} MGraph;
//以下定义邻接表类型
typedef struct ANode
{
int adjvex;
struct ANode *nextarc;
} ArcNode;
typedef struct Vnode
{
int data;
ArcNode *firstarc;
} VNode;
typedef struct
{
VNode vertices[MAXV];
int vexnum,arcnum;
} ALGraph;
void MatToList(MGraph g,ALGraph *&G){
//将邻接矩阵g转换成邻接表G
int i,j;
ArcNode *p,*s;
G=(ALGraph *)malloc(sizeof(ALGraph));
for (i=0; i<g.vexnum; i++)
G->vertices[i].firstarc=NULL;
for (i=0; i<g.vexnum; i++)
for (j=0; j<g.vexnum; j++)
if (g.arcs[i][j]!=0){
p=(ArcNode *)malloc(sizeof(ArcNode));
p->adjvex=j; p->nextarc=NULL;
if(!G->vertices[i].firstarc)
G->vertices[i].firstarc=p;
else{
s=G->vertices[i].firstarc;
while(s->nextarc) s=s->nextarc;
s->nextarc=p;
}
}
G->vexnum=g.vexnum;
G->arcnum=g.arcnum;
}