数据结构之--图的讲解与C语言实现

数据结构–图

图是研究数据元素之间的多对多的关系。在这种结构中,任意两个元素之间可能存在关系。即结点之间的关系可以是任意的,图中任意元素之间都可能相关。图的应用极为广泛,已渗入到诸如语言学、逻辑学、物理、化学、电讯、计算机科学以及数学的其它分支。

图的定义

一个图(G)定义为一个偶对(V,E) ,记为G=(V,E) 。其中: V是顶(Vertex)的非空有限集合,记为V(G);E是无序集V&V的一个子集,记为E(G) ,其元素是图的弧(Arc)。将顶点集合为空的图称为空图。其形式化定义为:G=(V ,E),V={v|v in data object},
E={(v,w)| v,w in V and p(v,w)},P(v,w)表示从顶点v到顶点w有一条直接通路。

图的结构

图的存储结构比较复杂,其复杂性主要表现在:
任意顶点之间可能存在联系,无法以数据元素在存储区中的物理位置来表示元素之间的关系。
图中顶点的度不一样,有的可能相差很大,若按度数最大的顶点设计结构,则会浪费很多存储单元,反之按每个顶点自己的度设计不同的结构,又会影响操作。
图的常用的存储结构有:邻接矩阵、邻接链表、十字链表、邻接多重表和边表。
这里写图片描述

在图的邻接链表表示中,所有顶点结点用一个向量 以顺序结构形式存储,可以随机访问任意顶点的链表,该向量称为表头向量,向量的下标指示顶点的序号。
用邻接链表存储图时,对无向图,其邻接链表是唯一的,对有向图,其邻接链表有两种形式。
这里写图片描述
这里写图片描述

图的遍历

深度优先搜索(DFS):深度优先搜索(Depth First Search–DFS)遍历类似树的先序遍历,是树的先序遍历的推广。
设初始状态时图中的所有顶点未被访问,则:
⑴ :从图中某个顶点vi出发,访问vi;然后找到vi的一个邻接顶点vi1 ;
⑵:从vi1出发,深度优先搜索访问和vi1相邻接且未被访问的所有顶点;
⑶:转⑴ ,直到和vi相邻接的所有顶点都被访问为止
⑷ :继续选取图中未被访问顶点vj作为起始顶点,转(1),直到图中所有顶点都被访问为止。
广度优先搜索(BFS):广度优先搜索(Breadth First Search–BFS)遍历类似树的按层次遍历的过程。
设初始状态时图中的所有顶点未被访问,则:
⑴ :从图中某个顶点vi出发,访问vi;
⑵:访问vi的所有相邻接且未被访问的所有顶点vi1,vi2,…,vim;
⑶:以vi1,vi2, …,vim的次序,以vij(1≦j≦m)依此作为vi ,转⑴;
⑷ :继续选取图中未被访问顶点vk作为起始顶点,转⑴,直到图中所有顶点都被访问为止。

代码实现–C语言实现

Graph.c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "Queue.h"

#define MAX_VERTEX_NUM 10
#define INFINITY 32768
typedef enum{DG,DN,UDG,UDN} GraphKind;

#define ERROR 0
#define TRUE 1

typedef int status;
typedef char ElemType;


typedef struct MNode{
    ElemType vertex[MAX_VERTEX_NUM];  /*顶点*/
    int Arc[MAX_VERTEX_NUM][MAX_VERTEX_NUM];  /*弧*/
    int vexnum,arcnum;  /*弧个数,顶点个数*/
    GraphKind kind;
}GraphNode,*Graph;

int IsRead[MAX_VERTEX_NUM];  //标记顶点是否被遍历过

/*初始化*/
status Init(Graph *G){
    (*G) = (GraphNode *)malloc(sizeof(GraphNode));
    (*G)->vexnum = 0;
    (*G)->arcnum = 0;
    if((*G))return TRUE;
    else{
        printf("初始化出错...\n");
    }
    return ERROR;
}

/*查找位置*/
void FindPos(Graph G,char a,char b,int *pos1,int *pos2){
    int i = 0;
    *pos1 = -1; *pos2 = -1; //初值
    for(i = 0; i<G->vexnum;i++){
        if(G->vertex[i]==a){
            (*pos1) = i;
            continue;
        }else if(G->vertex[i] == b){
            (*pos2) = i;
            continue;
        }
    }
}

/*建立图*/
void BuildGraph(Graph G){
    int choice = 0,num = 0,pos1,pos2,i,j,weight;
    char a,b,ch;
    printf("请选择建立的图的类型:1:有向图,2:有向网,3:无向图,无向网:\n");
    scanf("%d",&choice);
    getchar();
    printf("\n");  //下一行
    if(choice == 1){  //有向图

        for(i = 0;i<MAX_VERTEX_NUM;i++){ //初始化弧
            for(j = 0;j<MAX_VERTEX_NUM;j++){
                G->Arc[i][j] = 0;
            }
        }
        G->kind = DG; //设置图的类型

        printf("请输入顶点(不超过10个,以#结束):\n");
        scanf("%c",&ch);
        while(ch!='#' && num <10){
            G->vertex[num] = ch;
            scanf("%c",&ch);
            num++;
        }
        G->vexnum = num;  //顶点个数

        getchar();  //清除键盘缓冲区

        printf("请输入对应的弧以a->b格式输入(以#->#结束):\n");
        scanf("%c->%c",&a,&b);
        while(a!='#' && b!='#'){
            printf("%c,%c",a,b);
            FindPos(G,a,b,&pos1,&pos2);
            printf("位置a:%d,位置b:%d\n",pos1,pos2);
            if(pos1!= -1 && pos2!= -1){  //忽略不存在的顶点
                G->Arc[pos1][pos2] = 1;
                G->arcnum++;
            }
            scanf("%c->%c",&a,&b);
        }
        getchar(); //清空
    }
    else if(choice==2){ //有向网

        num = 0;  //个数初始化
        for(i = 0;i < MAX_VERTEX_NUM; i++){ //初始化弧
            for(j = 0;j<MAX_VERTEX_NUM; j++){
                G->Arc[i][j] = INFINITY;
            }
        }
        G->kind = DN; //设置图的类型

        printf("请输入顶点(不超过10个,以#结束):\n");
        scanf("%c",&ch);
        while(ch!='#' && num <10){
            G->vertex[num] = ch;
            scanf("%c",&ch);
            num++;
        }
        G->vexnum = num;  //顶点个数

        getchar();  //清除键盘缓冲区

        printf("请输入对应的弧以a->b:weight格式输入(以#->#:0结束):\n");
        scanf("%c->%c:%d",&a,&b,&weight);
        while(a!='#' && b!='#'){
            printf("%c,%c",a,b);
            FindPos(G,a,b,&pos1,&pos2);
            printf("位置a:%d,位置b:%d\n",pos1,pos2);
            if(pos1!= -1 && pos2!= -1){  //忽略不存在的顶点
                G->Arc[pos1][pos2] = weight;
                G->arcnum++;
            }
            scanf("%c->%c:%d",&a,&b,&weight);
        }
        getchar(); //清空
    }
    else if(choice == 3){//无向图

        num = 0;
        for(i = 0;i<MAX_VERTEX_NUM;i++){ //初始化弧
            for(j = 0;j<MAX_VERTEX_NUM;j++){
                G->Arc[i][j] = 0;
            }
        }
        G->kind = UDG; //设置图的类型

        printf("请输入顶点(不超过10个,以#结束):\n");
        scanf("%c",&ch);
        while(ch!='#' && num <10){
            G->vertex[num] = ch;
            scanf("%c",&ch);
            num++;
        }
        G->vexnum = num;  //顶点个数

        getchar();  //清除键盘缓冲区

        printf("请输入对应的弧以a-b格式输入(以#-#结束):\n");
        scanf("%c-%c",&a,&b);
        while(a!='#' && b!='#'){
            printf("%c,%c",a,b);
            FindPos(G,a,b,&pos1,&pos2);
            printf("位置a:%d,位置b:%d\n",pos1,pos2);
            if(pos1!= -1 && pos2!= -1){  //忽略不存在的顶点
                G->Arc[pos1][pos2] = 1;
                G->Arc[pos2][pos1] = 1;
                G->arcnum++;
            }
            scanf("%c-%c",&a,&b);
        }
        getchar(); //清空
    }
    else if(choice == 4){ //无向网

        num = 0;  //个数初始化
        for(i = 0;i < MAX_VERTEX_NUM; i++){ //初始化弧
            for(j = 0;j<MAX_VERTEX_NUM; j++){
                G->Arc[i][j] = INFINITY;
            }
        }
        G->kind = DN; //设置图的类型

        printf("请输入顶点(不超过10个,以#结束):\n");
        scanf("%c",&ch);
        while(ch!='#' && num <10){
            G->vertex[num] = ch;
            scanf("%c",&ch);
            num++;
        }
        G->vexnum = num;  //顶点个数

        getchar();  //清除键盘缓冲区

        printf("请输入对应的弧以a-b:weight格式输入(以#-#:0结束):\n");
        scanf("%c->%c:%d",&a,&b,&weight);
        while(a!='#' && b!='#'){
            printf("%c,%c",a,b);
            FindPos(G,a,b,&pos1,&pos2);
            printf("位置a:%d,位置b:%d\n",pos1,pos2);
            if(pos1!= -1 && pos2!= -1){  //忽略不存在的顶点
                G->Arc[pos1][pos2] = weight;
                G->Arc[pos2][pos1] = weight;
                G->arcnum++;
            }
            scanf("%c-%c:%d",&a,&b,&weight);
        }
        getchar(); //清空
    }
    else {  //非法输入的选择
        printf("输入非法,请输入正确的数字!!\n");
        return;
    }
}

void DepthFS(Graph G,int pos){ /*深度优先搜索for图*/
    int i = 0,j = 0;
    if(IsRead[pos] == 0){
        IsRead[pos] = 1; //从第一个开始
        printf("遍历顶点%c\n",G->vertex[pos]);
    }

    for(i = 0;i<G->vexnum;i++){
        if(G->Arc[pos][i] == 1 && IsRead[i] ==0){  //存在弧
            DepthFS(G,i);
        }
    }
}

void DepthFS1(Graph G,int pos){ /*深度优先搜索for网*/
    int i = 0,j = 0;
    if(IsRead[pos] == 0){
        IsRead[pos] = 1; //从第一个开始
        printf("遍历顶点%c\n",G->vertex[pos]);
    }

    for(i = 0;i<G->vexnum;i++){
        if(G->Arc[pos][i] !=INFINITY && IsRead[i] ==0){  //存在弧且未被遍历
            DepthFS1(G,i);
        }
    }
}

/*深度优先搜索*/
void DFS(Graph G){
    if(G->kind == DG || G->kind == UDG){  //图
        DepthFS(G,0);
    }else if(G->kind == DN || G->kind == UDN){ //网
        DepthFS1(G,0);
    }
}

void BFS1(Graph G,int pos){ //广度优先搜索for图
    int i = 0,temp;
    Queue Q;
    InitQueue(&Q);
    for(i = 0; i <G->vexnum;i++){  //清零
        IsRead[i] = 0;
    }
    if(IsRead[pos] ==0){
        IsRead[pos] = 1;
        printf("遍历顶点:%c\n",G->vertex[pos]);
    }
    EnterQueue(Q,pos);
    while(!isEmpty(Q)){//当队列不为空
        OutQueue(Q,&temp);
        for(i = 0; i< G->vexnum;i++){
            if(G->Arc[temp][i] == 1 && IsRead[i] == 0){
                IsRead[i] = 1;
                printf("遍历顶点:%c\n",G->vertex[i]);
                EnterQueue(Q,i);
            }
        }
    }
    free(Q);
}

void BFS2(Graph G,int pos){ //广度优先搜索for图
    int i = 0,temp;
    Queue Q;
    InitQueue(&Q);
    for(i = 0; i <G->vexnum;i++){  //清零
        IsRead[i] = 0;
    }
    if(IsRead[pos] ==0){
        IsRead[pos] = 1;
        printf("遍历顶点:%c\n",G->vertex[pos]);
    }
    EnterQueue(Q,pos);
    while(!isEmpty(Q)){//当队列不为空
        OutQueue(Q,&temp);
        for(i = 0; i< G->vexnum;i++){
            if(G->Arc[temp][i] != INFINITY && IsRead[i] == 0){
                IsRead[i] = 1;
                printf("遍历顶点:%c\n",G->vertex[i]);
                EnterQueue(Q,i);
            }
        }
    }
    free(Q);
}

void BFS(Graph G){
    if(G->kind == DG || G->kind == UDG){  //图
        BFS1(G,0);
    }else if(G->kind == DN || G->kind == UDN){ //网
        BFS2(G,0);
    }
}

void main(){
    int i = 0;
    Graph G = NULL;
    Init(&G);
    BuildGraph(G);
    for(i = 0; i<MAX_VERTEX_NUM; i++){
        IsRead[i] = 0;  //未被遍历
    }
    printf("\n深度优先搜索:\n");
    DFS(G,0);
    printf("\n广度优先搜索:\n");
    BFS(G,0);

}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316

Queue.h

#include <stdio.h>
#include <stdlib.h>

#define TRUE 1
#define ERROR 0
#define MAX_SIZE 20

typedef int status;

/*定义队列*/
typedef struct QNode{
    int Qarr[MAX_SIZE];
    int tail,head;
    int size;
}QNode,*Queue;

void InitQueue(Queue *Q){
    (*Q) = (QNode *)malloc(sizeof(QNode));
    if(*Q){
        (*Q)->size = 0;
        (*Q)->head = 0;
        (*Q)->tail = 0;
    }
}

/*入队列*/
void EnterQueue(Queue Q, int data){
    if((Q->tail +1) % MAX_SIZE == Q->head){
        printf("队列已经满!!\n");
        return;
    }
    Q->Qarr[Q->tail] = data;
    Q->size++;
    Q->tail = (Q->tail +1) % MAX_SIZE;
    return;
}

void OutQueue(Queue Q, int *data){
    if(Q->head == Q->tail){
        printf("队列为空!!\n");
        return;
    }
    (*data) = Q->Qarr[Q->head];
    Q->size--;
    Q->head = (Q->head +1) % MAX_SIZE;
    return;
}

int isEmpty(Queue Q){
    if(Q->head == Q->tail)return 1;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值