邻接表 

邻接矩阵的实现请看这里

是不错的一种图存储结构,但是,对于边数相对顶点较少的图,这种结构存在对存储空间的极大浪费。因此,找到一种数组与链表相结合的存储方法称为邻接表
邻接表的处理方法是这样的:

  • (1)图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过,数组可以较容易的读取顶点的信息,更加方便。
  • (2)图中每个顶点vi的所有邻接点构成一个线性表,由于邻接点的个数不定,所以,用单链表存储,无向图称为顶点vi的边表,有向图则称为顶点vi作为弧尾的出边表。
    例如,下图就是一个无向图的邻接表的结构。

从图中可以看出,顶点表的各个结点由data和firstedge两个域表示,data是数据域,存储顶点的信息,firstedge是指针域,指向边表的第一个结点,即此顶点的第一个邻接点。边表结点由adjvex和next两个域组成。adjvex是邻接点域,存储某顶点的邻接点在顶点表中的下标,next则存储指向边表中下一个结点的指针。
对于带权值的网图,可以在边表结点定义中再增加一个weight的数据域,存储权值信息即可。如下图所示。

代码实现邻接表(有向邻接表图) 基于C++

/*** C++: 邻接表图** @author lph* */#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;#define MAX 100
// 邻接表
class ListDG {
private: // 内部类// 邻接表中表对应的链表顶点class ENode {public:int ivex;         // 该边所指向的顶点的位置ENode* nextEdge;  // 指向下一条弧的指针};// 邻接表中表的顶点class VNode {public:char data;         //顶点信息ENode* firstEdge; //指向第一条依赖该顶点的弧};private: // 私有成员int mVexNum;            //图的顶点的数目int mEdgNum;           //图的边的数目VNode mVexs[MAX];       //用一维数组来存储邻接表的顶点public:// 创建邻接表对应的图(自己输入)ListDG();// 创建邻接表对应的图(用已经提供的数据)ListDG(char vexs[], int vlen, char edges[][2], int elen);~ListDG();// 打印邻接表图void print();private:// 读取一个输入字符char readChar();// 返回ch的位置int getPosition(char ch);// 将node节点链接到List的最后void linkLast(ENode* list, ENode* node);
};/*
* 创建邻接表对应的图(自己输入)
*/
ListDG::ListDG() {char c1, c2;int v, e;int i, p1, p2;ENode* node1, * node2;// 输入顶点数和边数cout << "input vertex number: ";cin >> mVexNum;cout << "input edge number: ";cin >> mEdgNum;if (mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum - 1)))) {cout << "input error: invalid parameters! " << endl;return;}// 初始化邻接表的顶点for (i = 0; i < mVexNum; ++i) {cout << "vertex(" << i << "):";mVexs[i].data = readChar();mVexs[i].firstEdge = nullptr;}// 初始化邻接表的边for (i = 0; i < mEdgNum; ++i) {// 读取边的起始点和结束顶点cout << "edge(" << i << "):";c1 = readChar();c2 = readChar();p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到p1所在链表的末尾if (mVexs[p1].firstEdge == nullptr)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}
}/*创建邻接表对应的图(用已经提供的数据)
*/
ListDG::ListDG(char vexs[], int vlen, char edges[][2], int elen) {char c1, c2;int i, p1, p2;ENode* node1, * node2;// 初始化顶点数和边数mVexNum = vlen;mEdgNum = elen;// 初始化"邻接表"的顶点for (i = 0; i < mVexNum; i++){mVexs[i].data = vexs[i];mVexs[i].firstEdge = NULL;}// 初始化邻接表的边for (i = 0; i < mEdgNum; ++i) {// 读取边的起始顶点和结束顶点c1 = edges[i][0];c2 = edges[i][1];p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到p1所在链表的末尾if (mVexs[p1].firstEdge == nullptr)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);}
}/*析构函数
*/
ListDG::~ListDG() {}
/*将node节点连接到List最后
*/
void ListDG::linkLast(ENode* list, ENode* node) {ENode* p = list;while (p->nextEdge)p = p->nextEdge;p->nextEdge = node;
}/*返回ch的位置
*/
int ListDG::getPosition(char ch) {int i;for (i = 0; i < mVexNum; ++i) if (mVexs[i].data == ch)return i;return -1; // 失败返回-1}/*读取一个输入字符
*/
char ListDG::readChar() {char ch;do {cin >> ch;} while (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')));return ch;
}/*打印邻接表图
*/
void ListDG::print() {int i, j;ENode* node;cout << "List Graph: " << endl;for (i = 0; i < mVexNum; ++i) {cout << i << "(" << mVexs[i].data << "):";node = mVexs[i].firstEdge;while (node != nullptr) {cout << node->ivex << "(" << mVexs[node->ivex].data << ") ";node = node->nextEdge;}cout << endl;}
}
int main() {char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };char edges[][2] = {{'A', 'B'},{'B', 'C'},{'B', 'E'},{'B', 'F'},{'C', 'E'},{'D', 'C'},{'E', 'B'},{'E', 'D'},{'F', 'G'} };int vlen = sizeof(vexs) / sizeof(vexs[0]);int elen = sizeof(edges) / sizeof(edges[0]);ListDG* pG;// 自定义图(输入矩阵队列)// pG = new ListDG();// 采用已经有的图pG = new ListDG(vexs, vlen, edges, elen);pG->print();return 0;}

用已经有的数据运行代码后的结果(有向邻接表图)为:

用自己手动输入数据的结果(有向邻接表图)

邻接表的实现(无向邻接表图) :

/*C++: 邻接表表示的"无向图(List Undirected Graph)"@author lph*/
#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;constexpr auto MAX = 100;
// 邻接表;
class ListUDG {
private:// 内部类// 邻接表中表对应的链表的顶点class ENode {public:int ivex;     // 该边所指向的顶点的位置ENode* nextEdge;// 指向下一条弧的指针};// 邻接表中表对应的顶点class VNode {public:char data;     // 顶点信息ENode* firstEdge;// 指向第一条依赖该顶点的弧};
private:int mVexNum;        // 图的顶点个数int mEdgNum;       // 图的边的数目VNode mVexs[MAX];  // 一维数组存储图的顶点,也就是邻接表第一列的顶点
public:// 创建邻接表对应的图(自己输入)ListUDG();// 创建邻接表对应的图(用已经提供的数据)ListUDG(char vexs[], int vlen, char edges[][2], int elen);// 析构函数~ListUDG();// 打印邻接表图void print();
private:// 读取一个输入字符char readChar();// 返回ch的位置int getPosition(char ch);// 将node节点链接到list的最后void linkLast(ENode* list, ENode* node);
};
/*创建邻接表对应的图(自己输入)
*/
ListUDG::ListUDG() {char c1, c2;// int v, e;int i, p1, p2;ENode* node1, * node2;// 输入顶点数和边数cout << "input vertex number: ";cin >> mVexNum;cout << "input edge number: ";cin >> mEdgNum;if (mVexNum < 1 || mEdgNum < 1 || (mEdgNum > (mVexNum * (mVexNum - 1)))) {cout << "input error: invalid parameters!" << endl;return;
}// 初始化邻接表的顶点for (i = 0; i < mVexNum; ++i) {cout << "vertex(" << i << "):";mVexs[i].data = readChar(); // 如果mVexs在之前用的是VNode* mVexs[MAX],那么这里需要用指针mVexs[i]->datamVexs[i].firstEdge = nullptr;}// 初始化邻接表的边for (i = 0; i < mEdgNum; ++i) {// 读取边的起点和结束顶点cout << "edge(" << i << "):";c1 = readChar();c2 = readChar();p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到p1所在链表的末尾if (mVexs[p1].firstEdge == nullptr)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;// 将node2链接到p2所在链表的末尾if (mVexs[p2].firstEdge == nullptr)mVexs[p2].firstEdge = node2;elselinkLast(mVexs[p2].firstEdge, node2);}
}
/*创建邻接表对应的图(用已提供的数据)
*/
ListUDG::ListUDG(char vexs[], int vlen, char edges[][2], int elen) {char c1, c2;int i, p1, p2;ENode* node1, * node2;// 初始化顶点数和边数mVexNum = vlen;mEdgNum = elen;// 初始化邻接表的顶点for (i = 0; i < mVexNum; ++i) {mVexs[i].data = vexs[i];mVexs[i].firstEdge = nullptr;}// 初始化邻接表的边for (i = 0; i < mEdgNum; ++i) {// 读取边的起始顶点和结束顶点c1 = edges[i][0];c2 = edges[i][1];p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;// 将node1链接到p1所在的末尾if (mVexs[p1].firstEdge == nullptr)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;// 将node2链接到p2所在链表的末尾if (mVexs[p2].firstEdge == nullptr)mVexs[p2].firstEdge = node2;elselinkLast(mVexs[p2].firstEdge, node2);}
}
/*析构函数
*/
ListUDG::~ListUDG() {}
/*将node节点连接到list最后
*/
void ListUDG::linkLast(ENode* list, ENode* node) {ENode* p = list;while (p->nextEdge)p = p->nextEdge;p->nextEdge = node;
}
/*返回ch的位置
*/
int ListUDG::getPosition(char ch) {int i;for (i = 0; i < mVexNum; ++i) if (mVexs[i].data == ch)return i;return -1;
}
/*读取一个输入字符
*/
char ListUDG::readChar() {char ch;do {cin >> ch;} while  (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')));return ch;
}/*打印邻接表图
*/
void ListUDG::print() {int i, j;ENode* node;cout << "List Graph:" << endl;for (i = 0; i < mVexNum; ++i) {cout << i << "(" << mVexs[i].data << ")";node = mVexs[i].firstEdge;while (node != nullptr) {cout << node->ivex << "(" << mVexs[node->ivex].data << ")";node = node->nextEdge;}cout << endl;}
}
int main(){char vexs[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G' };char edges[][2] = {{'A', 'C'},{'A', 'D'},{'A', 'F'},{'B', 'C'},{'C', 'D'},{'E', 'G'},{'F', 'G'} };int vlen = sizeof(vexs) / sizeof(vexs[0]);int elen = sizeof(edges) / sizeof(edges[0]);ListUDG* pG;// 自定义"图"(输入矩阵队列)//pG = new ListUDG();// 采用已有的"图"pG = new ListUDG(vexs, vlen, edges, elen);pG->print();   // 打印图return 0;
}

打印已提供邻接表(无向邻接表图)数据的结果: 

 打印自己输入的邻接表(无向邻接表图)的数据:

邻接矩阵的实现请看这里

邻接表的实现(有向邻接表)、(无向邻接表),基于C++相关推荐

  1. leftjoin多表联合查询_结合mybatis-plus 实现无XML多表联合查询

    项目地址:github multipleselect java mybatis 多表查询 简介 实现简单的实体类操作多表, 首先你的项目是使用了mybatis-plus 才可以使用 设计说明 如何关联 ...

  2. 构建静态服务器_为静态网站构建无服务器联系表

    构建静态服务器 介绍 (Introduction) A few years ago AWS launched static hosting service S3, which was a paradi ...

  3. mysql 表空间监控shell_一种通过zabbix监控mysql表空间的方法

    一种通过zabbix监控mysql表空间的方法[ 技术领域: ][0001]本发明涉及计算机自动化运维与监控领域,具体地说是一种通过ZABBIX监控MYSQL表空间的方法.[ 背景技术: ][0002 ...

  4. 你分库分表的姿势对么?——详谈水平分库分表

    作者:vivo平台产品开发团队-Han Lei 一.背景 提起分库分表,对于大部分服务器开发来说,其实并不是一个新鲜的名词.随着业务的发展,我们表中的数据量会变的越来越大,字段也可能随着业务复杂度的升 ...

  5. html实现动态多表单输入,提交多个动态添加的html表单

    我正在构建一个可以动态添加表单的功能.不是表单字段,而是一个完整的单独的HTML表单.提交多个动态添加的html表单 我使用JS添加它们. add_email_template $('#add_ema ...

  6. mysql grant all详解_grant all赋权后mysql.user表权限字段还是N,但能登录和新建表

    grant all privileges on linuxeye.* to linuxeye@'localhost' identified by 'linuxeye'; select * from m ...

  7. html表单输入框添加验证码,织梦Dedecms为自定义表单添加验证码功能

    使用织梦Dedecms自定义表单的时候,即使你做了字段的验证,也很有可能被人刷很多垃圾的内容,更加安全的一个方法是为自定义表单添加上验证码功能.今天我就来为大家分享一下怎样给自定义表单添加验证码! 一 ...

  8. mysql 列出表_[MySQL优化1]centos中MySQL列出所有表

    步骤1 - 连接到MySQL数据库服务器: [root@host]# mysql -u root -p Enter password:****** 提示登陆成功 Welcome to the MySQ ...

  9. html表单的数据保存在哪里,提交和保存表单数据

    关于提交数据连接 用户提交表单就表示表单已经填写完毕.此时数据通过提交数据连接提交,该连接将信息保存在 SharePoint 表单库等外部数据源中.这一点与保存表单操作不同.例如,作为表单设计者,当您 ...

最新文章

  1. StoneAge Dict 技术方案的可行性[1]
  2. 开源!开源!我写的Anto.exe C#代码自动生成工具.欢迎下载。。
  3. port常用和不常用端口一览表
  4. 纯css实现网页侧边栏弹窗滑进滑出
  5. ubuntu 18 mysql5.7_Ubuntu18.04 下 MySQL5.7 的安装
  6. 【报错笔记】Navicat连接数据库显示2003错误,无法连接到数据库
  7. 《UML面向对象设计基础》—第1章1.5节消息
  8. 简单实用的多线程学习实例
  9. linux内核维护者,Linux 内核维护者封杀明尼苏达大学(转载) - 优秀的Free OS(Linux)版 - 北大未名BBS...
  10. 关于Mybatis的xml配置文件中使用and与or混合查询
  11. Tomcat 7 部署和配置
  12. 【计算机网络】信源编码——香农三大定理
  13. oracle exadata中国保有量,怎样购买Exadata?
  14. JAVA文件夹批量重命名
  15. 手绘机器学习全流程,教你如何实现模型训练
  16. 暗影精灵8 Pro 安装 Ubuntu20.04 问题记录
  17. 年仅21岁,干掉6位诺贝尔奖得主,被誉为科学界最强杀手,却惨被人骂成一个笑话...
  18. 计算机型号或配置,查看电脑各项配置参数的方法
  19. 学习如何做个有钱人 你也有机会赚上1000万
  20. EET_loss学习

热门文章

  1. Codeforces Round #410 (Div. 2) D. Mike and distribution(贪心)
  2. Java-基础-6.Xml
  3. 刘洋——联邦学习技术在金融领域的研究与应用
  4. python学习技术网站收集
  5. PCI Express 布线规范
  6. uni-app实战开发
  7. 外校保研北大计算机,保研到清华、北大的外校学生,武大最多、山大次之
  8. nvidia jetson nano 风扇控制
  9. Oracle 学习笔记 12 -- 序列、索引、同义词
  10. python科学计算——用Weave嵌入C语言