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. spring学习(四) ———— 整合web项目(SSH)

    清楚了spring的IOC 和 AOP,最后一篇就来整合SSH框架把,记录下来,以后应该会用的到. --WH 一.web项目中如何使用spring? 当tomcat启动时,就应该加载spring的配置 ...

  2. Linux上安装nginx+tomcat负载均衡

    1.Ngnix Nginx (发音同 engine x)是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.  其特点是占有内 ...

  3. 第一册:lesson sixty seven。

    原文: The weekend. A:Hello , were you an tht butcher's? B:Yes I was. A:Were you at the butcher's too? ...

  4. 集成腾讯位置服务到webapi

    经纬度转换为详细地址信息 参考文档:http://lbs.qq.com/webservice_v1/guide-gcoder.html 首先申请key,如果使用的是服务端请求webservice AP ...

  5. C# 操作注册表WindowsRegistry

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsof ...

  6. MyBatis进阶使用——动态SQL

    MyBatis的强大特性之一就是它的动态SQL.如果你有使用JDBC或者其他类似框架的经验,你一定会体会到根据不同条件拼接SQL语句的痛苦.然而利用动态SQL这一特性可以彻底摆脱这一痛苦 MyBati ...

  7. hihoCoder编程练习赛69

    题目1 : 偶数长度回文子串 时间限制:5000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个小写字母字符串,请判断它是否有长度为偶数的非空连续回文子串 输入 输入包含多组数据. ...

  8. 向后台提交数据:通过form表单提交数据需刷新网页 但通过Ajax提交数据不用刷新网页可通过原生态Ajax或jqueryAjax。Ajax代码部分

    原生态Ajax提交表单:需要借助XMLHttpRequest对象的open,要收通过post发送请求还要setRequsetHeader,然后把数据发送给后端,代码如下 目录结构 index.py代码 ...

  9. 《JavaScript高级程序设计》笔记:在HTML中使用Javascript(二)

    script元素 向html页面中插入js的主要方法就是使用<script>元素.使用<script>元素的方式有两种:直接在页面中嵌入js代码和包含外部js文件.直接在页面中 ...

  10. 洛谷P4578 [FJOI2018]所罗门王的宝藏(dfs)

    题意 题目链接 Sol 对于每个询问\(x, y, c\) 从在\((x, y)\)之间连一条边权为\(c\)的双向边,然后就是解\(K\)个二元方程. 随便带个数进去找找环就行了 #include& ...