C++数据结构之实现邻接表

本文实例为大家分享了C++数据结构之实现邻接表的具体代码,供大家参考,具体内容如下

一、图的邻接表实现

1.实现了以顶点顺序表、边链表为存储结构的邻接表;

2.实现了图的创建(有向/无向/图/网)、边的增删操作、深度优先递归/非递归遍历、广度优先遍历的算法;

3.采用顶点对象列表、边(弧)对象列表的方式,对图的创建进行初始化;引用 "ObjArrayList.h"头文件,头文件可参看之前博文“数据结构之顺序列表(支持对象元素)”代码;

4.深度优先遍历分别采用递归/非递归算法;非递归中用到的栈,引用"LinkStack.h"头文件,头文件可参看之前博文“数据结构之栈”代码;

5.广度优先遍历采用队列方式实现;用到的队列,引用 "LinkQueue.h"头文件,头文件可参看之前博文“数据结构之队列”代码;

6.测试代码中以有向网的所有带权边作为边的初始化数据,选择图类型(DG, UDG, DN, UDN)可创建成不同类型的图。

7.优劣分析:

7.1.(优势)邻接表存储结构,相比邻接矩阵,消除了无邻接关系顶点的边存储空间;

7.2.(优势)邻接表比邻接矩阵更容易访问某顶点的邻接顶点;

7.3.(优势)邻接表比邻接矩阵更易于统计边总数,无需逐行逐列遍历;

7.4.(劣势)在确定两顶点间是否有边的搜索过程中,邻接表不如邻接矩阵可直接寻址快,反而需要顶点到边链的遍历;

7.5.(劣势)邻接矩阵在删除顶点时,只需清除对应行列数据即可;而邻接表在清除顶点指向的边链后,还需遍历整个边表,清除所有邻接于此顶点的边结点;

7.6.(不足)邻接表在统计有向图出度时容易,只需遍历依附此顶点的边链;却在统计其入度时,需要遍历整个边表,比较麻烦;可采用十字链表(邻接表与逆邻接表的结合)解决这个问题;

7.7.(不足)邻接表在无向图的存储中,属于行列对称矩阵形式,因此会有一半重复的边数据,故可采用邻接多重表,只存储一半边,来优化存储。

二、测试代码中的图结构

深度优先遍历序列(从 v1 顶点开始):

1.无向图/网:v1-v2-v3-v5-v4-v6-v7

2.有向图/网:v1-v2-v5-v3-v4-v6-v7

广度优先遍历序列(从 v2 顶点开始):

1.无向图/网:v2-v1-v3-v5-v4-v6-v7

2.有向图/网:v2-v5 后序无法遍历

注:有向图的遍历 是遵循出度方向遍历的,若无出度方向,则遍历终止。

三、代码

//文件名:"GraphAdjList.h"
#pragma once
#ifndef GRAPHADJLISL_H_
#define GRAPHADJLISL_H_

#include <string>
#include "ObjArrayList.h"
using namespace std;

/*
. 图(邻接表实现) Graph Adjacency List
. 相关术语:
. 顶点 Vertex ; 边 Arc ;权 Weight ;
. 有向图 Digraph ;无向图 Undigraph ;
. 有向网 Directed Network ;无向网 Undirected Network ;
. 存储结构:
. 1.顶点表只能采用顺序结构。(因为若采用链式结构,顶点结点定义与边表结点定义就相互引用,无法定义)
. 2.边表采用链表结构。
*/

class GraphAdjList
{
 /*
 . 边表(链表)结点
 */
 struct ArcNode
 {
 int adjVex; //邻接顶点所在表中下标
 int weight; //边权重
 ArcNode * next; //下一条边
 };
 /*
 . 顶点表(顺序表)结点
 */
 struct VNode
 {
 string name; //顶点名
 ArcNode * first; //指向的第一个依附该顶点的顶点边结点
 };
public:
 /*
 . 图 种类
 */
 enum GraphType
 {
 DG, //有向图,默认 0
 UDG, //无向图,默认 1
 DN, //有向网,默认 2
 UDN //无向网,默认 3
 };
 /*
 . 边(弧)数据,注:供外部初始化边数据使用
 */
 struct ArcData
 {
 string Tail; //弧尾
 string Head; //弧头
 int Weight; //权重
 };

private:
 static const int _MAX_VERTEX_NUM = 10; //支持最大顶点数

 VNode vexs[_MAX_VERTEX_NUM]; //顶点表
 int vexs_visited[_MAX_VERTEX_NUM]; //顶点访问标记数组:0|未访问 1|已访问
 int vexNum; //顶点数
 int arcNum; //边数
 int type; //图种类

 void _CreateVexSet(ObjArrayList<string> * vexs); //创建顶点集合
 void _CreateDG(ObjArrayList<ArcData> * arcsList); //创建有向图
 void _CreateUDG(ObjArrayList<ArcData> * arcsList); //创建无向图
 void _CreateDN(ObjArrayList<ArcData> * arcsList); //创建有向网
 void _CreateUDN(ObjArrayList<ArcData> * arcsList); //创建无向网

 int _Locate(string vertex);   //定位顶点元素位置
 void _InsertArc(int tail, int head, int weight); //插入边(元操作,不分有向/无向)
 void _DeleteArc(int tail, int head);  //删除边(元操作,不分有向/无向)
 void _DFS_R(int index);   //深度优先遍历 递归
 void _DFS(int index);   //深度优先遍历 非递归

public:
 GraphAdjList(int type); //构造函数:初始化图种类
 ~GraphAdjList();  //析构函数
 void Init(ObjArrayList<string> * vexs, ObjArrayList<ArcData> * arcsList); //初始化顶点、边数据为 图|网
 void InsertArc(ArcData * arcData); //插入边(含有向/无向操作)
 void DeleteArc(ArcData * arcData); //删除边(含有向/无向操作)
 void Display();  //显示 图|网
 void Display_DFS_R(string *vertex); //从指定顶点开始,深度优先 递归 遍历
 void Display_DFS(string *vertex); //从指定顶点开始,深度优先 非递归 遍历
 void Display_BFS(string *vertex); //从指定顶点开始,广度优先遍历

};
//文件名:"GraphAdjList.cpp"
#include "stdafx.h"
#include <string>
#include "ObjArrayList.h"
#include "LinkQueue.h"
#include "LinkStack.h"
#include "GraphAdjList.h"
using namespace std;

GraphAdjList::GraphAdjList(int type)
{
 /*
 . 构造函数:初始化图类型
 */
 this->type = type;
 this->vexNum = 0;
 this->arcNum = 0;
}

GraphAdjList::~GraphAdjList()
{
 /*
 . 析构函数:销毁图
 */
}

void GraphAdjList::Init(ObjArrayList<string> * vexs, ObjArrayList<ArcData> * arcsList)
{
 /*
 . 初始化顶点、边数据,并构建 图|网
 . 入参:
 . vexs: 顶点 列表
 . arcsList: 边数据 列表
 */
 //1.创建顶点集
 _CreateVexSet(vexs);
 //2.根据图类型,创建指定的图
 switch (this->type)
 {
 case DG:
 _CreateDG(arcsList); break;
 case UDG:
 _CreateUDG(arcsList); break;
 case DN:
 _CreateDN(arcsList); break;
 case UDN:
 _CreateUDN(arcsList); break;
 default:
 break;
 }
}

void GraphAdjList::_CreateVexSet(ObjArrayList<string> * vexs)
{
 /*
 . 创建顶点集合
 */
 string vertex = "";
 //顶点最大数校验
 if (vexs->Length() > this->_MAX_VERTEX_NUM)
 {
 return;
 }
 //遍历顶点表,无重复插入顶点,并计数顶点数
 for (int i = 0; i < vexs->Length(); i++)
 {
 vertex = *vexs->Get(i);
 if (_Locate(vertex) == -1)
 {
 this->vexs[this->vexNum].name = vertex;
 this->vexs[this->vexNum].first = NULL;
 this->vexNum++;
 }
 }
}

void GraphAdjList::_CreateDG(ObjArrayList<ArcData> * arcsList)
{
 /*
 . 创建有向图
 . 邻接矩阵为 非对称边
 */
 //初始化临时 边对象
 ArcData * arcData = NULL;
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 //遍历边数据列表
 for (int i = 0; i < arcsList->Length(); i++)
 {
 //按序获取边(弧)
 arcData = arcsList->Get(i);
 //定位(或设置)边的两端顶点位置
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //插入边
 _InsertArc(tail, head, 0);
 }
}

void GraphAdjList::_CreateUDG(ObjArrayList<ArcData> * arcsList)
{
 /*
 . 创建无向图
 . 邻接矩阵为 对称边
 */
 //初始化临时 边对象
 ArcData * arcData = NULL;
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 //遍历边数据列表
 for (int i = 0; i < arcsList->Length(); i++)
 {
 //按序获取边(弧)
 arcData = arcsList->Get(i);
 //定位(或设置)边的两端顶点位置
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //插入对称边
 _InsertArc(tail, head, 0);
 _InsertArc(head, tail, 0);
 }
}

void GraphAdjList::_CreateDN(ObjArrayList<ArcData> * arcsList)
{
 /*
 . 创建有向网
 . 邻接矩阵为 非对称矩阵
 */
 //初始化临时 边对象
 ArcData * arcData = NULL;
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 //遍历边数据列表
 for (int i = 0; i < arcsList->Length(); i++)
 {
 //按序获取边(弧)
 arcData = arcsList->Get(i);
 //定位(或设置)边的两端顶点位置
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //插入边
 _InsertArc(tail, head, arcData->Weight);
 }
}

void GraphAdjList::_CreateUDN(ObjArrayList<ArcData> * arcsList)
{
 /*
 . 创建无向网
 . 邻接矩阵为 对称矩阵
 */
 //初始化临时 边对象
 ArcData * arcData = NULL;
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 //遍历边数据列表
 for (int i = 0; i < arcsList->Length(); i++)
 {
 //按序获取边(弧)
 arcData = arcsList->Get(i);
 //定位(或设置)边的两端顶点位置
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //插入对称边
 _InsertArc(tail, head, arcData->Weight);
 _InsertArc(head, tail, arcData->Weight);
 }
}

int GraphAdjList::_Locate(string vertex)
{
 /*
 . 定位顶点元素位置
 . 后期可改成【字典树】,顶点数超过100个后定位顶点位置可更快
 */
 //遍历定位顶点位置
 for (int i = 0; i < this->_MAX_VERTEX_NUM; i++)
 {
 if (vertex == this->vexs[i].name)
 {
 return i;
 }
 }
 //cout << endl << "顶点[" << vertex << "]不存在。" << endl;
 return -1;
}

void GraphAdjList::_InsertArc(int tail, int head, int weight)
{
 /*
 . 插入边(元操作,不分有向/无向)
 */
 //边结点指针:初始化为 弧尾 指向的第一个边
 ArcNode * p = this->vexs[tail].first;
 //初始化 前一边结点的指针
 ArcNode * q = NULL;
 //重复边布尔值
 bool exist = false;
 //1.边的重复性校验
 while (p != NULL)
 {
 //若已存在该边,则标记为 存在 true
 if (p->adjVex == head)
 {
 exist = true;
 break;
 }
 //若不是该边,继续下一个边校验
 q = p;
 p = p->next;
 }
 //2.1.如果边存在,则跳过,不做插入
 if (exist)
 return;
 //2.2.边不存在时,创建边
 ArcNode * newArc = new ArcNode();
 newArc->adjVex = head;
 newArc->weight = weight;
 newArc->next = NULL;
 //3.1.插入第一条边
 if (q == NULL)
 {
 this->vexs[tail].first = newArc;
 }
 //3.2.插入后序边
 else
 {
 q->next = newArc;
 }
 //4.边 计数
 this->arcNum++;
}

void GraphAdjList::InsertArc(ArcData * arcData)
{
 /*
 . 插入边(含有向/无向操作)
 */
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //根据图类型,插入边
 switch (this->type)
 {
 case DG:
 _InsertArc(tail, head, 0);
 break;
 case UDG:
 _InsertArc(tail, head, 0);
 _InsertArc(head, tail, 0);
 break;
 case DN:
 _InsertArc(tail, head, arcData->Weight);
 break;
 case UDN:
 _InsertArc(tail, head, arcData->Weight);
 _InsertArc(head, tail, arcData->Weight);
 break;
 default:
 break;
 }
}

void GraphAdjList::_DeleteArc(int tail, int head)
{
 /*
 . 删除边(元操作,不分有向/无向)
 */
 //边结点指针:初始化为 弧尾 指向的第一个边
 ArcNode * p = this->vexs[tail].first;
 //初始化 前一边结点的指针
 ArcNode * q = NULL;
 //1.遍历查找边
 while (p != NULL)
 {
 //若存在该边,则结束循环
 if (p->adjVex == head)
 {
 break;
 }
 //若不是该边,继续下一个边
 q = p;
 p = p->next;
 }
 //2.1.边不存在
 if (p == NULL)
 {
 cout << endl << "边[" << this->vexs[head].name << "->" << this->vexs[head].name << "]不存在。" << endl;
 return;
 }
 //2.2.边存在,删除边
 //2.2.1.若为第一条边
 if (q == NULL)
 {
 this->vexs[tail].first = p->next;
 }
 //2.2.2.非第一条边
 else
 {
 q->next = p->next;
 }
 //3.释放 p
 delete p;
}

void GraphAdjList::DeleteArc(ArcData * arcData)
{
 /*
 . 删除边(含有向/无向操作)
 */
 //初始化 Tail Head 顶点下标索引
 int tail = 0, head = 0;
 tail = _Locate(arcData->Tail);
 head = _Locate(arcData->Head);
 //根据图类型,删除边
 switch (this->type)
 {
 case DG:
 _DeleteArc(tail, head);
 break;
 case UDG:
 _DeleteArc(tail, head);
 _DeleteArc(head, tail);
 break;
 case DN:
 _DeleteArc(tail, head);
 break;
 case UDN:
 _DeleteArc(tail, head);
 _DeleteArc(head, tail);
 break;
 default:
 break;
 }
}

void GraphAdjList::Display()
{
 /*
 . 显示 图|网
 */
 //初始化边表结点指针
 ArcNode * p = NULL;
 cout << endl << "邻接表:" << endl;
 //遍历顶点表
 for (int i = 0; i < this->_MAX_VERTEX_NUM; i++)
 {
 //空顶点(在删除顶点的操作后会出现此类情况)
 if (this->vexs[i].name == "")
 {
 continue;
 }
 //输出顶点
 cout << "[" << i << "]" << this->vexs[i].name << " ";
 //遍历输出边顶点
 p = this->vexs[i].first;
 while (p != NULL)
 {
 cout << "[" << p->adjVex << "," << p->weight << "] ";
 p = p->next;
 }
 cout << endl;
 }
}

void GraphAdjList::_DFS_R(int index)
{
 /*
 . 深度优先遍历 递归
 */
 //1.访问顶点,并标记已访问
 cout << this->vexs[index].name << " ";
 this->vexs_visited[index] = 1;
 //2.遍历访问其相邻顶点
 ArcNode * p = this->vexs[index].first;
 int adjVex = 0;
 while (p != NULL)
 {
 adjVex = p->adjVex;
 //当顶点未被访问过时,可访问
 if (this->vexs_visited[adjVex] != 1)
 {
 _DFS_R(adjVex);
 }
 p = p->next;
 }
}

void GraphAdjList::Display_DFS_R(string *vertex)
{
 /*
 . 从指定顶点开始,深度优先 递归 遍历
 */
 //1.判断顶点是否存在
 int index = _Locate(*vertex);
 if (index == -1)
 return;
 //2.初始化顶点访问数组
 for (int i = 0; i < this->_MAX_VERTEX_NUM; i++)
 {
 this->vexs_visited[i] = 0;
 }
 //3.深度优先遍历 递归
 cout << "深度优先遍历(递归):(从顶点" << *vertex << "开始)" << endl;
 _DFS_R(index);
}

void GraphAdjList::_DFS(int index)
{
 /*
 . 深度优先遍历 非递归
 */
 //1.访问第一个结点,并标记为 已访问
 cout << this->vexs[index].name << " ";
 vexs_visited[index] = 1;
 //初始化 边结点 栈
 LinkStack<ArcNode> * s = new LinkStack<ArcNode>();
 //初始化边结点 指针
 ArcNode * p = this->vexs[index].first;
 //2.寻找下一个(未访问的)邻接结点
 while (!s->Empty() || p != NULL)
 {
 //2.1.未访问过,则访问 (纵向遍历)
 if (vexs_visited[p->adjVex] != 1)
 {
 //访问结点,标记为访问,并将其入栈
 cout << this->vexs[p->adjVex].name << " ";
 vexs_visited[p->adjVex] = 1;
 s->Push(p);
 //指针 p 移向 此结点的第一个邻接结点
 p = this->vexs[p->adjVex].first;
 }
 //2.2.已访问过,移向下一个边结点 (横向遍历)
 else
 p = p->next;
 //3.若无邻接点,则返回上一结点层,并出栈边结点
 if (p == NULL)
 {
 p = s->Pop();
 }
 }
 //释放 栈
 delete s;
}

void GraphAdjList::Display_DFS(string *vertex)
{
 /*
 . 从指定顶点开始,深度优先 非递归 遍历
 */
 //1.判断顶点是否存在
 int index = _Locate(*vertex);
 if (index == -1)
 return;
 //2.初始化顶点访问数组
 for (int i = 0; i < this->_MAX_VERTEX_NUM; i++)
 {
 this->vexs_visited[i] = 0;
 }
 //3.深度优先遍历 递归
 cout << "深度优先遍历(非递归):(从顶点" << *vertex << "开始)" << endl;
 _DFS(index);
}

void GraphAdjList::Display_BFS(string *vertex)
{
 /*
 . 从指定顶点开始,广度优先遍历
 */
 //1.判断顶点是否存在
 int index = _Locate(*vertex);
 if (index == -1)
 return;
 //2.初始化顶点访问数组
 for (int i = 0; i < this->_MAX_VERTEX_NUM; i++)
 {
 this->vexs_visited[i] = 0;
 }
 //3.广度优先遍历
 cout << "广度优先遍历:(从顶点" << *vertex << "开始)" << endl;
 //3.1.初始化队列
 LinkQueue<int> * vexQ = new LinkQueue<int>();
 //3.2.访问开始顶点,并标记访问、入队
 cout << this->vexs[index].name << " ";
 this->vexs_visited[index] = 1;
 vexQ->EnQueue(new int(index));
 //3.3.出队,并遍历邻接顶点(下一层次),访问后入队
 ArcNode * p = NULL;
 int adjVex = 0;
 while (vexQ->GetHead() != NULL)
 {
 index = *vexQ->DeQueue();
 p = this->vexs[index].first;
 //遍历邻接顶点
 while (p != NULL)
 {
 adjVex = p->adjVex;
 //未访问过的邻接顶点
 if (this->vexs_visited[adjVex] != 1)
 {
 //访问顶点,并标记访问、入队
 cout << this->vexs[adjVex].name << " ";
 this->vexs_visited[adjVex] = 1;
 vexQ->EnQueue(new int(adjVex));
 }
 p = p->next;
 }
 }

 //4.释放队列
 int * e;
 while (vexQ->GetHead() != NULL)
 {
 e = vexQ->DeQueue();
 delete e;
 }
 delete vexQ;
}
//文件名:"GraphAdjList_Test.cpp"
#include "stdafx.h"
#include <iostream>
#include "GraphAdjList.h"
#include "ObjArrayList.h"
using namespace std;

int main()
{
 //初始化顶点数据
 string * v1 = new string("v1");
 string * v2 = new string("v2");
 string * v3 = new string("v3");
 string * v4 = new string("v4");
 string * v5 = new string("v5");
 string * v6 = new string("v6");
 string * v7 = new string("v7");
 ObjArrayList<string> * vexs = new ObjArrayList<string>();
 vexs->Add(v1);
 vexs->Add(v2);
 vexs->Add(v3);
 vexs->Add(v4);
 vexs->Add(v5);
 vexs->Add(v6);
 vexs->Add(v7);

 //初始化边(弧)数据
 GraphAdjList::ArcData * arc1 = new GraphAdjList::ArcData{ "v1", "v2", 2 };
 GraphAdjList::ArcData * arc2 = new GraphAdjList::ArcData{ "v1", "v3", 3 };
 GraphAdjList::ArcData * arc3 = new GraphAdjList::ArcData{ "v1", "v4", 4 };
 GraphAdjList::ArcData * arc4 = new GraphAdjList::ArcData{ "v3", "v1", 5 };
 GraphAdjList::ArcData * arc5 = new GraphAdjList::ArcData{ "v3", "v2", 6 };
 GraphAdjList::ArcData * arc6 = new GraphAdjList::ArcData{ "v3", "v5", 7 };
 GraphAdjList::ArcData * arc7 = new GraphAdjList::ArcData{ "v2", "v5", 8 };
 GraphAdjList::ArcData * arc8 = new GraphAdjList::ArcData{ "v4", "v6", 9 };
 GraphAdjList::ArcData * arc9 = new GraphAdjList::ArcData{ "v4", "v7", 9 };
 GraphAdjList::ArcData * arc10 = new GraphAdjList::ArcData{ "v6", "v7", 9 };
 ObjArrayList<GraphAdjList::ArcData> * arcsList = new ObjArrayList<GraphAdjList::ArcData>();
 arcsList->Add(arc1);
 arcsList->Add(arc2);
 arcsList->Add(arc3);
 arcsList->Add(arc4);
 arcsList->Add(arc5);
 arcsList->Add(arc6);
 arcsList->Add(arc7);
 arcsList->Add(arc8);
 arcsList->Add(arc9);
 arcsList->Add(arc10);

 //测试1:无向图
 cout << endl << "无向图初始化:" << endl;
 GraphAdjList * udg = new GraphAdjList(GraphAdjList::UDG);
 udg->Init(vexs, arcsList);
 udg->Display();
 //1.1.深度优先遍历
 cout << endl << "无向图深度优先遍历序列:(递归)" << endl;
 udg->Display_DFS_R(v1);
 cout << endl << "无向图深度优先遍历序列:(非递归)" << endl;
 udg->Display_DFS(v1);
 //1.2.广度优先遍历
 cout << endl << "无向图广度优先遍历序列:" << endl;
 udg->Display_BFS(v2);
 //1.3.插入新边
 cout << endl << "无向图新边:" << endl;
 udg->InsertArc(new GraphAdjList::ArcData{ "v7", "v1", 8 });
 udg->Display();
 //1.4.删除边
 cout << endl << "无向图删除边arc9:" << endl;
 udg->DeleteArc(arc9);
 udg->Display();

 //测试2:有向图
 cout << endl << "有向图:" << endl;
 GraphAdjList * dg = new GraphAdjList(GraphAdjList::DG);
 dg->Init(vexs, arcsList);
 dg->Display();
 //2.1.深度优先遍历
 cout << endl << "有向图深度优先遍历序列:(递归)" << endl;
 dg->Display_DFS_R(v1);
 cout << endl << "有向图深度优先遍历序列:(非递归)" << endl;
 dg->Display_DFS(v1);
 //2.2.广度优先遍历
 cout << endl << "有向图广度优先遍历序列:" << endl;
 dg->Display_BFS(v2);

 //测试:无向网
 cout << endl << "无向网:" << endl;
 GraphAdjList * udn = new GraphAdjList(GraphAdjList::UDN);
 udn->Init(vexs, arcsList);
 udn->Display();

 //测试:有向网
 cout << endl << "有向网:" << endl;
 GraphAdjList * dn = new GraphAdjList(GraphAdjList::DN);
 dn->Init(vexs, arcsList);
 dn->Display();

 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++实现图的邻接表存储和广度优先遍历实例分析

    本文实例讲述了C++实现图的邻接表存储和广度优先遍历方法.分享给大家供大家参考.具体如下: 示例:建立如图所示的无向图 由上图知,该图有5个顶点,分别为a,b,c,d,e,有6条边. 示例输入(按照这个格式输入): 5 6 abcde 0 1 0 2 0 3 2 3 2 4 1 4 输入结束(此行不必输入) 注:0 1表示该图的第0个顶点和第1个定点有边相连,如上图中的a->b所示       0 2表示该图的第0个顶点和第2个定点有边相连,如上图中的a->c所示       2 3表示该图的

  • C++实现邻接表顶点的删除

    本文实例为大家分享了C++实现邻接表顶点的删除代码,供大家参考,具体内容如下 这里的边是无向边 删除顶点v时,要找到顶点v的邻接顶点w,把w中指向v的边删除掉,再删除边(v,w).循环这个过程,直到把和顶点v有关的边都删除掉为止. 再接着需要删除顶点v. 不可以直接像数组那样直接把顶点v之后的顶点位置像前移动一位,因为这样其他顶点的位置将会发生变化,顶点边中的顶点位置将会出错. 边和顶点的定义如下: struct Edge{//边节点的定义 int dest;//边的另一顶点位置 E cost;

  • C++数据结构之实现邻接表

    本文实例为大家分享了C++数据结构之实现邻接表的具体代码,供大家参考,具体内容如下 一.图的邻接表实现 1.实现了以顶点顺序表.边链表为存储结构的邻接表: 2.实现了图的创建(有向/无向/图/网).边的增删操作.深度优先递归/非递归遍历.广度优先遍历的算法: 3.采用顶点对象列表.边(弧)对象列表的方式,对图的创建进行初始化:引用 "ObjArrayList.h"头文件,头文件可参看之前博文"数据结构之顺序列表(支持对象元素)"代码: 4.深度优先遍历分别采用递归/

  • C++实现有向图邻接表的构建

    本文实例为大家分享了C++实现有向图邻接表的构建代码,供大家参考,具体内容如下 数据结构里面的一道基础题,分享下自己的写法,验证可跑. #include<iostream> #include<string> const int MAX = 20; using namespace std; struct ArcNode { //弧结点 int adjvex = -1; //所指顶点位置 ArcNode *nextarc = nullptr; //下一条狐指针 size_t info

  • Java用邻接表存储图的示例代码

    目录 一.点睛 1.无向图 2.无向图的链接表 3.说明 4.无向图 二.邻接表的数据结构 1.节点 2.邻接点 三.算法步骤 四.实现 五.测试 一.点睛 邻接表是图的一种链式存储方法,其数据结构包括两部分:节点和邻接点. 用邻接表可以表示无向图,有向图和网.在此用无向图进行说明. 1.无向图 2.无向图的链接表 3.说明 节点 a 的邻接点是节点 b.d,其邻接点的存储下标为1.3,按照头插法(逆序)将其放入节点 a 后面的单链表中. 节点 b 的邻接点是节点 a.c.d,其邻接点的存储下标

  • 数据结构TypeScript之邻接表实现示例详解

    目录 图的结构特点 图的分类 图的表示 面向对象方法封装邻接表 构造函数 增加顶点和边 删除顶点和边 图的遍历 颜色标记 广度优先搜索(队列) 深度优先搜索(栈) 图的结构特点 图由顶点和顶点之间的边构成,记为G(V, E).其中V是顶点集合,E是边集合.作为一种非线性的数据结构,顶点之间存在多对多关系. 图的分类 无向图:两个顶点之间有两条互相关联的边.A和B之间为双向互通. 有向图:两个顶点之间有一条或两条关联的边.从A到B或者从B到A,只能单向通过. 带权无向图:在无向图的基础上增加一个权

  • 图的邻接表存储表示示例讲解

    复制代码 代码如下: //---------图的邻接表存储表示------- #include<stdio.h>#include<stdlib.h> #define MAX_VERTEXT_NUM 20 typedef int InfoType;typedef char VertextType; typedef struct ArcNode{    int adjvex;    struct ArcNode *nextArc;    InfoType *info;}ArcNode;

  • 邻接表无向图的Java语言实现完整源码

    邻接表无向图的介绍 邻接表无向图是指通过邻接表表示的无向图. 上面的图G1包含了"A,B,C,D,E,F,G"共7个顶点,而且包含了"(A,C),(A,D),(A,F),(B,C),(C,D),(E,G),(F,G)"共7条边. 上图右边的矩阵是G1在内存中的邻接表示意图.每一个顶点都包含一条链表,该链表记录了"该顶点的邻接点的序号".例如,第2个顶点(顶点C)包含的链表所包含的节点的数据分别是"0,1,3":而这"

  • java实现图的邻接表存储结构的两种方式及实例应用详解

    前言 本篇来谈一谈图的邻接表实现的两种方式,首先我们明确一点"学会图的邻接表实现的关键点在于":你所建立的图的邻接表的对象是什么! 首先我们看一下<算法导论>中关于图的邻接表的定义: 图G=(V,E)的邻接表表示有一个包含 |V| 个列表的数组Adj所组成,其中每个列表对应于V中的一个顶点,对于每一个u∈V,邻接表Adj[u]包含所有满足条件(u,v)∈E的顶点v,亦即,Adj[u]包含图G中所有和顶点u相邻的顶点.(或者他也可能指向这些顶点的指针),每个邻接表中的顶点一般

  • Mysql通过Adjacency List(邻接表)存储树形结构

    以下内容给大家介绍了MYSQL通过Adjacency List (邻接表)来存储树形结构的过程介绍和解决办法,并把存储后的图例做了分析. 今天来看看一个比较头疼的问题,如何在数据库中存储树形结构呢? 像mysql这样的关系型数据库,比较适合存储一些类似表格的扁平化数据,但是遇到像树形结构这样有深度的人,就很难驾驭了. 举个栗子:现在有一个要存储一下公司的人员结构,大致层次结构如下: (画个图真不容易..) 那么怎么存储这个结构?并且要获取以下信息: 1.查询小天的直接上司. 2.查询老宋管理下的

  • C++实现有向图的邻接表表示

    本文实例为大家分享了C++有向图的邻接表表示,供大家参考,具体内容如下 一.思路: 有向图的插入有向边.删除边.删除顶点和无向图的有区别.其他的和无向图的类似. 1.插入有向边<e1, e2> 只需要插入<e1, e2>边就行,不需要插入对称边<e2, e1> 2.删除边<e1,e2>: 只需要删除<e1, e2>边就行,不需要仔找对称边<e2, e1>进行删除. 3.删除顶点v: 首先,要在邻接表中删除以v为头的边<v, w&

随机推荐