16、数据结构与算法 - 图(一)存储

线性表特性;
明显层次关系, 1对多关系
图的结构, 结点之间关系任意.
 
 
二叉树有空树(只有根结点),但是图没有空图的概念。
图的结点可以形成闭环也可以不形成闭环,同样也可以不连接

带方向的叫有向图,没有方向的叫无向图

 

二、图的存储

 连接线:无向图叫边,有向图叫弧
 自己用0,没有关系就用无穷大表示(代码中用最大值表示),有关系有权重就用权重,没有权重就用1.没有
 多少个顶点就多大的数组

 

1、邻接矩阵(顺序存储)


 

#include <stdio.h>
#include "string.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define OK 1
#define ERROR 0
#define TURE 1
#define FALSE 0
#define MAXVEX 100
#define INFINTTYC 0
//邻接矩阵
//二维数组
/*
 图的度,一行的总和
 代码里用INT_MAX  最大值用来代表无穷
 */

typedef int Status;//函数类型,其值是返回结果状态码
typedef char VertexType;
//typedef CElemType SqBiTree[MAX_TREE_SIZE];//0号存储单元根结点
//CElemType Nil = 0;//设整形以0 为空 或 INT_MAX(65535)
typedef int EdgeType;

typedef struct {
    VertexType vexs[MAXVEX];//结点层
    EdgeType arc[MAXVEX][MAXVEX];
    int numNodes, numEdges;//图中当前的顶点数和边数 本层的序号(按照满二叉树给定序号规则)
}MGraph;

void CreateMGraph(MGraph *G){
    int i,j,k,w;
    printf("输入顶点数和边数:\n");
    //1、输入顶点数/边数
    scanf("%d,%d",&G->numNodes,&G->numEdges);
    printf("顶点数:%d,边数:%d\n",G->numNodes,G->numEdges);
    
    //2、输入顶点信息/顶点表
    for (i=0; i<= G->numNodes; i++) {
        scanf("%c",&G->vexs[i]);
    }
    
    //3、初始化邻接矩阵
    //全部标记为0
    for (i=0; i<G->numNodes; i++) {
        for (j=0; j<G->numNodes; j++) {
            G->arc[i][j] = INFINTTYC;
        }
    }
    
    //4、输入边表信息
    for (k = 0; k<G->numEdges; k++) {
        printf("输入边(vi,vj)上的下标i,下标j,权w\n");
        scanf("%d,%d,%d",&i,&j,&w);
        
        G->arc[i][j] = w;
        //如果无向图,矩阵对称
        G->arc[j][i] = G->arc[i][j];
    }
    
    //5、打印邻接矩阵
    for (int i=0; i<G->numNodes; i++) {
        printf("\n");
        for (int j=0; j<G->numNodes; j++) {
            printf("%d ",G->arc[i][j]);
        }
    }
    printf("\n");
}
int main(int argc, const char * argv[]) {
    printf("邻接矩阵实现图的存储\n");
    /*图的存储-邻接矩阵*/
    MGraph G;
    CreateMGraph(&G);
    return 0;
}
邻接矩阵实现图的存储
 输入顶点数和边数:
 4,5
 顶点数:4,边数:5
 abcd
 输入边(vi,vj)上的下标i,下标j,权w
 0,1,1
 输入边(vi,vj)上的下标i,下标j,权w
 0,2,1
 输入边(vi,vj)上的下标i,下标j,权w
 0,3,1
 输入边(vi,vj)上的下标i,下标j,权w
 1,2,1
 输入边(vi,vj)上的下标i,下标j,权w
 2,3,1

 0 1 1 1
 1 0 1 0
 1 1 0 1
 1 0 1 0
 Program ended with exit

 

2、邻接表(链式存储)

如果说如下图这种情况,用邻接矩阵来存储的话就太浪费内存空间了

这个时候我们就用邻接表

 

#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "time.h"

#define M 100
#define true 1
#define false 0

 连接表结点解析

思路

typedef char Element;
typedef int BOOL;
//邻接表的节点
typedef struct Node{
    int adj_vex_index;  //弧头的下标,也就是被指向的下标
    Element data;       //权重值
    struct Node * next; //边指针
}EdgeNode;

//顶点节点表
typedef struct vNode{
    Element data;          //顶点的权值
    EdgeNode * firstedge;  //顶点下一个是谁?
}VertexNode, Adjlist[M];

//总图的一些信息
typedef struct Graph{
    Adjlist adjlist;       //顶点表
    int arc_num;           //边的个数
    int node_num;          //节点个数
    BOOL is_directed;      //是不是有向图
}Graph, *GraphLink;
void creatGraph(GraphLink *g){
    int i,j,k;
    EdgeNode *p;
    
    //1. 顶点,边,是否有向
    printf("输入顶点数目,边数和有向?:\n");
    scanf("%d %d %d", &(*g)->node_num, &(*g)->arc_num, &(*g)->is_directed);
    
    //2.顶点表
     printf("输入顶点信息:\n");
    for (i = 0; i < (*g)->node_num; i++) {
        getchar();
        scanf("%c", &(*g)->adjlist[i].data);
        (*g)->adjlist[i].firstedge = NULL;
    }
    
    //3.
    printf("输入边信息:\n");
    for (k = 0; k < (*g)->arc_num; k++){
        getchar();
        scanf("%d %d", &i, &j);
        
        //①新建一个节点
        p = (EdgeNode *)malloc(sizeof(EdgeNode));
        //②弧头的下标
        p->adj_vex_index = j;
        //③头插法插进去,插的时候要找到弧尾,那就是顶点数组的下标i
        p->next = (*g)->adjlist[i].firstedge;
        //④将顶点数组[i].firstedge 设置为p
        (*g)->adjlist[i].firstedge = p;
        
        //j->i
        if(!(*g)->is_directed)
        {
            // j -----> i
            //①新建一个节点
            p = (EdgeNode *)malloc(sizeof(EdgeNode));
            //②弧头的下标i
            p->adj_vex_index = i;
            //③头插法插进去,插的时候要找到弧尾,那就是顶点数组的下标i
            p->next = (*g)->adjlist[j].firstedge;
            //④将顶点数组[i].firstedge 设置为p
            (*g)->adjlist[j].firstedge = p;
        }
    }
}

void putGraph(GraphLink g){
    int i;
    printf("邻接表中存储信息:\n");
    //遍历一遍顶点坐标,每个再进去走一次
    for (i = 0; i < g->node_num; i++) {
        EdgeNode * p = g->adjlist[i].firstedge;
        while (p) {
            printf("%c->%c ", g->adjlist[i].data, g->adjlist[p->adj_vex_index].data);
            p = p->next;
        }
        printf("\n");
    }
}
int main(int argc, const char * argv[]) {
    // insert code here...
    printf("邻接表实现图的存储\n");
    /*
     邻接表实现图的存储
     输入顶点数目,边数和有向?:
     4 5 0
     输入顶点信息:
     0 1 2 3
     输入边信息:
     0 1 0 2 0 3 2 1 2 3
     邻接表中存储信息:
     0->3 0->2 0->1
     1->2 1->0
     2->3 2->1 2->0
     3->2 3->0
    */
    /*
     邻接表实现图的存储
     输入顶点数目,边数和有向?:
     4 5 1
     输入顶点信息:
     0 1 2 3
     输入边信息:
     1 0 1 2 2 1 2 0 0 3
     邻接表中存储信息:
     0->3
     1->2 1->0
     2->0 2->1
     */
    GraphLink g = (Graph *)malloc(sizeof(Graph));
    creatGraph(&g);
    putGraph(g);
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值