图的实现

说明

  • 只保留顶点的索引号,而不需要知道任何与顶点相关的信息。因此,使用一个数组表示点集。
  • 使用一个数组mark来记录每个顶点是否被访问过,用来实现图的遍历,最小生成树算法和最短路径算法。
  • 图的邻接矩阵表示法中,用一个二维数组matrix表示边的权重。如果边不存在,则权重为0。如果边存在,则权重大于0。
  • 图的邻接表表示法中,有一个长度为|V|的数组,数组中第 i 个元素存储指向顶点 i 的所有边构成的链表。链表的节点存储边的信息,由于边的起点已知,只需要存储边的终点和权重即可。

邻接矩阵表示法

Graphm.h

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

#define UNVISITED 0
#define VISITED 1   

typedef struct{
    int numVertex;          // 点数
    int numEdge;            // 边数
    int **matrix;           // 邻接矩阵
    int *mark;              // 标记点
}Graphm;

Graphm create_Graphm(int numVertex);                         // 创建图
int n(Graphm g);                                             // 获取点数
int e(Graphm g);                                             // 获取边数
int isVertex(Graphm g, int v);                               // 判断点v是否是图中的点(点从0开始)
int isEdge(Graphm g, int v1, int v2);                        // 判断v1->v2是否是图中的边
void setEdge(Graphm *g, int v1, int v2, int w);              // 创建边并初始化边的权重
void delEdge(Graphm *g, int v1, int v2);                     // 删除边
int getWeight(Graphm g, int v1, int v2);                     // 获取边的权重
void setMark(Graphm *g, int v, int val);                     // 设置点的值
int getMark(Graphm g, int v);                                // 获取点的值
int firstNeighbor(Graphm g, int v);                          // 返回v的第一个邻接点
int nextNeighbor(Graphm g, int v, int w);                    // 返回v的w之后的下一个邻接点


Graphm create_Graphm(int numVertex){
    Graphm *g = (Graphm *)malloc(sizeof(Graphm));
    g->numVertex = numVertex;
    g->numEdge = 0;
    g->mark = (int *)malloc(sizeof(int)*numVertex);
    g->matrix = (int **)malloc(sizeof(int *)*numVertex);
    for(int i = 0; i < numVertex; i++){
        g->matrix[i] = (int *)malloc(sizeof(int)*numVertex);
    }
    for(int i = 0; i < numVertex; i++){
        g->mark[i] = UNVISITED;
    }
    for(int i = 0; i < numVertex; i++){
        for(int j = 0; j < numVertex; j++){
            g->matrix[i][j] = 0;
        }
    }
    return *g;
}

int n(Graphm g){
    return g.numVertex;
}

int e(Graphm g){
    return g.numEdge;
}

int isVertex(Graphm g, int v){
    if(v >= n(g) || v < 0){
        return 0;
    }
    return 1;
}

int isEdge(Graphm g, int v1, int v2){
    if(!isVertex(g, v1) || !isVertex(g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    return g.matrix[v1][v2] != 0;
}

void setEdge(Graphm *g, int v1, int v2, int w){
    if(!isVertex(*g, v1) || !isVertex(*g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    if(w <= 0){
        printf("error! weight must be larger than 0\n");
        exit(0);
    }
    if(g->matrix[v1][v2] == 0){
        g->numEdge++;
    }
    g->matrix[v1][v2] = w;
}

void delEdge(Graphm *g, int v1, int v2){
    if(!isVertex(*g, v1) || !isVertex(*g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    if(g->matrix[v1][v2] != 0){
        g->numEdge--;
    }
    g->matrix[v1][v2] = 0;
}

int getWeight(Graphm g, int v1, int v2){
    if(!isVertex(g, v1) || !isVertex(g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    return g.matrix[v1][v2];
}

void setMark(Graphm *g, int v, int val){
    if(!isVertex(*g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    g->mark[v] = val;
}

int getMark(Graphm g, int v){
    if(!isVertex(g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    return g.mark[v];
}

int firstNeighbor(Graphm g, int v){
    if(!isVertex(g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    for(int i = 0; i < g.numVertex; i++){
        if(g.matrix[v][i] != 0){
            return i;
        }
    }
    // 如果点v没有邻接点
    return g.numVertex;
}

int nextNeighbor(Graphm g, int v, int w){
    if(!isVertex(g, v) || !isVertex(g, w)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    for(int i = w + 1; i < g.numVertex; i++){
        if(g.matrix[v][i] != 0){
            return i;
        }
    }
    // 如果点v没有邻接点
    return g.numVertex;
}

测试代码

#include"Graphm.h"

int main(){
    Graphm g = create_Graphm(5);
    setEdge(&g, 0, 1, 1);
    setEdge(&g, 0, 4, 1);
    setEdge(&g, 1, 3, 1);
    setEdge(&g, 2, 4, 1);
    setEdge(&g, 3, 2, 1);
    setEdge(&g, 4, 1, 1);
    for(int i = 0; i < n(g); i++){
        for(int j = 0; j < n(g); j++){
            printf("%d\t", getWeight(g, i, j));
        }
        printf("\n");
    }
    printf("%d\n", firstNeighbor(g, 0));
    printf("%d\n", nextNeighbor(g, 0, 1));
    return 0;
}

邻接表表示法

Graphl.h

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

#define UNVISITED 0
#define VISITED 1

typedef struct{
    int numVertex;              // 点数
    int numEdge;                // 边数
    LList **vertex;             // 邻接矩阵
    int *mark;                  // 标记点
}Graphl;

Graphl create_Graphl(int numVertex);                         // 创建图
int n(Graphl g);                                             // 获取点数
int e(Graphl g);                                             // 获取边数
int isVertex(Graphl g, int v);                               // 判断点v是否是图中的点(点从0开始)
int isEdge(Graphl g, int v1, int v2);                        // 判断v1->v2是否是图中的边
void setEdge(Graphl *g, int v1, int v2, int w);              // 创建边并初始化边的权重
void delEdge(Graphl *g, int v1, int v2);                     // 删除边
int getWeight(Graphl g, int v1, int v2);                     // 获取边的权重
void setMark(Graphl *g, int v, int val);                     // 设置点的值
int getMark(Graphl g, int v);                                // 获取点的值
int firstNeighbor(Graphl g, int v);                          // 返回v的第一个邻接点
int nextNeighbor(Graphl g, int v, int w);                    // 返回v的w之后的下一个邻接点


Graphl create_Graphl(int numVertex){
    Graphl *g = (Graphl *)malloc(sizeof(Graphl));
    g->numVertex = numVertex;
    g->numEdge = 0;
    g->mark = (int *)malloc(sizeof(int)*numVertex);
    g->vertex = (LList **)malloc(sizeof(LList *)*numVertex);
    for(int i = 0; i < numVertex; i++){
        g->vertex[i] = (LList *)malloc(sizeof(LList));
    }
    for(int i = 0; i < numVertex; i++){
        g->mark[i] = UNVISITED;
    }
    for(int i = 0; i < numVertex; i++){
        *g->vertex[i] = create_LList();
    }
    return *g;
}

int n(Graphl g){
    return g.numVertex;
}

int e(Graphl g){
    return g.numEdge;
}

int isVertex(Graphl g, int v){
    if(v >= n(g) || v < 0){
        return 0;
    }
    return 1;
}

int isEdge(Graphl g, int v1, int v2){
    if(!isVertex(g, v1) || !isVertex(g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    // 注意,在判断v1->v2是否是图中的边时,改变了链表的当前位置
    for(moveToStart(g.vertex[v1]); currPos(*g.vertex[v1]) < length(*g.vertex[v1]); next(g.vertex[v1])){
        Edge temp = getValue(*g.vertex[v1]);
        if(_vertex(temp) == v2){
            return 1;
        }
    }
    return 0;
}

void setEdge(Graphl *g, int v1, int v2, int w){
    if(!isVertex(*g, v1) || !isVertex(*g, v2)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    // 边的权重必须大于0
    if(w <= 0){
        printf("error! weight must be larger than 0\n");
        exit(0);
    }
    Edge currEdge = create_Edge(v2, w);
    // 如果v1->v2存在
    if(isEdge(*g, v1, v2)){
        delete(g->vertex[v1]);
        insert(g->vertex[v1], currEdge);
    }
    // 如果v1->v2不存在
    else{
        g->numEdge++;
        for(moveToStart(g->vertex[v1]); currPos(*g->vertex[v1]) < length(*g->vertex[v1]); next(g->vertex[v1])){
            Edge temp = getValue(*g->vertex[v1]);
            if(_vertex(temp) > v2){
                break;
            }
        }
        insert(g->vertex[v1], currEdge);
    }
}

void delEdge(Graphl *g, int v1, int v2){
    if(isEdge(*g, v1, v2)){
        delete(g->vertex[v1]);
        g->numEdge--;
    }
}

int getWeight(Graphl g, int v1, int v2){
    if(isEdge(g, v1, v2)){
        Edge temp = getValue(*g.vertex[v1]);
        return _weight(temp);
    }
    // 如果边v1->v2不存在
    return 0;
}

void setMark(Graphl *g, int v, int val){
    if(!isVertex(*g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    g->mark[v] = val;
}

int getMark(Graphl g, int v){
    if(!isVertex(g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    return g.mark[v];
}

int firstNeighbor(Graphl g, int v){
    if(!isVertex(g, v)){
        printf("error! vertex doesn't exist\n");
        exit(0);
    }
    // 如果v没有邻接点
    if(length(*g.vertex[v]) == 0){
        return n(g);
    }
    moveToStart(g.vertex[v]);
    Edge temp = getValue(*g.vertex[v]);
    return _vertex(temp);
}

int nextNeighbor(Graphl g, int v, int w){
    if(isEdge(g, v, w)){
        if(currPos(*g.vertex[v]) + 1 < length(*g.vertex[v])){
            next(g.vertex[v]);
            Edge temp = getValue(*g.vertex[v]);
            return _vertex(temp);
        }
    }
    // 如果w后面没有邻接点,或者w不是v的邻接点
    return n(g);
}

LList_Graph.h

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

typedef struct{
    int v;              // 边的终点
    int w;              // 边的权重
}Edge;

typedef struct node{
    Edge value;
    struct node *next;
}node;

typedef struct{
    node *head;         // 头节点
    node *tail;         // 尾节点
    node *curr;         // 当前节点(为了方便进行插入或删除操作,实际上操作的是当前节点的下一个节点)
    int count;          // 链表当前节点数(空节点除外)
}LList;

LList create_LList();                                   // 创建链表
void clear(LList *llist);                               // 清空链表
void append(LList *llist, Edge value);                  // 在链表末尾添加节点
void insert(LList *llist, Edge value);                  // 在当前位置插入节点
Edge delete(LList *llist);                              // 在当前位置删除节点
int currPos(LList llist);                               // 获取当前位置
void moveToStart(LList *llist);                         // 移到表头
void moveToEnd(LList *llist);                           // 移到表位
void moveToPos(LList *llist, int pos);                  // 移到指定位置(pos从0开始)
void next(LList *llist);                                // 当前位置向后移
Edge getValue(LList llist);                             // 获取当前节点的元素
int length(LList llist);                                // 获取链表长度

Edge create_Edge(int v, int w);                         // 创建边并初始化权重
int _vertex(Edge e);                                    // 获取边的终点
int _weight(Edge e);                                    // 获取边的权重


void init(LList *llist){
    // 当链表为空时,头节点、尾节点、当前节点无处可指,在插入删除操作时,需要增加额外的代码。
    // 为此,增加一个空节点
    node *n = (node *)malloc(sizeof(node));
    n->next = NULL;
    // 头节点,尾节点,当前节点指向空节点
    llist->head = n;
    llist->curr = n;
    llist->tail = n;
    llist->count = 0; 
}

void removeall(LList *llist){
    // 只要链表不为空,不断地从头删除节点
    while(llist->head != NULL){
        llist->curr = llist->head;
        llist->head = llist->head->next;
        free(llist->curr);
    }
}

LList create_LList(){  
    LList *llist = (LList *)malloc(sizeof(LList));
    init(llist);
    return *llist;
}

void clear(LList *llist){
    removeall(llist);
    init(llist);
}

void append(LList *llist, Edge value){
    node *n = (node *)malloc(sizeof(node));
    n->value = value;
    n->next = NULL;
    // 让链表尾节点指向它(注意指针与实际物理内存的联系,不然会产生疑惑)
    llist->tail->next = n;   
    llist->tail = llist->tail->next;
    llist->count++;
}

void insert(LList *llist, Edge value){
    node *n = (node *)malloc(sizeof(node));
    n->value = value;
    n->next = llist->curr->next;
    llist->curr->next = n;
    // 如果当前节点为尾节点,那么尾节点需要指向该节点(尾节点始终应该在链表末尾)
    if(llist->curr == llist->tail){
        llist->tail = llist->curr->next;
    }
    llist->count++;
}

int currPos(LList llist){
    node *temp = llist.head;
    int i;
    for(i = 0; temp != llist.curr; i++){
        temp = temp->next;
    }
    return i;
}

Edge delete(LList *llist){
    // getValue已经判断了是否为空的情况
    Edge value = getValue(*llist);
    node *n = llist->curr->next;
    // 如果待删除的节点为尾节点,那么尾节点需要指向当前节点(因为尾节点不应该无处可指)
    if(llist->curr->next == llist->tail){
        llist->tail = llist->curr;
    }
    llist->curr->next = llist->curr->next->next;
    free(n);
    llist->count--;
    return value;
}

void moveToStart(LList *llist){    
    llist->curr = llist->head;
}

void moveToEnd(LList *llist){
    llist->curr = llist->tail;
}

void moveToPos(LList *llist, int pos){
    if(pos < 0 || pos >= llist->count){
        printf("position out of range");
        exit(0);
    }
    moveToStart(llist);
    int i = 0;
    while(i < pos){
        llist->curr = llist->curr->next;
        i++;
    }
}

void next(LList *llist){
    if(llist->curr != llist->tail){
        llist->curr = llist->curr->next;
    }
}

Edge getValue(LList llist){
    if(llist.curr->next == NULL){
        printf("No value");
        exit(0);
    }
    // 返回的是当前节点的下一个节点的值
    return llist.curr->next->value;
}

int length(LList llist){
    return llist.count;
}

Edge create_Edge(int v, int w){
    Edge *e = (Edge *)malloc(sizeof(Edge));
    e->v = v;
    e->w = w;
    return *e;
}
int _vertex(Edge e){
    return e.v;
}
int _weight(Edge e){
    return e.w;
}

测试代码

#include"Graphl.h"

int main(){
    Graphl g = create_Graphl(5);
    setEdge(&g, 0, 1, 1);
    setEdge(&g, 0, 4, 1);
    setEdge(&g, 1, 3, 1);
    setEdge(&g, 2, 4, 1);
    setEdge(&g, 3, 2, 1);
    setEdge(&g, 4, 1, 1);
    for(int i = 0; i < n(g); i++){
        for(int j = 0; j < n(g); j++){
            printf("%d\t", getWeight(g, i, j));
        }
        printf("\n");
    }
    printf("%d\n", firstNeighbor(g, 0));
    printf("%d\n", nextNeighbor(g, 0, 1));
    return 0;
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值