创建图的三种方法(邻接矩阵+邻接表+十字链表)

一、邻接矩阵
采用矩阵的方式来描述图中的连接各非连接关系,若不能连上用无穷大或者0来表示,但是如果边很稀少,顶点很多,那么将会有很大的浪费。同时,这个矩阵可以同时刻画有向图和无向图,无向图就是把有向图根据对角线对称即可。

这里写图片描述

1、思想:建立一个结构体,它包含了这个图所应该具备的顶点、边的条数、矩阵(二维数组的信息),同时因为边有三个信息,权值,连接两个顶点v1,v2,所以也用一个结构体表示

这里写图片描述
2、用到的函数:

MGraph CreateGraph_matric(int nvNum);
void InsertEdge_matric(MGraph Graph,Edge E);
MGraph biuldGraph_matric()

3、过程
(1)从文件中读入nv
(2)创建一个具有nv个顶点的图:

CreateGraph_matric(nv)

申请一个邻接矩阵图的空间,先把边设置成0,再用两个for循环遍历所有可能的边,每条边设置成无穷大(初始化)
(3)从文件中读入边的信息,读入边的连接信息(权值+两个被边连接的顶点),把他们的信息赋给Edge的边的结构体,再把这条边插进图中

InsertEdge_matric(Graph,E);

在插入函数中,说明:哪两个顶点间的权值是多少,即可

Graph->G[E->v1][E->v2]=E->weight;

二、邻接表
1、结构体

/*邻接点的定义*/
typedef int weightType;
typedef char dataType;
struct AdjvNode{
    Vertex Adjv;//邻接点的下标
    weightType weight;
    struct AdjvNode *next;
};
typedef struct AdjvNode *PtrToAdjvNode;


/*顶点表头结点的定义*/
struct Vnode{
    PtrToAdjvNode firstEdge;//边表头指针
    dataType data;
};
//开辟顶点结点的数组
typedef struct Vnode AdjList[MaxVertexNum];


/*邻接表-图的定义*/
struct GNode_AL{
    int nv;
    int ne;
    AdjList G;//顶点表
};
typedef struct GNode_AL *LGraph;

这里写图片描述

邻接表的结构是这样构建的:
整个图应该由顶点表+边表构成,怎么把他们连接起来?
(大框架)(里边包含顶点表,边数,顶点数)->(顶点表)(又包含 顶点内容+指向边表的指针)->(指针引出边表)(边表包含 :被指向边的顶点+权值+指向该条链表的下一个指针)

这里写图片描述
2、用到函数
同邻接矩阵(3个)
3、建立过程
同邻接矩阵。
初始化的时候有些区别。刚开始的时候,除了申请一个图的空间,还给每个顶点表也申请了空间,其实根本不用,因为我们创建的顶点表是用数组来创建的,已经申请了空间。把每个顶点表的头指针赋值为NULL。

//建立邻接表的图
LGraph biuldGraph_adjacencyList(){
    LGraph Graph;
    Edge E;
    int nv,i;

    FILE*fp;
     if((fp=fopen("E://数据结构//图 实验//matric1.txt","r"))==NULL)
    {
        printf("fail to open!");
        exit(0);
    }
    fscanf(fp,"%d\n",&nv);//顶点个数
    Graph=CreateGraph_adjacencyList(nv);//初始化有nv个顶点但没有边的图

    fscanf(fp,"%d\n",&Graph->ne);//读入边数
    if(Graph->ne!=0){
        E=(Edge)malloc(sizeof(struct ENode));
        for(i=0;i<Graph->ne;i++){
            fscanf(fp,"%d %d %d\n",&E->v1,&E->v2,&E->weight);//读入边的信息
            InsertEdge_adjacencyList(Graph,E);//把这条边插入矩阵信息中
        }
    }
    //读入顶点的数据
    for(i=0;i<Graph->nv;i++){
        fscanf(fp,"%c",&Graph->G[i].data);//读入A、B、C顶点的数据
    }
    return Graph;
}
//初始化有nv个顶点但没有边的图
LGraph CreateGraph_adjacencyList(int nvNum){
    Vertex v;
    LGraph Graph;
    //为这个图申请空间
    Graph =(LGraph)malloc(sizeof(struct GNode));
    Graph->nv=nvNum;
    Graph->ne=0;
    for(v=0;v<Graph->nv;v++)
        Graph->G[v].firstEdge=NULL;
    return Graph;
}

插入的时候,每一行的插入都是往前插

//把这条边插入邻接表信息中
void InsertEdge_adjacencyList(LGraph Graph,Edge E){
    PtrToAdjvNode newnode;//定义一个表头结点
    //建立一个v2邻接点
    newnode=(PtrToAdjvNode)malloc(sizeof(struct AdjvNode));
    newnode->Adjv=E->v2;//被连接到的点
    newnode->weight=E->weight;
    //将v2插入v1表头
    newnode->next=Graph->G[E->v1].firstEdge;
    Graph->G[E->v1].firstEdge=newnode;
}

如何理解将v2插入v1表头
这里写图片描述

三、十字链表
1、结构体

/*十字链表的结构体*/
//结点结构
struct ArcNode{
    int tailvex,headvex;//弧的头和顶点的位置
    struct ArcNode *hlink,*tlink;//头尾指针
    weightType weight;
};
typedef struct ArcNode *Arcbox;

//头结点
struct XNode{
    dataType data;
    Arcbox firstIn,firstOut;
};
typedef struct XNode xlist[MaxVertexNum];

/*十字链表-图的定义*/
struct OLGNode{
    int nv;
    int ne;
    xlist G;//邻接表
};
typedef struct OLGNode *OLGraph;

结点表和边表都多了一个方向的指针

这里写图片描述

2、过程
这个一模一样,不写了

OLGraph biuldGraph_arc(){}

下面这个for语句是要对两个头尾指针都要赋初值NULL,但是没有用括号,导致另一个指针瞎指,找了好久才发现,一定要细心!!

//初始化有nv个顶点但没有边的图
OLGraph CreateGraph_arc(int nvNum){
    Vertex v;
    OLGraph Graph;
    //为这个图申请空间
    Graph =(OLGraph)malloc(sizeof(struct OLGNode));
    Graph->nv=nvNum;
    Graph->ne=0;
    /*
    for(v=0;v<Graph->nv;v++)
        Graph->G[v].firstIn=NULL;
        Graph->G[v].firstOut=NULL;出错原因!!

    */
    for(v=0;v<Graph->nv;v++){
        Graph->G[v].firstIn=NULL;
        Graph->G[v].firstOut=NULL;
    }
    return Graph;
}
//把这条边插入邻接表信息中
void InsertEdge_arc(OLGraph Graph,Edge E){
    Arcbox A;
    A=(Arcbox)malloc(sizeof(struct ArcNode));//为结点申请空间

    A->weight=E->weight;
    A->headvex=E->v2;
    A->tailvex=E->v1;

    A->tlink=Graph->G[A->tailvex].firstOut;//出去的指针解决了
    Graph->G[A->tailvex].firstOut=A;//把出去的边连接上
    //解决firstIn,hlink的指针
    A->hlink=Graph->G[A->headvex].firstIn;
    Graph->G[A->headvex].firstIn=A;
}

firstout-tlink firstin-hlink

  • 7
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,邻接矩阵可以用十字链表来表示。十字链表是一种用于表示稀疏矩阵的数据结构,它可以更有效地存储和访问矩阵中的非零元素。邻接矩阵虽然可以表示稠密,但是对于稀疏来说,它会浪费大量的空间。因此,使用十字链表可以更好地支持稀疏的存储和操作。 在十字链表中,每个非零元素对应一个节点,节点中记录了该元素的值、行列下标以及上下左右四个指针。具体来说,对于一个n*n的邻接矩阵,我们可以定义两个头节点row_head和col_head,分别表示行链表和列链表的头结点。对于每个非零元素matrix[i][j],我们可以创建一个节点node,同时将node分别插入到row_head[i]和col_head[j]所表示的链表中。在节点node中,我们可以记录matrix[i][j]的值以及上下左右四个指针,用于链接其他的非零元素。 以下是一个简单的示例代码,用于将一个邻接矩阵转换为十字链表的形式: ```c #include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 typedef struct node { int row; int col; int value; struct node *up, *down, *left, *right; } Node; Node *create_node(int row, int col, int value) { Node *node = (Node *)malloc(sizeof(Node)); node->row = row; node->col = col; node->value = value; node->up = node->down = node->left = node->right = NULL; return node; } void free_node(Node *node) { free(node); } void print_cross_list(Node *row_head[], int n) { for (int i = 0; i < n; i++) { for (Node *p = row_head[i]->right; p != row_head[i]; p = p->right) { printf("(%d,%d,%d) ", p->row, p->col, p->value); } printf("\n"); } } void adjacency_matrix_to_cross_list(int **matrix, int n, Node *row_head[], Node *col_head[]) { for (int i = 0; i < n; i++) { row_head[i] = create_node(i, -1, 0); col_head[i] = create_node(-1, i, 0); row_head[i]->right = row_head[i]; col_head[i]->down = col_head[i]; Node *last = row_head[i]; for (int j = 0; j < n; j++) { if (matrix[i][j] != 0) { Node *node = create_node(i, j, matrix[i][j]); node->left = last; node->right = row_head[i]; last->right = node; row_head[i]->left = node; last = node; node->up = col_head[j]; node->down = col_head[j]->down; col_head[j]->down = node; node->down->up = node; } } } } int main() { int n = 5; int matrix[MAX_SIZE][MAX_SIZE] = {{0, 1, 0, 2, 0}, {0, 0, 0, 0, 1}, {0, 0, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 0, 0, 0, 0}}; Node *row_head[MAX_SIZE], *col_head[MAX_SIZE]; adjacency_matrix_to_cross_list(matrix, n, row_head, col_head); print_cross_list(row_head, n); return 0; } ``` 以上代码中,`Node`结构体表示十字链表中的一个节点,`create_node`函数用于创建一个节点,`free_node`函数用于释放节点的内存,`print_cross_list`函数用于打印十字链表的内容。在`main`函数中,我们首先定义一个大小为5的邻接矩阵,并将其转换为十字链表的形式,然后打印结果。在`adjacency_matrix_to_cross_list`函数中,我们首先创建两个头节点row_head和col_head,分别表示行链表和列链表的头结点。然后,对于每个非零元素matrix[i][j],我们创建一个节点node,并将node分别插入到row_head[i]和col_head[j]所表示的链表中。在节点node中,我们记录matrix[i][j]的值以及上下左右四个指针,用于链接其他的非零元素。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值