图的详细介绍在上一篇大佬的链接处:
1.结构
实现一个领接表的图,设计的结构如下,照着这个结构,想要设计成什么样,自己改一改就行了。
#define MAXVEX 100 //图中顶点数目的最大值
type char VertexType; //顶点类型应由用户定义
typedef int EdgeType; //边上的权值类型应由用户定义
/*边表结点*/
typedef struct EdgeNode{
int adjvex; //该弧所指向的顶点的下标或者位置
EdgeType weight; //权值,对于非网图可以不需要
struct EdgeNode *next; //指向下一个邻接点
}EdgeNode;
/*顶点表结点*/
typedef struct VertexNode{
Vertex data; //顶点域,存储顶点信息
EdgeNode *firstedge //边表头指针
}VertexNode, AdjList[MAXVEX];
/*邻接表*/
typedef struct{
AdjList adjList;
int numVertexes, numEdges; //图中当前顶点数和边数
}
2.实现
2.1.变量
变量名称 | 类型 | 属性 | 说明 |
---|---|---|---|
m_vertexList | _VertexPtr | 私有 | 点的集合 |
m_vertexCount | size_t | 私有 | 点的数量 |
m_edgeCount | size_t | 私有 | 边的数量 |
2.2.方法
方法名 | 返回类型 | 参数 | 属性 | 说明 |
---|---|---|---|---|
AdjacencyListGraph() | - | size_t vertexCount | 公有 | 传值构造 |
AdjacencyListGraph() | - | const AdjacencyListGraph& ALG | 公有 | 拷贝构造 |
~AdjacencyListGraph() | - | - | 公有 | 析构函数 |
operator = () | AdjacencyListGraph& | const AdjacencyListGraph& ALG | 公有 | =重载 |
vertexCount() const | size_t | - | 公有 | 返回点数 |
edgeCount() const | size_t | - | 公有 | 返回边数 |
setVertexName() | bool | int vertexIndex, _VertexType vertexName | 公有 | 设置点的名称 |
addVertex() | bool | _VertexType vertexName | 公有 | 添加一个点 |
removeVertex() | bool | _VertexType vertexName | 公有 | 删除一个点 |
setEdgeValue() | bool | _VertexType firstVertexName, _VertexType secondeVertexName, _EdgeType value | 公有 | 更改边的数据 |
addEdge() | bool | _VertexType firstVertexName, _VertexType secondeVertexName, _EdgeType value | 公有 | 添加一条边 |
removeEdge() | bool | _VertexType firstVertexName, _VertexType secondeVertexName | 公有 | 删除一条边 |
DFS() | void | - | 公有 | 深度优先搜索(一半,外部可访问) |
BFS() | void | - | 公有 | 广度优先搜索 |
init() | void | size_t vertexCount | 初始化 | 保护 |
clear() | void | - | 保护 | 清楚(释放) |
copy() | void | const AdjacencyListGraph& ALG | 保护 | 复制数据 |
DFS() | void | _VertexPtr vertexList, int currVertexIndex, bool* visited | 保护 | 深度优先搜索(一半,外部不可访问) |
3.测试
3.1.测试代码
#include <iostream>
#include "adjacencylistgraph.h"
int main()
{
AdjacencyListGraph<int, char> graph(8);
for (int i = 0; i < graph.vertexCount(); i++)
{
graph.setVertexName(i, 'a' + i);
}
std::cout << "构造一个有8个点的图,点的名称为:abcdefgh" << std::endl;
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
std::cout << "添加7条边:" << std::endl;
graph.addEdge('a', 'b', 1);
graph.addEdge('a', 'c', 1);
graph.addEdge('b', 'd', 1);
graph.addEdge('b', 'e', 1);
graph.addEdge('e', 'h', 1);
graph.addEdge('c', 'f', 1);
graph.addEdge('c', 'g', 1);
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
std::cout << "边数:" << graph.edgeCount() << std::endl;
std::cout << "点数:" << graph.vertexCount() << std::endl;
std::cout << "添加一个s点:" << std::endl;
graph.addVertex('s');
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
std::cout << "添加两条边:as, ds" << std::endl;
graph.addEdge('a', 's', 1);
graph.addEdge('d', 's', 1);
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
std::cout << "删除一条边:cf" << std::endl;
graph.removeEdge('c', 'f');
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
std::cout << "删除点f:" << std::endl;
graph.removeVertex('f');
std::cout << "深度优先搜索:" << std::endl;
graph.DFS();
std::cout << std::endl;
std::cout << "广度优先搜索:" << std::endl;
graph.BFS();
std::cout << std::endl;
return 0;
}
3.2.输出结果
构造一个有8个点的图,点的名称为:abcdefgh
深度优先搜索:
a, b, c, d, e, f, g, h,
广度优先搜索:
a, b, c, d, e, f, g, h,
添加7条边:
深度优先搜索:
a, b, d, e, h, c, f, g,
广度优先搜索:
a, b, c, d, e, f, g, h,
边数:7
点数:8
添加一个s点:
深度优先搜索:
a, b, d, e, h, c, f, g, s,
广度优先搜索:
a, b, c, d, e, f, g, h, s,
添加两条边:as, ds
深度优先搜索:
a, b, d, s, e, h, c, f, g,
广度优先搜索:
a, b, c, s, d, e, f, g, h,
删除一条边:cf
深度优先搜索:
a, b, d, s, e, h, c, g, f,
广度优先搜索:
a, b, c, s, d, e, g, h, f,
删除点f:
深度优先搜索:
a, b, d, e, s, c, h, g,
广度优先搜索:
a, b, c, d, e, h, s, g,
4.实现代码
#pragma once
#ifndef _ADJACENCYLISTGRAPH_H_
#define _ADJACENCYLISTGRAPH_H_
#include <iostream>
#include <queue>
template <typename _EdgeType>
struct Edge
{
_EdgeType m_value;
int m_adjacency;
Edge* m_next;
Edge() : m_value(_EdgeType()), m_adjacency(-1), m_next(nullptr) {}
Edge(_EdgeType value) : m_value(value), m_adjacency(-1), m_next(nullptr) {}
Edge(_EdgeType value, Edge* next) : m_value(value), m_adjacency(-1), m_next(next) {}
Edge(_EdgeType value, int adjacency) : m_value(value), m_adjacency(adjacency), m_next(nullptr) {}
Edge(_EdgeType value, int adjacency, Edge* next) : m_value(value), m_adjacency(adjacency), m_next(next) {}
};
template <typename _EdgeType, typename _VertexType>
struct Vertex
{
_VertexType m_name;
Edge<_EdgeType>* m_firstEdge;
Vertex() : m_name(_VertexType()), m_firstEdge(nullptr) {}
Vertex(_VertexType name) : m_name(name), m_firstEdge(nullptr) {}
Vertex(_VertexType name, Edge<_EdgeType>* firstEdge) : m_name(name), m_firstEdge(firstEdge) {}
};
template <typename _EdgeType, typename _VertexType>
class AdjacencyListGraph
{
using _VertexPtr = Vertex<_EdgeType, _VertexType>*;
using _EdgePtr = Edge<_EdgeType>*;
public:
AdjacencyListGraph(size_t vertexCount)
{
init(vertexCount);
}
AdjacencyListGraph(const AdjacencyListGraph& ALG)
{
init(ALG.m_vertexCount);
copy(ALG);
}
~AdjacencyListGraph()
{
clear();
}
AdjacencyListGraph& operator = (const AdjacencyListGraph& ALG)
{
clear();
init(ALG.m_vertexCount);
copy(ALG);
return *this;
}
size_t vertexCount() const
{
return m_vertexCount;
}
size_t edgeCount() const
{
return m_edgeCount;
}
bool setVertexName(int vertexIndex, _VertexType vertexName)
{
if (vertexIndex < 0 || vertexIndex >= m_vertexCount)
{
return false;
}
int index = 0;
while (index < m_vertexCount)
{
if (m_vertexList[index].m_name == vertexName)
{
return false;
}
index++;
}
m_vertexList[vertexIndex].m_name = vertexName;
return true;
}
bool addVertex(_VertexType vertexName)
{
for (int i = 0; i < m_vertexCount; i++)
{
if (m_vertexList[i].m_name == vertexName)
{
return false;
}
}
_VertexPtr vertexList = new Vertex<_EdgeType, _VertexType>[m_vertexCount + 1];
for (int i = 0; i < m_vertexCount; i++)
{
vertexList[i] = m_vertexList[i];
}
vertexList[m_vertexCount].m_name = vertexName;
delete[]m_vertexList;
m_vertexList = vertexList;
m_vertexCount++;
return true;
}
bool removeVertex(_VertexType vertexName)
{
int rmIndex = 0;
for (; rmIndex < m_vertexCount; rmIndex++)
{
if (m_vertexList[rmIndex].m_name == vertexName)
{
break;
}
}
if (rmIndex == m_vertexCount)
{
return false;
}
_VertexPtr vertexList = new Vertex<_EdgeType, _VertexType>[m_vertexCount - 1];
for (int i = 0; i < m_vertexCount - 1; i++)
{
if (i < rmIndex)
{
vertexList[i] = m_vertexList[i];
}
else
{
vertexList[i] = m_vertexList[i + 1];
}
}
delete[]m_vertexList;
m_vertexList = vertexList;
m_vertexCount--;
for (int index = 0; index < m_vertexCount; index++)
{
if (m_vertexList[index].m_firstEdge == nullptr)
{
continue;
}
else if (m_vertexList[index].m_firstEdge->m_next == nullptr)
{
if (m_vertexList[index].m_firstEdge->m_adjacency == rmIndex)
{
delete m_vertexList[index].m_firstEdge;
m_vertexList[index].m_firstEdge = nullptr;
}
else
{
continue;
}
}
else
{
_EdgePtr preEdge = m_vertexList[index].m_firstEdge;
_EdgePtr currEdge = preEdge->m_next;
if (preEdge->m_adjacency == rmIndex)
{
m_vertexList[index].m_firstEdge = currEdge;
delete preEdge;
preEdge = nullptr;
}
else
{
while (currEdge)
{
if (currEdge->m_adjacency == rmIndex)
{
preEdge->m_next = currEdge->m_next;
delete currEdge;
currEdge = nullptr;
break;
}
preEdge = currEdge;
currEdge = currEdge->m_next;
}
}
}
}
return true;
}
bool setEdgeValue(_VertexType firstVertexName, _VertexType secondeVertexName, _EdgeType value)
{
//
int firstVertexIndex = -1;
int secondeVertexIndex = -1;
for (int index = 0; index < m_vertexCount; index++)
{
if (m_vertexList[index].m_name == firstVertexName)
{
firstVertexIndex = index;
}
if (m_vertexList[index].m_name == secondeVertexName)
{
secondeVertexIndex = index;
}
}
if (firstVertexIndex == -1 || secondeVertexIndex == -1 || firstVertexIndex == secondeVertexIndex)
{
return false;
}
//
if (m_vertexList[firstVertexIndex].m_firstEdge == nullptr)
{
return false;
}
else
{
_EdgePtr firstEdge = m_vertexList[firstVertexIndex].m_firstEdge;
while (firstEdge)
{
if (firstEdge->m_adjacency == secondeVertexIndex)
{
firstEdge->m_value = value;
break;
}
firstEdge = firstEdge->m_next;
}
if (firstEdge == nullptr)
{
return false;
}
}
//
if (m_vertexList[secondeVertexIndex].m_firstEdge == nullptr)
{
return false;
}
else
{
_EdgePtr firstEdge = m_vertexList[secondeVertexIndex].m_firstEdge;
while (firstEdge)
{
if (firstEdge->m_adjacency == firstVertexIndex)
{
firstEdge->m_value = value;
break;
}
firstEdge = firstEdge->m_next;
}
if (firstEdge == nullptr)
{
return false;
}
}
return true;
}
bool addEdge(_VertexType firstVertexName, _VertexType secondeVertexName, _EdgeType value)
{
//
int firstVertexIndex = -1;
int secondeVertexIndex = -1;
for (int index = 0; index < m_vertexCount; index++)
{
if (m_vertexList[index].m_name == firstVertexName)
{
firstVertexIndex = index;
}
if (m_vertexList[index].m_name == secondeVertexName)
{
secondeVertexIndex = index;
}
}
if (firstVertexIndex == -1 || secondeVertexIndex == -1 || firstVertexIndex == secondeVertexIndex)
{
return false;
}
//
if (m_vertexList[firstVertexIndex].m_firstEdge == nullptr)
{
m_vertexList[firstVertexIndex].m_firstEdge = new Edge<_EdgeType>(value, secondeVertexIndex);
}
else
{
_EdgePtr firstEdge = m_vertexList[firstVertexIndex].m_firstEdge;
while (firstEdge->m_next)
{
if (firstEdge->m_adjacency == secondeVertexIndex)
{
return false;
}
firstEdge = firstEdge->m_next;
}
if (firstEdge->m_adjacency == secondeVertexIndex)
{
return false;
}
firstEdge->m_next = new Edge<_EdgeType>(value, secondeVertexIndex);
}
//
if (m_vertexList[secondeVertexIndex].m_firstEdge == nullptr)
{
m_vertexList[secondeVertexIndex].m_firstEdge = new Edge<_EdgeType>(value, firstVertexIndex);
}
else
{
_EdgePtr firstEdge = m_vertexList[secondeVertexIndex].m_firstEdge;
while (firstEdge->m_next)
{
firstEdge = firstEdge->m_next;
}
firstEdge->m_next = new Edge<_EdgeType>(value, firstVertexIndex);
}
m_edgeCount++;
return true;
}
bool removeEdge(_VertexType firstVertexName, _VertexType secondeVertexName)
{
//找到需要删除的点的下标
int firstVertexIndex = -1;
int secondeVertexIndex = -1;
for (int index = 0; index < m_vertexCount; index++)
{
if (m_vertexList[index].m_name == firstVertexName)
{
firstVertexIndex = index;
}
if (m_vertexList[index].m_name == secondeVertexName)
{
secondeVertexIndex = index;
}
}
if (firstVertexIndex == -1 || secondeVertexIndex == -1 || firstVertexIndex == secondeVertexIndex)
{
return false;
}
//
if (m_vertexList[firstVertexIndex].m_firstEdge == nullptr)
{
return false;
}
else if (m_vertexList[firstVertexIndex].m_firstEdge->m_next == nullptr)
{
if (m_vertexList[firstVertexIndex].m_firstEdge->m_adjacency == secondeVertexIndex)
{
delete m_vertexList[firstVertexIndex].m_firstEdge;
m_vertexList[firstVertexIndex].m_firstEdge = nullptr;
}
else
{
return false;
}
}
else
{
_EdgePtr preEdge = m_vertexList[firstVertexIndex].m_firstEdge;
_EdgePtr currEdge = preEdge->m_next;
if (preEdge->m_adjacency == secondeVertexIndex)
{
m_vertexList[firstVertexIndex].m_firstEdge = currEdge;
delete preEdge;
preEdge = nullptr;
}
else
{
while (currEdge)
{
if (currEdge->m_adjacency == secondeVertexIndex)
{
preEdge->m_next = currEdge->m_next;
delete currEdge;
currEdge = nullptr;
break;
}
preEdge = currEdge;
currEdge = currEdge->m_next;
}
}
}
//
if (m_vertexList[secondeVertexIndex].m_firstEdge == nullptr)
{
return false;
}
else if (m_vertexList[secondeVertexIndex].m_firstEdge->m_next == nullptr)
{
if (m_vertexList[secondeVertexIndex].m_firstEdge->m_adjacency == secondeVertexIndex)
{
delete m_vertexList[secondeVertexIndex].m_firstEdge;
m_vertexList[secondeVertexIndex].m_firstEdge = nullptr;
}
else
{
return false;
}
}
else
{
_EdgePtr preEdge = m_vertexList[secondeVertexIndex].m_firstEdge;
_EdgePtr currEdge = preEdge->m_next;
if (preEdge->m_adjacency == firstVertexIndex)
{
m_vertexList[secondeVertexIndex].m_firstEdge = currEdge;
delete preEdge;
preEdge = nullptr;
}
else
{
while (currEdge)
{
if (currEdge->m_adjacency == firstVertexIndex)
{
preEdge->m_next = currEdge->m_next;
delete currEdge;
currEdge = nullptr;
break;
}
preEdge = currEdge;
currEdge = currEdge->m_next;
}
}
}
m_edgeCount--;
return true;
}
void DFS()
{
if (m_vertexCount == 0)
{
return;
}
bool* visited = new bool[m_vertexCount];
for (int i = 0; i < m_vertexCount; i++)
{
visited[i] = false;
}
for (int i = 0; i < m_vertexCount; i++)
{
if (!visited[i])
{
DFS(m_vertexList, i, visited);
}
}
delete[] visited;
visited = nullptr;
}
void BFS()
{
if (m_vertexCount <= 0)
{
return;
}
bool* visited = new bool[m_vertexCount];
for (int i = 0; i < m_vertexCount; i++)
{
visited[i] = false;
}
std::queue<int> vertexIndexQueue;
for (int currIndex = 0; currIndex < m_vertexCount; currIndex++)
{
if (!visited[currIndex])
{
visited[currIndex] = true;
std::cout << m_vertexList[currIndex].m_name << ", ";
vertexIndexQueue.push(currIndex);
while (!vertexIndexQueue.empty())
{
int vertexIndex = vertexIndexQueue.front();
vertexIndexQueue.pop();
_EdgePtr edge = m_vertexList[vertexIndex].m_firstEdge;
while (edge)
{
if (!visited[edge->m_adjacency])
{
visited[edge->m_adjacency] = true;
std::cout << m_vertexList[edge->m_adjacency].m_name << ", ";
vertexIndexQueue.push(edge->m_adjacency);
}
edge = edge->m_next;
}
}
}
}
}
protected:
void init(size_t vertexCount)
{
m_vertexCount = vertexCount;
m_edgeCount = 0;
if (m_vertexCount == 0)
{
m_vertexList = nullptr;
}
else
{
m_vertexList = new Vertex<_EdgeType, _VertexType>[m_vertexCount];
}
}
void clear()
{
if (m_vertexList == nullptr)
{
return;
}
int index = 0;
while (index < m_vertexCount)
{
_EdgePtr currEdge = m_vertexList[index].m_firstEdge;
while (currEdge != nullptr)
{
_EdgePtr edge = currEdge;
currEdge = currEdge->m_next;
delete edge;
edge = nullptr;
}
index++;
}
delete[]m_vertexList;
m_vertexList = nullptr;
m_vertexCount = 0;
}
void copy(const AdjacencyListGraph& ALG)
{
int index = 0;
while (index < m_vertexCount)
{
_EdgePtr& myCurrEdge = m_vertexList[index].m_firstEdge;
_EdgePtr ALGCurrEdge = ALG.m_vertexList[index].m_firstEdge;
while (ALGCurrEdge != nullptr)
{
myCurrEdge = new Edge<_EdgeType>(ALGCurrEdge->m_value);
myCurrEdge = myCurrEdge->m_next;
ALGCurrEdge = ALGCurrEdge->m_next;
}
m_vertexList[index].m_name = ALG.m_vertexList[index].m_name;
index++;
}
m_edgeCount = ALG.m_edgeCount;
}
void DFS(_VertexPtr vertexList, int currVertexIndex, bool* visited)
{
std::cout << vertexList[currVertexIndex].m_name << ", ";
visited[currVertexIndex] = true;
_EdgePtr firstEdge = vertexList[currVertexIndex].m_firstEdge;
while (firstEdge)
{
if (!visited[firstEdge->m_adjacency])
{
DFS(vertexList, firstEdge->m_adjacency, visited);
}
firstEdge = firstEdge->m_next;
}
}
private:
_VertexPtr m_vertexList;
size_t m_vertexCount;
size_t m_edgeCount;
};
#endif // !_ADJACENCYLISTGRAPH_H_
5.总结
实现得不是很好,代码耦合度高。领接表和领接矩阵相比,感觉还是实现起来麻烦,指针确实是很麻烦得东西,但是又方便灵活。