图(Graph)

while(!x)相当于x!=1;

while(x)相当于x==1;

一,图的存储方法;

1邻接矩阵存储方法:

1.1类型定义:

#define MAXV 100
typedef struct {
    int no;//定点编号
    char info;//定点其他信息
}VertexType;//定点定义
typedef struct {
    int adjMatrix[MAXV][MAXV];//邻接矩阵
    int vexnum,arcnum;//定点数,弧数
    VertexType Vexs[MAXV];//存放定点信息
}MGragh;//图定义

  1.2用邻接矩阵创建带权无向图:

  • 算法思路
    • 1.输入总顶点数和总边数(为vexnum和arcnum赋值)
    • 2.依次输入点的信息存入顶点表中(为vexs[i]赋值)。
    • 3.初始化邻接矩阵,使每个权值初始化为极大值。
    • 4.构造邻接矩阵
#include <stdio.h>
#include <string.h>

#define Max 999999//无穷大
MGragh CreateAdjMatrix(){
    MGragh G;
    int v1,v2,w;
    scanf("%d %d",&G.vexnum,&G.arcnum);//输入总顶点数,总边数
    for(int i=0;i<G.vexnum;i++){
        scanf("%c",&G.Vexs[i]);//依次输入顶点的信息
        getchar();
    }
    for(int i=0;i<G.vexnum;i++){
        for(int j=0;j<G.vexnum;j++){
            G.adjMatrix[i][j]=Max;//边的权值均置为无穷大
        }
    }
    for(int k=0;k<G.arcnum;k++){
        scanf("%d %d %d",&v1,&v2,&w);//输入一条边所依附的顶点及边的权值
        G.adjMatrix[v1][v2]=w; G.adjMatrix[v2][v1]=w;//边<v1,v2>的权值为w,边<v2,v1>的权值为w
    }
    return (G);
}

1.3输出:

void PrintMG(MGraph MG)// 输出邻接矩阵
{
    int i, j;
    for (i = 0; i < MG.vexnum; i++) {
        for (j = 0; j < MG.vexnum; j++)
            printf("%d", MG.edges[i][j]);
        printf("\n");
    }
}

2.邻接表存储方法

2.1类型定义:

#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define MAXV 9999
typedef  struct ANode{
    int adjvex;//该弧的终点位置
    struct ANode *nextarc;//指向下一条弧的指针
    char info;//该弧的相关信息可为weight
}ArcNode;//定义弧结点
typedef struct Vnode{
    char data;//顶点域,存储顶点信息
    ArcNode *firstarc;//指向第一条弧的表头指针
} VNode;//定义结点
typedef struct {
    VNode AdjList[MAXV];//邻接表
    int Vernum,arcnum;//定点数,边数
    int kind;//图的种类标志
}ALGraph;//定义图类型

 

2.2用邻接表构造无权图

  • 算法思路
    • 1.输入总顶点数和总边数(为vexnum和arcnum赋值)
    • 2.依次输入点的信息存入顶点表中(为AdjList[i].data赋值)。同时初始化邻接表,使每个结点的头指针初始化为NULL。
    • 4.构造邻接表:输入每一条边的两个定点v1,v2。利用中间弧结点s(将s的终点置为v2,s->info赋值为G.AdjList[v2].data),再将s头插进G.AdjList[v1]。(无向图还要构造v1)

 

ALGraph CreatAdjList(ALGraph G){
    scanf("%d %d",&G.Vernum,&G.arcnum);//输入图中顶点总数,弧总数
    scanf("%d",&G.kind);getchar();//kind为0则G为无向图,若kind为1则G为有向图
    for(int i=0;i<G.Vernum;i++){
        scanf("%c",&G.AdjList[i].data);//输入每个定点的相关信息
        getchar();
        G.AdjList[i].firstarc=NULL;//每个定点得头指针置为NULL
    }
    for(int k=0;k<G.arcnum;k++){
        int v1,v2;scanf("%d %d",&v1,&v2);//输入无向图中每一条弧的两个定点
        ArcNode *s=(ArcNode*)malloc(sizeof(ArcNode));
        s->adjvex=v2;//弧结点s的终点结点为v2
        s->info=G.AdjList[v2].data;
        s->nextarc=G.AdjList[v1].firstarc;//头插
        G.AdjList[v1].firstarc=s;//头插
        if(G.kind==0){//无向图的对称性
            ArcNode *t;
            t=(ArcNode*)malloc(sizeof(ArcNode));
            t->adjvex=v1;
            t->info=G.AdjList[v1].data;
            t->nextarc=G.AdjList[v2].firstarc;
            G.AdjList[v2].firstarc=t;
        }
    }
    return (G);
}

2.3输出:

void showALGraph(ALGraph *G){
    for(int v=0;v<G->Vernum;v++){
        printf("%c",G->AdjList[v].data);
        ArcNode *p=G->AdjList[v].firstarc;
        while(p){
            printf("%c",p->info);
            p=p->nextarc;
        }
        printf("\n");
    }
}

 

二,图的遍历

1.深度优先遍历DFS

算法思想:借助visited[MAXV]={0}数组

  1. 从起点开始,访问与其相邻的第一个未被访问的节点。
  2. 如果该节点未被访问,则将其标记为已访问(visited=1)(并将其加入到栈中)。
  3. 继续访问该节点的下一个未被访问的相邻节点,重复步骤2。
  4. 如果该节点没有未被访问的相邻节点,(则从栈中弹出该节点)并返回到上一个节点,重复步骤3。

 

1.1以邻接表为存储结构的DFS

// 深度优先遍历
void DFS(ALGraph G,int v,int visited[]){
    visited[v]=1;// 标记当前顶点已经访问过
    printf("%d ",G.AdjList[v].data);
    ArcNode *p=G.AdjList[v].firstarc;
    while(p!=NULL){
        if(visited[p->adjvex]!=1){
            //如果邻接顶点未被访问过,则递归调用DFS函数继续遍历
            DFS(G, p->adjvex,visited);
        }
        p=p->nextarc;
    }
}
int main(){
    ALGraph G;
    G=CreatAdjList(G);
    int d;scanf("%d",&d);
    int visited[MAXV]={0};
    DFS(G,d-1,visited);
    return 0;
}

 2775b6c8a0ef4cd79be47c3a3f8dbfde.png03ab5e4f1f424d0a88247fd10d39c511.png

1.2以邻接矩阵为存储结构的DFS

 

void DFS(MGragh G,int v,int visited[]){
    visited[v]=1;//标记已经访问的结点
    printf("%d ",G.Vexs[v].no);
    for(int w=0;w<G.vexnum;w++){
        if(G.adjMatrix[v][w]&&visited[w]!=1)DFS(G,w,visited);
    }
}
int main(){
    MGragh G;
    G=CreateAdjMatrix();
    int visited[MAXV]={0};
    int v0;scanf("%d",&v0);//从V0开始遍历
    DFS(G,v0-1,visited);
    return 0;
}

 

2.广度优先遍历BFS

算法思想:借助visited[MAXV]数组和队列

  1. 从起点开始,将起点加入到队列中。
  2. 从队列中取出队首元素,并访问与其相邻的所有未被访问的节点
  3. 将这些节点标记为已访问,并将其加入到队列中。
  4. 重复步骤2和3直到队列为空

2.1以邻接表为存储结构的BFS

// 广度优先遍历
void BFS(ALGraph G, int v, int visited[]) {
    SqQueue Q;  // 定义队列
    Q=initSqQueue();
    printf("%d ", G.AdjList[v].data);  // 访问初始顶点v并打印顶点值
    visited[v] = 1;  // 标记顶点v已访问
    Q.data[Q.rear++] = v;  // 顶点v入队
    while (Q.front != Q.rear) {  // 队列不空
        int j = Q.data[Q.front++];  // 出队
        ArcNode *p = G.AdjList[j].firstarc;
        while (p != NULL) {
            if (visited[p->adjvex]!=1) {//结点未被访问
                printf("%d ", G.AdjList[p->adjvex].data);  // 打印顶点值
                visited[p->adjvex] = 1;  // 标记顶点已访问
                Q.data[Q.rear++] = p->adjvex;  // 该顶点入队
            }
            p = p->nextarc;
        }
    }
}

int main(){
    ALGraph G;
    G=CreatAdjList(G);
    int d;scanf("%d",&d);//输入遍历初始点d
    int visited[MAXV]={0};
    BFS(G,d-1,visited);
    return 0;
}
typedef struct{
    int data[MAXV+1];
    int front,rear;
}SqQueue;//队列
SqQueue initSqQueue(){//初始化队列
    SqQueue q;
    q.front=0;
    q.rear=0; // 队头和队尾指针
    return q;
}

c4eb29907d19460a902799438dc8fd54.png03ab5e4f1f424d0a88247fd10d39c511.png

 

三,最小生成树

G(n,e)    →    MST:1️⃣n个顶点,n-1条边;2️⃣连通无回路;3️⃣权值最小;

1.prim算法

1.1算法思想:

U和V-U两个阵营中不停的找一条最短的(代价最低的)可连通的边,然后将该边附着的在V-U阵营中的顶点加入U阵营中。00f8c4c8708642f4b2b345d76cacb6ab.png

1.2 代码

void MiniSpanTree_Prim(MGraph *G,Vertex start){
    ShortEdge ShortEdge[VexMAx];
    int vset[G->vexnum];//辅助数组记录顶点位置未访问0访问1
    int k=LocateVex(G,start);//定位初始点的位置
    for(int i=0;i<G->vexnum;i++){
        if(i!=k){//非k的顶点放入v-u的集合
            ShortEdge[i].adjvex=start;//候选最短边的邻接点初置为start
            ShortEdge[i].lowcost=G->AdjMatrix[k][i];
            vset[i]=0;
        }
    }
        vset[k]=1;//lowcost为1表示该顶点属于U集合
        for(int i=0;i<G->vexnum;i++){//找最短路径的顶点
            int min=-1;
            for(int j=0;j<G->vexnum;j++){
                if(vset[j]!=1&&ShortEdge[j].lowcost<min){
                    min=ShortEdge[j].lowcost;
                    k=j;//求出T的下一个结点:第k个结点
                }
            }
            vset[k]=1;//第k个定点并入U集合
            for(int j=0;j<G->vexnum;j++){//有更短路径出现时,将其替换进shortedge数组
                if((vset[j]==0)&&(G->AdjMatrix[k][j]<ShortEdge[j].lowcost)){//有更短路径出现时,将其替换进shortedge数组
                    ShortEdge[j].adjvex=G->vexs[k];
                    ShortEdge[j].lowcost=G->AdjMatrix[k][j];
                }
            }
        }
}
typedef struct{//辅助数组结构体(候选最短边)
    Vertex adjvex;//候选最短边的邻接点
    int lowcost;//候选最短边的权值
}ShortEdge;
int LocateVex(MGraph *G,Vertex v1){//查找元素v在一维数组 Vertex[] 中的下标,并返回下标
    int flag=-1;
    for(int i=0;i<G->vexnum;i++){
        if(v1.info==G->vexs[i].info)flag=i;
    }
    return flag;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define VexMAx  100//最大顶点数为100
#define MaxInt 9999//表示最大整数,表示 ∞

typedef struct{
    int no;
    char info;
}Vertex;
typedef struct{
    int AdjMatrix[VexMAx][VexMAx];
    int vexnum,arcnum;
    Vertex vexs[VexMAx];
}MGraph;
void CreateAdjMatrix(MGraph *G);
int LocateVex(MGraph *G,Vertex v);
void print(MGraph G);
void MiniSpanTree_Prim(MGraph *G,Vertex start);

int main(){
    MGraph G;
    CreateAdjMatrix(&G);
    print(G);
    printf("请输入起始点:");Vertex start;
    scanf("%c",&start.info);
    MiniSpanTree_Prim(&G,start);
}
void CreateAdjMatrix(MGraph *G){//构造以邻接矩阵为存储结构的无向图
    printf("输入顶点个数和边数:\n");
    printf("顶点数 n=");
    scanf("%d",&G->vexnum);
    printf("边  数 e=");
    scanf("%d",&G->arcnum);
    printf("\nvexnum=%d\n",G->vexnum);
    
    //2.输入顶点元素
    printf("输入顶点元素:");
    for(int k=0;k<G->vexnum;k++){
        printf("%d是 ",k);
        scanf("%c",&G->vexs[k].info);
        G->vexs[k].info=getchar();
    }
    for(int i=0;i<G->vexnum;i++){
        printf("%c",G->vexs[i].info);
    }
    //3.矩阵初始化
    for(int i=0;i<G->vexnum;i++)
    for(int j=0;j<G->vexnum;j++){
         G->AdjMatrix[i][j]=MaxInt;
    }
    //4.构建邻接矩阵
    int a,b,weight;//v1->v2的权值
    Vertex v1,v2;
    printf("请输入边的信息和权值(a b 9):\n");
    for(int i=0;i<G->arcnum;i++){
        scanf("%c %c %d",&v1.info,&v2.info,&weight);
        //printf("\nv1.info=%c v2.info=%c weight=%d\n",v1.info,v2.info,weight);
        a=LocateVex(G,v1); //获取v1所对应的在Vertex数组中的坐标
        b=LocateVex(G,v2); //获取v2所对应的在Vertex数组中的坐标
        if(a==-1||b==-1)printf("NO This Vertex!\n");
    }
    G->AdjMatrix[a][b]=weight;
    G->AdjMatrix[b][a]=weight;//无向网仅此处不同
}
void print(MGraph G){
    int i,j;
    printf("\n-------------------------------");
    printf("\n 邻接矩阵:\n\n");
        printf("\t ");
        for(i=0;i<G.vexnum;i++)
        printf("\t%c",G.vexs[i]);
        printf("\n");
        for(i=0;i<G.vexnum;i++){
             printf("\t%c",G.vexs[i]);
             for(j=0;j<G.vexnum;j++){
             if(G.AdjMatrix[i][j]==MaxInt) printf("\t∞");
             else printf("\t%d",G.AdjMatrix[i][j]);
        }
          printf("\n");
       }
}

 

 

 

四,最短路径

 

五,拓扑排序

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值