c/c++ 图的创建及图的相关函数(链表法)

图的概念

  • 图由点和线组成
  • 知道了图中有多少个点,和哪些点之间有线,就可以把一张图描绘出来
  • 点之间的线,分有方向和无方向

创建图

创建图,实际就是创建出节点,和节点之间的线。

下面的代码实现了上面的图的创建

graph_link.h

#ifndef __graph_link__
#define __graph_link__ #include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <memory.h> #define default_vertex_size 10
#define T char //边的结构
typedef struct Edge{
//顶点的下标
int idx;
//指向下一个边的指针
struct Edge* link;
}Edge; //顶点的结构
typedef struct Vertex{
//顶点的值
T data;
//边
Edge* adj;
}Vertex; //图的结构
typedef struct GraphLink{
int MaxVertices;
int NumVertices;
int NumEdges; Vertex* nodeTable;
}GraphLink; //初始化图
void init_graph_link(GraphLink* g);
//显示图
void show_graph_link(GraphLink* g);
//插入顶点
void insert_vertex(GraphLink* g, T v);
//插入边尾插
void insert_edge_tail(GraphLink* g, T v1, T v2);
//插入边头插
void insert_edge_head(GraphLink* g, T v1, T v2);
//删除边
void remove_edge(GraphLink* g, T v1, T v2);
//删除顶点
void remove_vertex(GraphLink* g, T v);
//销毁图
void destroy_graph_link(GraphLink* g);
//取得指定顶点的第一个后序顶点
int get_first_neighbor(GraphLink* g, T v);
//取得指定顶点v1的临街顶点v2的第一个后序顶点
int get_next_neighbor(GraphLink* g, T v1, T v2); #endif

graph_link.c

#include "graph_link.h"

//初始化图
void init_graph_link(GraphLink* g){
g->MaxVertices = default_vertex_size;
g->NumVertices = g->NumEdges = 0; g->nodeTable = (Vertex*)malloc(sizeof(Vertex) * g->MaxVertices);
assert(NULL != g->nodeTable);
for(int i = 0; i < g->MaxVertices; ++i){
g->nodeTable[i].adj = NULL;
}
} //显示图
void show_graph_link(GraphLink* g){
if(NULL == g)return;
for(int i = 0; i < g->NumVertices; ++i){
printf("%d %c->", i, g->nodeTable[i].data);
Edge* p = g->nodeTable[i].adj;
while(NULL != p){
printf("%d->", p->idx);
p = p->link;
}
printf(" NULL\n");
}
} //插入顶点
void insert_vertex(GraphLink* g, T v){
if(g->NumVertices >= g->MaxVertices)return;
g->nodeTable[g->NumVertices++].data = v;
} //查找顶点的index
int getVertexIndex(GraphLink* g, T v){
for(int i = 0; i < g->NumVertices; ++i){
if(v == g->nodeTable[i].data)return i;
}
return -1;
} //创建边
void buyEdge(Edge** e, int idx){
Edge* p = (Edge*)malloc(sizeof(Edge));
p->idx = idx;
p->link = NULL;
if(NULL == *e){
*e = p;
}
else{
Edge* tmp = *e;
while(tmp->link != NULL){
tmp = tmp->link;
}
tmp->link = p;
}
}
//插入边(尾插)
void insert_edge_tail(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2); if(p1 == -1 || p2 == -1)return; buyEdge(&(g->nodeTable[p1].adj), p2);
g->NumEdges++;
buyEdge(&(g->nodeTable[p2].adj), p1);
g->NumEdges++; }
//插入边(头插)
void insert_edge_head(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2); if(p1 == -1 || p2 == -1)return; Edge* p = (Edge*)malloc(sizeof(Edge));
p->idx = p2;
p->link = g->nodeTable[p1].adj;
g->nodeTable[p1].adj = p; p = (Edge*)malloc(sizeof(Edge));
p->idx = p1;
p->link = g->nodeTable[p2].adj;
g->nodeTable[p2].adj = p;
}
//删除边
int remove_edge_(Edge** p, int i){
if(NULL == *p)return -1;
Edge* f;
//判断第一个边是否是目标边
if((*p)->idx == i){
//删除第一条边
f = *p;
*p = (*p)->link;
free(f);
return 0;
} Edge* tmp = *p;
while(tmp->link != NULL && tmp->link->idx != i){
tmp = tmp->link;
}
//没有找到边
if(tmp->link == NULL){
return -1;
}
//找到边
else{
f = tmp->link;
tmp->link = tmp->link->link;
free(f);
return 0;
} }
void remove_edge(GraphLink* g, T v1, T v2){
int p1 = getVertexIndex(g, v1);
int p2 = getVertexIndex(g, v2); if(p1 == -1 || p2 == -1)return; int r = remove_edge_(&(g->nodeTable[p1].adj), p2);
if(r == 0){
g->NumEdges--;
remove_edge_(&(g->nodeTable[p2].adj), p1);
g->NumEdges--;
} }
//删除顶点
void remove_vertex(GraphLink* g, T v){
int p = getVertexIndex(g, v); if(p == -1)return; //删除目标顶点以外的顶点,与目标顶点之间的边
for(int i = 0; i < g->NumVertices; ++i){
if(i == p){
continue;
}else{
remove_edge_(&(g->nodeTable[i].adj), p);
}
} //删除目标顶点行的所有边
Edge* te = g->nodeTable[p].adj;
Edge* tmp;
while(te != NULL){
tmp = te;
te = te->link;
free(tmp);
} //让被删除顶点那行,指向最后一个顶点那行。
//因为最后一行向上移动了,所以要修改和最后一行有连线的点那行的线的下标。
g->nodeTable[p].data = g->nodeTable[g->NumVertices - 1].data;
g->nodeTable[p].adj = g->nodeTable[g->NumVertices - 1].adj;
tmp = g->nodeTable[p].adj;
Edge* q;
while(tmp != NULL){
q = g->nodeTable[tmp->idx].adj;
while(q != NULL && q->idx != g->NumVertices - 1){
q = q->link;
}
q->idx = p; tmp = tmp->link;
}
g->NumVertices--;
}
//销毁图
void destroy_graph_link(GraphLink* g){
//释放所有边的内存空间
Edge* t = NULL;
Edge* p = NULL;
for(int i = 0; i< g->NumVertices; ++i){
t = g->nodeTable[i].adj;
while(NULL != t){
p = t;
t = t->link;
free(p);
}
} //释放所有顶点的内存空间
free(g->nodeTable);
g->nodeTable = NULL;
g->MaxVertices = g->NumVertices = g->NumEdges = 0;
} //取得指定顶点的第一个后序顶点
int get_first_neighbor(GraphLink* g, T v){
int i = getVertexIndex(g, v);
if (-1 == i)return -1;
Edge* p = g->nodeTable[i].adj;
if(NULL != p)
return p->idx;
else
return -1;
} //取得指定顶点v1的临街顶点v2的第一个后序顶点
int get_next_neighbor(GraphLink* g, T ve1, T ve2){
int v1 = getVertexIndex(g, ve1);
int v2 = getVertexIndex(g, ve2);
if(v1 == -1 || v2 == -1)return -1; Edge* t = g->nodeTable[v1].adj;
while(t != NULL && t->idx != v2){
t = t->link;
}
if(NULL != t && t->link != NULL){
return t->link->idx;
}
return -1;
}

graph_linkmain.c

#include "graph_link.h"

int main(){
GraphLink gl;
//初始化图
init_graph_link(&gl);
//插入节点
insert_vertex(&gl, 'A');
insert_vertex(&gl, 'B');
insert_vertex(&gl, 'C');
insert_vertex(&gl, 'D');
insert_vertex(&gl, 'E');
//显示图
//show_graph_link(&gl); //插入边(尾插)
/*
insert_edge_tail(&gl, 'A', 'B');
insert_edge_tail(&gl, 'A', 'D');
insert_edge_tail(&gl, 'B', 'C');
insert_edge_tail(&gl, 'B', 'E');
insert_edge_tail(&gl, 'C', 'D');
insert_edge_tail(&gl, 'C', 'E');
*/ //插入边(头插)
///*
insert_edge_head(&gl, 'A', 'B');
insert_edge_head(&gl, 'A', 'D');
insert_edge_head(&gl, 'B', 'C');
insert_edge_head(&gl, 'B', 'E');
insert_edge_head(&gl, 'C', 'D');
insert_edge_head(&gl, 'C', 'E');
//*/
//显示图
show_graph_link(&gl); printf("\n"); //删除边
remove_edge(&gl, 'A', 'D');
//显示图
show_graph_link(&gl); printf("\n"); //删除顶点
remove_vertex(&gl, 'C');
//显示图
show_graph_link(&gl); //临街顶点的下标
int v = get_first_neighbor(&gl, 'B');
printf("%d\n", v);
v = get_next_neighbor(&gl, 'B', 'A');
printf("%d\n", v);
//销毁图
destroy_graph_link(&gl);
}

c/c++ 图的创建及图的相关函数(链表法)的更多相关文章

  1. 使用StarUML创建类图

    使用StarUML创建类图 http://www.flyne.org/article/379 1.综述(What) StarUML是一种生成类图和其他类型的UML图表的工具.本文是一个使用StarUM ...

  2. 图的创建和遍历(BFS/DFS)

    图的表示方法主要有邻接矩阵和邻接表.其中邻接表最为常用,因此这里便以邻接表为例介绍一下图的创建及遍历方法. 创建图用到的结构有两种:顶点及弧 struct ArcNode { int vertexIn ...

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

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

  4. JS实现图的创建和遍历

    图分为无向图和有向图 图的存储结构有邻接矩阵.邻接表.十字链表.邻接多重表这四种,最常用的是前两种 本篇主要是利用邻接矩阵实现无向图的创建和遍历(深度优先.广度优先),深度优先其实就是二叉树里的前序遍 ...

  5. 如何用Rational rose创建类图

    UML中各种图形概要: 图名 对照 说明 用例图 use case diagram 用例图表明系统做什么,与谁交互.用例是系统提供的功能,参与者是系统与谁交互,参与者可以是人.系统或其他实体.一个系统 ...

  6. Unity3D 动态地创建识别图

    前面介绍了EasyAR的单图识别,它是提前在Unity设置好图片路径的,那么如果我们的图片是存储在服务器上的,那么我们肯定不能直接把服务的图片地址填上去了.这个时候我们可以动态地创建识别图.步骤如下: ...

  7. iOS启动图和开屏广告图,类似网易

    iOS启动图和开屏广告图,类似网易 启动图是在iOS开发过程中必不可少的一个部分,很多app在启动图之后会有一张自定义的开屏广告图,点击该广告图可以跳转到广告图对应的页面.今天呢,和大家分享一下如何添 ...

  8. Shader中贴图知识汇总: 漫反射贴图、凹凸贴图、高光贴图、 AO贴图、环境贴图、 光照纹理及细节贴图

    原文过于冗余,精读后做了部分简化与测试实践,原文地址:http://www.j2megame.com/html/xwzx/ty/2571.html   http://www.cnblogs.com/z ...

  9. c语言实现灰度图转换为二值图

    将上篇得到的灰度图转换为二值图,读取像素数据,低于某一值置0,否则设置为255,为得到更好的效果不同图片应采用不同的值 /* 2015年6月2日11:16:22 灰度图转换为二值图 blog:http ...

随机推荐

  1. ES6躬行记(7)——代码模块化

    在ES6之前,由于ECMAScript不具备模块化管理的能力,因此往往需要借助第三方类库(例如遵守AMD规范的RequireJS或遵循CMD规范的SeaJS等)才能实现模块加载.而自从ES6引入了模块 ...

  2. MyBatis源码解析(六)——DataSource数据源模块之池型数据源

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675674.html 1 回顾 上一文中解读了MyBatis中非池型数据源的源码,非池型也 ...

  3. 网络爬虫之html2md

    前言 上周利用java爬取的网络文章,一直未能利用java实现html转化md,整整一周时间才得以解决. 虽然本人的博客文章数量不多,但是绝不齿于手动转换,毕竟手动转换浪费时间,把那些时间用来做些别的 ...

  4. sed修炼系列(二):sed武功心法(info sed翻译+注解)

    sed系列文章: sed修炼系列(一):花拳绣腿之入门篇sed修炼系列(二):武功心法(info sed翻译+注解)sed修炼系列(三):sed高级应用之实现窗口滑动技术sed修炼系列(四):sed中 ...

  5. Perl和操作系统交互(二):fork

    fork + exec fork是低层次的系统调用,通过复制父进程来创建子进程. fork的行为 fork用来拷贝当前进程,生成一个基本完全一样的子进程. my $pid=fork(); 如果fork ...

  6. webpack 配置文件相关解说

    博客地址:https://ainyi.com/10 webpack - 什么是webpack: WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它 ...

  7. sql存储过程,根据多个条件查询,返回一个dataTable或者DataSet

    不废话,先直接代码 首先sql部分(我在这里加了一个@zx作为判断,一般不需要这个参数): ALTER Proc [dbo].[Proc_Boss_Show] ),--开始条数 ),--结束条数 @S ...

  8. [转]Nginx 静态资源缓存设置

    本文转自:https://www.w3cschool.cn/nginxsysc/nginxsysc-cache.html 在开发调试web的时候,经常会碰到因浏览器缓存(cache)而经常要去清空缓存 ...

  9. Codeforces617E(莫队)

    E. XOR and Favorite Number time limit per test: 4 seconds memory limit per test: 256 megabytes input ...

  10. mapper代理查询

    对于查询来说,要根据具体的业务,来指定mapper接口中方法的返回值类型1:如果只返回一条记录,mapper接口中方法的返回值类型应指定为pojo类型或其他简单类型,这样mybatis内部就会使用se ...