c/c++ 图相关的函数(二维数组法)

  • 遍历图
  • 插入顶点
  • 添加顶点间的线
  • 删除顶点
  • 删除顶点间的线
  • 摧毁图
  • 取得与v顶点有连线的第一个顶点
  • 取得与v1顶点,v1顶点之后的v2顶点的之后的有连线的第一个顶点

graph_mtx.h

#ifndef __graph_mtx__
#define __graph_mtx__ #include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h> #define Default_vertex_size 10 #define T char//dai biao ding dian de lei xing typedef struct GraphMtx{
int MaxVertices;//zui da ding dian shu liang]
int NumVertices;//shi ji ding dian shu liang
int NumEdges;//bian de shu lian T* VerticesList;//ding dian list
int** Edge;//bian de lian jie xin xi, bu shi 0 jiu shi 1
}GraphMtx; //chu shi hua tu
void init_graph(GraphMtx* gm);
//打印二维数组
void show_graph(GraphMtx* gm);
//插入顶点
void insert_vertex(GraphMtx* gm, T v);
//添加顶点间的线
void insert_edge(GraphMtx* gm, T v1, T v2);
//删除顶点
void remove_vertex(GraphMtx* gm, T v);
//删除顶点间的线
void remove_edge(GraphMtx* gm, T v1, T v2);
//摧毁图
void destroy_graph(GraphMtx* gm);
//取得与v顶点有连线的第一个顶点
int getNeighbor(GraphMtx* gm, T v);
//取得与v1顶点,v1顶点之后的v2顶点的之后的有连线的第一个顶点
int getNextNeighbor(GraphMtx* gm, T v1, T v2); #endif

graph_mtx.c

#include "graph_mtx.h"

void init_graph(GraphMtx* gm){
gm->MaxVertices = Default_vertex_size;
gm->NumEdges = gm->NumVertices = 0; //kai pi ding dian de nei cun kong jian
gm->VerticesList = (T*)malloc(sizeof(T) * (gm->MaxVertices));
assert(NULL != gm->VerticesList); //创建二维数组
//让一个int的二级指针,指向一个有8个int一级指针的数组
//开辟一个能存放gm->MaxVertices个int一级指针的内存空间
gm->Edge = (int**)malloc(sizeof(int*) * (gm->MaxVertices));
assert(NULL != gm->Edge);
//开辟gm->MaxVertices组,能存放gm->MaxVertices个int的内存空间
for(int i = 0; i < gm->MaxVertices; ++i){
gm->Edge[i] = (int*)malloc(sizeof(int) * gm->MaxVertices);
}
//初始化二维数组
//让每个顶点之间的边的关系都为不相连的
for(int i = 0; i < gm->MaxVertices; ++i){
for(int j = 0; j < gm->MaxVertices; ++j){
gm->Edge[i][j] = 0;
}
}
}
//打印二维数组
void show_graph(GraphMtx* gm){
printf(" ");
for(int i = 0; i < gm->NumVertices; ++i){
printf("%c ", gm->VerticesList[i]);
}
printf("\n");
for(int i = 0; i < gm->NumVertices; ++i){
//在行首,打印出顶点的名字
printf("%c:", gm->VerticesList[i]);
for(int j = 0; j < gm->NumVertices; ++j){
printf("%d ", gm->Edge[i][j]);
}
printf("\n");
}
printf("\n");
}
//插入顶点
void insert_vertex(GraphMtx* gm, T v){
//顶点空间已满,不能再插入顶点了
if(gm->NumVertices >= gm->MaxVertices){
return;
}
gm->VerticesList[gm->NumVertices++] = v;
} int getVertexIndex(GraphMtx* gm, T v){
for(int i = 0; i < gm->NumVertices; ++i){
if(gm->VerticesList[i] == v)return i;
}
return -1;
}
//添加顶点间的线
void insert_edge(GraphMtx* gm, T v1, T v2){
if(v1 == v2)return; //查找2个顶点的下标
int j = getVertexIndex(gm, v1);
int k = getVertexIndex(gm, v2);
//说明找到顶点了,并且点之间还没有线
if(j != -1 && k != -1 && gm->Edge[j][k] != 1){
//因为是无方向,所以更新2个值
gm->Edge[j][k] = gm->Edge[k][j] = 1;
//边数加一
gm->NumEdges++;
}
}
//删除顶点间的线
void remove_edge(GraphMtx* gm, T v1, T v2){
if(v1 == v2)return;
//查找2个顶点的下标
int j = getVertexIndex(gm, v1);
int k = getVertexIndex(gm, v2);
//说明找到顶点了,并且点之间还有线
if(j != -1 && k != -1 && gm->Edge[j][k] == 1){
//因为是无方向,所以更新2个值
gm->Edge[j][k] = gm->Edge[k][j] = 0;
//边数减一
gm->NumEdges--;
}
}
//删除顶点
void remove_vertex(GraphMtx* gm, T v){
int k = getVertexIndex(gm, v);
if(-1 == k)return; //算出和要删除节点相关的边的数量,并减少。
for(int i = 0; i < gm->NumVertices; ++i){
if(gm->Edge[k][i] == 1){
gm->NumEdges--;
}
} //如果要删除的顶点不是最后一个顶点
if(k != gm->NumVertices - 1){
//把每一列向左移动一列
for(int i = 0; i < gm->NumVertices; ++i){
//把后面内存里的内容移动到前面,并把最后一个元素设置成0
memmove(&(gm->Edge[i][k]), &(gm->Edge[i][k+1]), sizeof(int) * (gm->NumVertices-1-k));
gm->Edge[i][gm->NumVertices - 1] = 0;
}
//把每一行向上移动一行
for(int i = k; i < gm->NumVertices - 1; ++i){
memmove(gm->Edge[i], gm->Edge[i+1], sizeof(int) * (gm->NumVertices-1));
}
memset(gm->Edge[gm->NumVertices - 1], 0, sizeof(int) * (gm->NumVertices - 1));
//memmove(&(gm->Edge[k]), &(gm->Edge[k+1]), sizeof(int*) * (gm->NumVertices-1-k));
//memset(gm->Edge[gm->NumVertices - 1], 0, sizeof(int) * (gm->NumVertices - 1)); //删除点
memmove(&(gm->VerticesList[k]), &(gm->VerticesList[k+1]), sizeof(T) * (gm->NumVertices-1-k));
}
//如果要删除的顶点是最后一个顶点
else{
for(int i = 0; i < gm->NumVertices; ++i){
gm->Edge[i][k] = gm->Edge[k][i] = 0;
}
} //节点数目减1
gm->NumVertices--;
} //摧毁图
void destroy_graph(GraphMtx* gm){
free(gm->VerticesList);
for(int i = 0; i < gm->NumVertices; ++i){
free(gm->Edge[i]);
}
free(gm->Edge);
gm->Edge = NULL;
gm->VerticesList = NULL;
gm->MaxVertices = gm->NumVertices = gm->NumEdges = 0;
} //取得与某顶点有连线的第一个顶点
int getNeighbor(GraphMtx* gm, T v){
int p = getVertexIndex(gm, v);
if(-1 == p)return -1;
for(int i = 0; i < gm->NumVertices; ++i){
if(gm->Edge[p][i] == 1)
return i;
}
return -1;
} //取得与v1顶点,v1顶点之后的v2顶点的之后的有连线的第一个顶点
int getNextNeighbor(GraphMtx* gm, T v1, T v2){
if(v1 == v2)return -1;
int p1 = getVertexIndex(gm, v1);
int p2 = getVertexIndex(gm, v2);
if(p1 == -1 || p2 == -1)return -1; for(int i = p2 + 1; i < gm->NumVertices; ++i){
if(gm->Edge[p1][i] == 1)
return i;
} return -1;
}

graph_mtxmain.c

#include "graph_mtx.h"

int main(){
GraphMtx gm;
//初始化图
init_graph(&gm);
//插入顶点
insert_vertex(&gm, 'A');
insert_vertex(&gm, 'B');
insert_vertex(&gm, 'C');
insert_vertex(&gm, 'D');
insert_vertex(&gm, 'E'); //添加连线
insert_edge(&gm, 'A', 'B');
insert_edge(&gm, 'A', 'D');
insert_edge(&gm, 'B', 'C');
insert_edge(&gm, 'B', 'E');
insert_edge(&gm, 'C', 'E');
insert_edge(&gm, 'C', 'D');
//打印图
show_graph(&gm); //删除连线
//remove_edge(&gm, 'A', 'B');
//打印图
//show_graph(&gm); //删除顶点
remove_vertex(&gm, 'A');
//打印图
show_graph(&gm); //添加顶点
insert_vertex(&gm, 'F');
//添加线
insert_edge(&gm, 'F', 'B');
insert_edge(&gm, 'F', 'C');
insert_edge(&gm, 'F', 'D');
//打印图
show_graph(&gm);
//删除顶点
remove_vertex(&gm, 'D');
//删除线
remove_edge(&gm, 'F', 'B');
//打印图
show_graph(&gm); //取得与某顶点有连线的第一个顶点
int p = getNeighbor(&gm, 'F');
printf("%d\n", p); //取得与v1顶点,v1顶点之后的v2顶点的之后的有连线的第一个顶点
int p1 = getNextNeighbor(&gm, 'E', 'B');
printf("%d\n", p1); //摧毁图
destroy_graph(&gm); }

c/c++ 图相关的函数(二维数组法)的更多相关文章

  1. c/c++ 图的创建(二维数组法)

    c/c++ 图的创建(二维数组法) 图的概念 图由点和线组成 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来 点之间的线,分有方向和无方向 创建图 创建图,实际就是创建出节点,和节点之 ...

  2. array_column() 函数[二维数组转为一维数组]

    array_column() 函数 输出数组中某个键值的集合[二维数组转为一位数组] <?php // 表示由数据库返回的可能记录集的数组 $a = array( array( 'id' =&g ...

  3. Java基本语法-----java二维数组

    由于word里的样式在csdn上调太麻烦了,所以我再次贴图了,后面二维数组那里是文字的,大家将就看吧. 二维数组常见的操作: 1.遍历二维数组 2.对二维数组求和 class Demo { // 定义 ...

  4. C语言中如何将二维数组作为函数的参数传递

    今天写程序的时候要用到二维数组作参数传给一个函数,我发现将二维数组作参数进行传递还不是想象得那么简单里,但是最后我也解决了遇到的问题,所以这篇文章主要介绍如何处理二维数组当作参数传递的情况,希望大家不 ...

  5. php对二维数组进行相关操作(排序、转换、去空白等)

    php对二维数组进行相关操作(排序.转换.去空白等) 投稿:lijiao 字体:[增加 减小] 类型:转载 时间:2015-11-04   这篇文章主要介绍了php对二维数组进行相关操作,包括php对 ...

  6. C语言学习笔记 (005) - 二维数组作为函数参数传递剖析

    前言 很多文章不外乎告诉你下面这几种标准的形式,你如果按照它们来用,准没错: //对于一个2行13列int元素的二维数组 //函数f的形参形式 f(int daytab[2][13]) {...} / ...

  7. C语言二维数组作为函数参数

    设有整型二维数组a[3][4]如下:0   1   2   34   5   6   78   9  10  11 它的定义为:    int a[3][4]={{0,1,2,3},{4,5,6,7} ...

  8. SDUT OJ 图练习-BFS-从起点到目标点的最短步数 (vector二维数组模拟邻接表+bfs , *【模板】 )

    图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 在古老的魔兽传说中,有两个军团,一个叫天 ...

  9. PHP代码篇(二)-- array_column函数将二维数组格式化成固定格式的一维数组,及优化查询方法

    小白因为经常用到多表查询,比如获取一个会员领取的卡卷list,里面当然包含了1“会员优惠券记录表t_coupon_members”主表,然后2“门店优惠券表t_coupon”,和3“门店信息表t_sh ...

随机推荐

  1. 【ASP.NET MVC系列】浅谈ASP.NET MVC运行过程

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  2. Mybatis学习(四)————— 高级映射,一对一,一对多,多对多映射

    一.单向和双向 包括一对一,一对多,多对多这三种情况,但是每一种又分为单向和双向,在hibernate中我们就详细解析过这单向和双向是啥意思,在这里,在重复一遍,就拿一对多这种关系来讲,比如有员工和部 ...

  3. eclipse中使用pull报错(git提交冲突)

    1.工程->Team->pull:报错 解决方案: 2.工程->Team->Syschronize Workspace: 3.在左侧会将有冲突的代码列举出来:(可选操作:在其上 ...

  4. JQuery官方学习资料(译):类型

    类型     JavaScript提供了多个内置数据类型.除了这些,这份文档还将介绍一些虚拟类型,例如选择器.伪类.事件等. String 在JavaScript中字符串是一个不可变的对象,它包含无. ...

  5. C# string数组转int数组

    用法 //字符串数组(源数组) string[] sNums = new[] {"1", "2"}; //整型数组(目标数组) int[] iNums; //转 ...

  6. [angularjs] angularjs系列笔记(五)Service

    AngularJs中你可以使用自己的服务或使用内建服务,服务是一个函数或对象,以下代码试验$location服务,$http服务,$timeout服务,$intverval服务,创建自定义服务 < ...

  7. linux内核里的字符串转换 ,链表操作常用函数(转)

    1.对双向链表的具体操作如下: list_add ———向链表添加一个条目 list_add_tail ———添加一个条目到链表尾部 __list_del_entry ———从链表中删除相应的条目 l ...

  8. Java学习笔记之——自动装箱与拆箱

    自动装箱与拆箱 基本类型与引用类型的互相转换 1. 基本类型对应的包装类 byte    short       char      int       long    flaot    double ...

  9. http协议、web服务器、并发服务器(下)

    Web静态服务器-5-非堵塞模式 单进程非堵塞模型 import socket import time def main(): tcp_socket_server = socket.socket(so ...

  10. JavaScript for/in 语句 遍历数组内容

    for-in遍历 for-in是为遍历对象而设计的,不适用于遍历数组. 遍历数组的缺点:数组的下标index值是数字,for-in遍历的index值"0","1" ...