邓俊辉的数据结构,学习笔记,老师讲课真的真的好,好多地方还要细细打磨。
先把所有的代码贴出来
Vertex.h
using VStatus=enum{UNDISCOVERED,DISCOVERED,VISITED};//顶点状态
using EType=enum {UNDETERMINED,TREE,CROSS,FORWARD,BACKWAED};//边在遍历树中所属的类型
#define INT_MAX 2147483647
#define Rank int
template<typename Tv>
struct Vertex {
Tv data;
int inDegree;//入度
int outDegree;//出度
VStatus status;//状态
int fTime; int dTime;
Rank parent; int priority;
Vertex(Tv const& d = (Tv)0) :
data(d), inDegree(0), outDegree(0), status(UNDISCOVERED),
dTime(-1), fTime(-1), parent(-1), priority(INT_MAX) {};
};
template<typename Te>
struct Edge
{
Te data; int weight; EType type;//数据,权重,类型
Edge(Te const&d,int w):data(d),weight(w),type(UNDETERMINED){}//构造
};
Graph.h
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<iostream>
#include"Vertex.h"
using namespace std;
template<typename Tv,typename Te>
class GraphMatrix {
private:
vector<Vertex<Tv>> V;//顶点集
vector<vector<Edge<Te>*>> E;//边集,邻接矩阵
void reset();
public:
GraphMatrix() { n = 0; e = 0; }
~GraphMatrix() {
for (Rank v = 0; v < n; v++) {
for (Rank u = 0; u < n; u++)
delete E[v][u];
}
}
int n; //顶点总数
int e; //边总数
//顶点的基本操作
Tv& vertex(Rank v) { return V[v].data; }//数据
int inDegree(Rank v) { return V[v].inDegree; }//入度
int outDegree(Rank v) { return V[v].outDegree; }//出度
Rank firstNbr(Rank v) { return nextNbr(v, n); }//首个邻接顶点
Rank nextNbr(Rank v, Rank u) {
while ((-1 < u) && (!exists(v, --u)));
return u;
}
VStatus& status(Rank v) { return V[v].status; }//状态
int& dTime(Rank v) { return V[v].dTime; }
int& fTime(Rank v) { return V[v].fTime; }
Rank& parent(Rank v) { return V[v].parent; }//在遍历树中的父亲
int& priority(Rank v) {return V[v].priority;}
//顶点动态操作
Rank insert(Tv const& vertex);
Tv remove(Rank v);
//边确认操作,看边是否存在
bool exists(Rank v, Rank u) //边(v, u)是否存在
{ return (-1 < v) && (v < n)&&(-1<u) && (u < n) && E[v][u] != nullptr; }
//边的基本操作
EType& type(Rank v, Rank u) { return E[v][u]->type; }
Te& edge(Rank v, Rank u) { return E[v][u]->data; }
int& weight(Rank v, Rank u) { return E[v][u]->weight; }
//边动态操作
void insert(Te const& edge, int w, Rank v, Rank u) {
if (E[v][u] != nullptr) return;
E[v][u] = new Edge<Te>(edge, w);
e++; V[v].outDegree++; V[u].inDegree++;
}
Te remove(Rank v, Rank u);
//遍历
void BFS(int v, int& clock);//广度优先搜索
void bfs(int s);//多连通
void DFS(int v, int& clock);//深度优先搜索
void dfs(int s);//多连通
//最短路径Dijkstra算法
void dijkstra(Rank s);
//最小生成树prim算法
void prim(Rank s);
//展示信息
void getInfo();
};
template<typename Tv, typename Te>
Tv GraphMatrix<Tv, Te>::remove(Rank v) {
for (Rank u = 0; u < n; u++) {//删除所有出边,以V[u]为起点
if (exists(v, u))
{
delete E[v][u];
V[u].inDegree--;
e--;
}
}
E.erase(E.begin() + v); n--;//删除第n行
Tv vBak = vertex(v); V.erase(V.begin() + v);
for (Rank u = 0; u < n; u++) {//删除第n列
Edge<Te>* x = E[u][v];
E[u].erase(E[u].begin() + v);
if (x != nullptr) {
delete x;
V[u].outDegree--;
e--;
}
}
return vBak;
};
template<typename Tv, typename Te>
Rank GraphMatrix<Tv, Te>::insert(Tv const& vertex)
{
//插入顶点,返回编号
for (Rank u = 0; u < n; u++) {
E[u].insert(E[u].end(), nullptr);
}
n++;
E.insert(E.end(), vector<Edge<Te>*>(n, (Edge<Te>*)nullptr));
V.insert(V.end(), Vertex<Tv>(vertex));
return V.size();
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::getInfo() {
// 用于输出各边的状态
map<int, string> vStatus;
vStatus[UNDISCOVERED] = "UNDISCOVERED";
vStatus[DISCOVERED] = "DISCOVERED";
vStatus[VISITED] = "VISITED";
map<int, string> eType;
eType[UNDETERMINED] = "UNDETERMINED";
eType[TREE] = "TREE";
eType[CROSS] = "CROSS";
eType[FORWARD] = "FORWARD";
eType[BACKWAED] = "BACKWARD";
cout << "一共有" << n << "个顶点," << e << "条边";
cout << endl<<"点信息:" << endl;
for (int i = 0; i < V.size(); i++) {
cout << "数据:" << V[i].data << " " << " 入度:" << V[i].inDegree
<< "出度:" << V[i].outDegree << endl;
cout<<"dTime:"<<dTime(i)<<" fTime:"<<fTime(i) << " 父节点:"<<parent(i) << " 状态:" << vStatus[status(i)] <<" 距离:"<<priority(i) << endl;
}
cout << endl << "边信息:" << endl;
for (int v = 0; v < n; v++) {
for (int u = 0; u < n; u++) {
if (E[v][u] != nullptr) {
cout << "起点:" << v << " 终点:" << u << " 类型:" << eType[type(v, u)] << endl;
}
}
}
for (int v = 0; v < n; v++) {
for (int u = 0; u < n; u++) {
if (E[v][u] != nullptr)
cout << E[v][u]->data << " ";
else
cout << 0 << " ";
}
cout << endl;
}
cout << endl;
};
template<typename Tv, typename Te>
Te GraphMatrix<Tv, Te>::remove(Rank v, Rank u) {
//删除顶点v和u之间的联边
Te eBak = edge(v, u);
delete E[v][u]; E[v][u] = nullptr;
e--; V[v].outDegree--; V[u].inDegree--;
return eBak;
}
template<typename Tv,typename Te>
void GraphMatrix<Tv, Te>::BFS(int v, int& clock) {
queue<Rank> Q;//存的是未遍历节点的编号
status(v) = DISCOVERED;
Q.push(v);
dTime(v) = clock; clock = 0;
while (!Q.empty()) {
Rank v = Q.front();
Q.pop();
for (Rank u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {
//遍历所有的邻居
if (UNDISCOVERED == status(u)) {
status(u) = DISCOVERED;
Q.push(u); dTime(u) = dTime(v) + 1;//发现该节点
type(v, u) = TREE; parent(u) = v;
}
else
type(v, u) = CROSS;
status(v) = VISITED;
fTime(v) = clock++;
if (Q.empty())
clock = dTime(v) + 1;
else if (dTime(v) < dTime(Q.front()))
clock = 0;
}
}
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::bfs(int s) {
reset(); int clock = 0; int v = s;
do
if (UNDISCOVERED == status(v))
BFS(v, clock);
while (s != (v = (++v % n)));
};
template<typename Tv,typename Te>
void GraphMatrix<Tv, Te>::reset() {
//所有的顶点、边的辅助信息复位
for (Rank v = 0; v < n; v++) {
//点信息复位
status(v) = UNDISCOVERED;
dTime(v) = -1; fTime(v) = -1;
parent(v) = -1; priority(v) = INT_MAX;
//边信息
for (Rank u = 0; u < n; u++)
if (exists(v, u))
type(v, u) = UNDETERMINED;
}
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::DFS(int v, int& clock) {
dTime(v) = ++clock; status(v) = DISCOVERED;
for (int u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {
switch (status(u))
{
case UNDISCOVERED:
type(v, u) = TREE; parent(u) = v; DFS(u, clock); break;
case DISCOVERED:
type(v, u) = BACKWAED; break;
default:
type(v, u) = (dTime(v) < dTime(u) ? FORWARD : CROSS);
break;
}
}
status(v) = VISITED; fTime(v) = ++clock;
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::dfs(int s) {
reset(); int clock = 0; int v = s;
do
if (UNDISCOVERED == status(v))
DFS(v, clock);
while (s != (v = (++v % n)));
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::dijkstra(Rank s) {
reset(); priority(s) = 0;
for (int i = 0; i < n; i++) {
status(s) = VISITED;
if (-1 < parent(s)) type(parent(s), s) = TREE;
for (Rank j = firstNbr(s); -1 < j; j = nextNbr(s, j)) {
//在所有s邻居里找最短的路径
if (status(j) == UNDISCOVERED && priority(j) > priority(s) + weight(s, j))
{
priority(j) = priority(s) + weight(s, j);
parent(j) = s;
}
}
//找出最短的路径,也适用于所有的找最小值
for (int shortest = INT_MAX, j = 0; j < n; j++) {
if (status(j) == UNDISCOVERED && shortest > priority(j)) {
shortest = priority(j); s = j;
}
}
}
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::prim(Rank s) {
reset(); priority(s) = 0;
for (int i = 0; i < n; i++) {
status(s) = VISITED;
if (-1 < parent(s)) type(parent(s), s) = TREE;
for (Rank j = firstNbr(s); -1 < j; j = nextNbr(s, j)) {
//在所有s邻居里找最短的路径,到自己的最短路径,不一样的地方
if (status(j) == UNDISCOVERED && priority(j) > weight(s, j))
{
priority(j) = weight(s, j);
parent(j) = s;
}
}
//找出最短的路径,也适用于所有的找最小值
for (int shortest = INT_MAX, j = 0; j < n; j++) {
if (status(j) == UNDISCOVERED && shortest > priority(j)) {
shortest = priority(j); s = j;
}
}
}
};
两个测试用例
void test() {
//BFS DFS测试用例
GraphMatrix<int, int> graph;
for (int i = 0; i < 10; i++) {
graph.insert(i);
}
for (int i = 1; i < 4; i++) {
graph.insert(1, 0, 0, i);
graph.insert(1, 0, i, 0);
}
int startPoint = 4;
for (int i = 1; i < 4; i++) {
for (int j = 0; j < 2; j++) {
graph.insert(1, 0, startPoint, i);
graph.insert(1, 0, i, startPoint);
startPoint++;
}
graph.insert(1, 0, startPoint - 2, startPoint - 1);
graph.insert(1, 0, startPoint - 1, startPoint - 2);
}
int a = 0;
graph.getInfo();
graph.dfs(0);
graph.getInfo();
}
void test_di() {
//迪杰斯特拉算法测试
GraphMatrix<int, int> graph;
for (int i = 0; i < 6; i++) {
graph.insert(i);
}
vector<vector<int>> a({ {0,1,12},{0,3,1},
{1,2,5},{1,3,9}, {1,4,4},
{3,4,3},
{2,4,13 },{2,5,15},
{4,5,14} });
for (int i = 0; i < a.size(); i++) {
int j = a[i][0], k = a[i][1];
int w = a[i][2];
graph.insert(1, w, j, k);
graph.insert(1, w, k, j);
}
graph.dijkstra(0);
graph.getInfo();
}
图的实现
与老师给的代码不一样的地方是,我用的是c++模板库里的vector,用自己写的Vector析构的时候会出现空指针,不知道问题在哪。
出现了一个很愚蠢的bug,一直找不着顶点集E,结果是没加using namespace std; 原来模板库要用这个,受教了。废话不多说,贴上代码。
顶点和边的实现
Vstataus是顶点状态,undiscovered未访问顶点,discovered访问过该顶点,但他的所有邻居还没访问完,在递归中,正在访问,visited访问完了,包括他的所有邻居。
EType是边的状态,undetermined是未访问边,tree是该边是树的组成部分,bfs, dfs构成的搜索树,cross是这个边的两个点没有亲缘关系,谁也不是谁的父亲或曾曾父亲,forward是起始点是父亲,终点是孩子,backward起始点是孩子,终点是父亲。
比较重要的是知道这几个enum类型是啥意思。
using VStatus=enum{UNDISCOVERED,DISCOVERED,VISITED};//顶点状态
using EType=enum {UNDETERMINED,TREE,CROSS,FORWARD,BACKWAED};//边在遍历树中所属的类型
#define INT_MAX 2147483647
#define Rank int
template<typename Tv>
struct Vertex {
Tv data;
int inDegree;//入度
int outDegree;//出度
VStatus status;//状态
int fTime; int dTime;//时间标签,dTime是开始访问的节点,fTime是结束访问的节点
Rank parent; int priority;
Vertex(Tv const& d = (Tv)0) :
data(d), inDegree(0), outDegree(0), status(UNDISCOVERED),
dTime(-1), fTime(-1), parent(-1), priority(INT_MAX) {};
};
template<typename Te>
struct Edge
{
Te data; int weight; EType type;//数据,权重,类型
Edge(Te const&d,int w):data(d),weight(w),type(UNDETERMINED){}//构造
};
图实现
接下来是图的操作,先把所有的方法贴上来,实现在后面。
template<typename Tv,typename Te>
class GraphMatrix {
private:
vector<Vertex<Tv>> V;//顶点集
vector<vector<Edge<Te>*>> E;//边集,邻接矩阵
void reset();
public:
GraphMatrix() { n = 0; e = 0; }
~GraphMatrix() {
for (Rank v = 0; v < n; v++) {
for (Rank u = 0; u < n; u++)
delete E[v][u];
}
}
int n; //顶点总数
int e; //边总数
//顶点的基本操作
Tv& vertex(Rank v) { return V[v].data; }//数据
int inDegree(Rank v) { return V[v].inDegree; }//入度
int outDegree(Rank v) { return V[v].outDegree; }//出度
Rank firstNbr(Rank v) { return nextNbr(v, n); }//首个邻接顶点
Rank nextNbr(Rank v, Rank u) {
while ((-1 < u) && (!exists(v, --u)));
return u;
}
VStatus& status(Rank v) { return V[v].status; }//状态
int& dTime(Rank v) { return V[v].dTime; }
int& fTime(Rank v) { return V[v].fTime; }
Rank& parent(Rank v) { return V[v].parent; }//在遍历树中的父亲
int& priority(Rank v) {return V[v].priority;}
//顶点动态操作
Rank insert(Tv const& vertex);
Tv remove(Rank v);
//边确认操作,看边是否存在
bool exists(Rank v, Rank u) //边(v, u)是否存在
{ return (-1 < v) && (v < n)&&(-1<u) && (u < n) && E[v][u] != nullptr; }
//边的基本操作
EType& type(Rank v, Rank u) { return E[v][u]->type; }
Te& edge(Rank v, Rank u) { return E[v][u]->data; }
int& weight(Rank v, Rank u) { return E[v][u]->weight; }
//边动态操作
void insert(Te const& edge, int w, Rank v, Rank u) {
if (E[v][u] != nullptr) return;
E[v][u] = new Edge<Te>(edge, w);
e++; V[v].outDegree++; V[u].inDegree++;
}
Te remove(Rank v, Rank u);
//遍历
void BFS(int v, int& clock);//广度优先搜索
void bfs(int s);//多连通
void DFS(int v, int& clock);//深度优先搜索
void dfs(int s);//多连通
//最短路径Dijkstra算法
void dijkstra(Rank s);
//最小生成树prim算法
void prim(Rank s);
//展示信息
void getInfo();
};
template<typename Tv, typename Te>
Tv GraphMatrix<Tv, Te>::remove(Rank v) {
for (Rank u = 0; u < n; u++) {//删除所有出边,以V[u]为起点
if (exists(v, u))
{
delete E[v][u];
V[u].inDegree--;
e--;
}
}
E.erase(E.begin() + v); n--;//删除第n行
Tv vBak = vertex(v); V.erase(V.begin() + v);
for (Rank u = 0; u < n; u++) {//删除第n列
Edge<Te>* x = E[u][v];
E[u].erase(E[u].begin() + v);
if (x != nullptr) {
delete x;
V[u].outDegree--;
e--;
}
}
return vBak;
};
template<typename Tv, typename Te>
Rank GraphMatrix<Tv, Te>::insert(Tv const& vertex)
{
//插入顶点,返回编号
for (Rank u = 0; u < n; u++) {
E[u].insert(E[u].end(), nullptr);
}
n++;
E.insert(E.end(), vector<Edge<Te>*>(n, (Edge<Te>*)nullptr));
V.insert(V.end(), Vertex<Tv>(vertex));
return V.size();
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::getInfo() {
// 用于输出各边的状态
map<int, string> vStatus;
vStatus[UNDISCOVERED] = "UNDISCOVERED";
vStatus[DISCOVERED] = "DISCOVERED";
vStatus[VISITED] = "VISITED";
map<int, string> eType;
eType[UNDETERMINED] = "UNDETERMINED";
eType[TREE] = "TREE";
eType[CROSS] = "CROSS";
eType[FORWARD] = "FORWARD";
eType[BACKWAED] = "BACKWARD";
cout << "一共有" << n << "个顶点," << e << "条边";
cout << endl<<"点信息:" << endl;
for (int i = 0; i < V.size(); i++) {
cout << "数据:" << V[i].data << " " << " 入度:" << V[i].inDegree
<< "出度:" << V[i].outDegree << endl;
cout<<"dTime:"<<dTime(i)<<" fTime:"<<fTime(i) << " 父节点:"<<parent(i) << " 状态:" << vStatus[status(i)] <<" 距离:"<<priority(i) << endl;
}
cout << endl << "边信息:" << endl;
for (int v = 0; v < n; v++) {
for (int u = 0; u < n; u++) {
if (E[v][u] != nullptr) {
cout << "起点:" << v << " 终点:" << u << " 类型:" << eType[type(v, u)] << endl;
}
}
}
for (int v = 0; v < n; v++) {
for (int u = 0; u < n; u++) {
if (E[v][u] != nullptr)
cout << E[v][u]->data << " ";
else
cout << 0 << " ";
}
cout << endl;
}
cout << endl;
};
template<typename Tv, typename Te>
Te GraphMatrix<Tv, Te>::remove(Rank v, Rank u) {
//删除顶点v和u之间的联边
Te eBak = edge(v, u);
delete E[v][u]; E[v][u] = nullptr;
e--; V[v].outDegree--; V[u].inDegree--;
return eBak;
}
说几个比较重要的点或者感悟
所有的小方法都写出来了,像边是否合法,是否存在,返回节点的下一个邻居,不从轮子造起,后面用的时候十分舒服
把点,边的属性用类的方法封装起来,一个&解决了很多问题,就不用去找Vertex的属性了
exists(v , u)方法,判断边( v , u)是否存在
v u 不能越界,越界了返回false
E[v][u]是否指向空指针
nextNbr(v , u), 返回V[v]的邻居V[u]的下一个邻居的下标,就像我们图上的边,下一条边,省去了很多的步骤。
插入一个点 insert( Vertex(d)),为d
V在末尾添加一个元素,指向新建的节点
E邻接向量的表示,E[0]~E[n-1]的末尾添加一个元素,也要添加一个长为e的E[n]
n++
插入一条边
E[v][u]=new Edge();
V[v]出度++
V[u]入度++
e++(边的数量)
删除点和边的时候,顺序和添加的时候完全相反
v和u一直表示边的起点下标和终点下标
bfs 广度优先搜索
图遍历算法的一种,从一个节点开始,第一次遍历所有和他相邻的边,第二次遍历和他相邻边的相邻边,就像石子投入湖泊,一层一层的涟漪。
思路:
queue中取出一个节点
遍历他的所有邻居,
他是UNDISCOVER,入栈,标记为DISCOVERED,记录辅助信息
他是VISITED或者DISCOVERED,标记边为CROSS
对这个节点标记为DISCOVERED
再从queue中取出一个节点,循环
辅助信息复位
template<typename Tv,typename Te>
void GraphMatrix<Tv, Te>::reset() {
//所有的顶点、边的辅助信息复位
for (Rank v = 0; v < n; v++) {
//点信息复位
status(v) = UNDISCOVERED;
dTime(v) = -1; fTime(v) = -1;
parent(v) = -1; priority(v) = INT_MAX;
//边信息
for (Rank u = 0; u < n; u++)
if (exists(v, u))
type(v, u) = UNDETERMINED;
}
};
bfs代码
template<typename Tv,typename Te>
void GraphMatrix<Tv, Te>::BFS(int v, int& clock) {
queue<Rank> Q;//存的是未遍历节点的编号
status(v) = DISCOVERED;
Q.push(v);
dTime(v) = clock; clock = 0;
while (!Q.empty()) {
Rank v = Q.front();
Q.pop();
for (Rank u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {
//遍历所有的邻居
if (UNDISCOVERED == status(u)) {
status(u) = DISCOVERED;
Q.push(u); dTime(u) = dTime(v) + 1;//发现该节点
type(v, u) = TREE; parent(u) = v;
}
else
type(v, u) = CROSS;
status(v) = VISITED;
fTime(v) = clock++;
if (Q.empty())
clock = dTime(v) + 1;
else if (dTime(v) < dTime(Q.front()))
clock = 0;
}
}
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::bfs(int s) {
reset(); int clock = 0; int v = s;
do
if (UNDISCOVERED == status(v))
BFS(v, clock);
while (s != (v = (++v % n)));
};
这个时候,dTime和fTime就显现出来了,当AdTime<BdTime<BfTime<AfTime时候,我们就可以从O(1)的时间内判断B是A的子节点。边属性为Tree,说明他是遍历树的枝干,Cross, 说明不是枝干。
外面的一个bfs,找到所有未访问的点,因为图可能会有两个连通域。总的算法还是O(n2),外面的不可能遍历所有的点。
dfs 深度优先遍历
对一个点,找到他的下一个未被发现的邻居,将这个点设为discovered,然后再对这个未被发现的邻居,进行dfs,知道他的所有邻居都被发现了,将这个点设为visited,设置ftime,再返回遍历他的那个邻居。
思路:
一个节点,遍历他的所有邻居
邻居为UNDISCOVERED,记录辅助信息,边设为TREE,对这个邻居递归调用dfs
邻居为DISCOVERED,说明他已经遍历完了,且辈分比这个节点大,边设为BACKWAED,意为边是从辈分小的到辈分大的边
邻居为VISITED,这个地方有点模糊。
结束,记录辅助信息。
贴代码,dfs的。
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::DFS(int v, int& clock) {
dTime(v) = ++clock; status(v) = DISCOVERED;
for (int u = firstNbr(v); -1 < u; u = nextNbr(v, u)) {
switch (status(u))
{
case UNDISCOVERED:
type(v, u) = TREE; parent(u) = v; DFS(u, clock); break;
case DISCOVERED:
type(v, u) = BACKWAED; break;
default:
type(v, u) = (dTime(v) < dTime(u) ? FORWARD : CROSS);
break;
}
}
status(v) = VISITED; fTime(v) = ++clock;
};
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::dfs(int s) {
reset(); int clock = 0; int v = s;
do
if (UNDISCOVERED == status(v))
DFS(v, clock);
while (s != (v = (++v % n)));
};
dijkstra
大名鼎鼎的最短路径算法,求带权图中,一个节点到另一个节点的最短距离。
假设A到D的最短路径是A-->B-->C-->D,那么A到C的最短路径一定是A-->B-->C,因为如果存在更短的路径使得A到C更短,那么我们可以找到另一条路径是A到D更短。
假设图中有A, B, C, D, E ,F六个点,求A到F最短路径,我们求出A到BCDE的最短距离,然后在BF, CF ,DF, EF(如果存在)选取一条最短的,两者相加即可。
思路:
遍历A的所有邻居,更新他们的权重为边AB, AC的权重(未遍历到的边权重设为正无穷)
选出权重最小的点,此时这个点的parent是A
遍历找到的所有邻居(假设他是B),当AB+BX<weight(X)时,说明有一条更短的路,更新他的权重
循环遍历n次
代码
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::dijkstra(Rank s) {
reset(); priority(s) = 0;
for (int i = 0; i < n; i++) {
status(s) = VISITED;
if (-1 < parent(s)) type(parent(s), s) = TREE;
for (Rank j = firstNbr(s); -1 < j; j = nextNbr(s, j)) {
//在所有s邻居里找最短的路径
if (status(j) == UNDISCOVERED && priority(j) > priority(s) + weight(s, j))
{
priority(j) = priority(s) + weight(s, j);
parent(j) = s;
}
}
//找出最短的路径,也适用于所有的找最小值
for (int shortest = INT_MAX, j = 0; j < n; j++) {
if (status(j) == UNDISCOVERED && shortest > priority(j)) {
shortest = priority(j); s = j;
}
}
}
};
测试
void test_di() {
//迪杰斯特拉算法测试
GraphMatrix<int, int> graph;
for (int i = 0; i < 6; i++) {
graph.insert(i);
}
vector<vector<int>> a({ {0,1,12},{0,3,1},
{1,2,5},{1,3,9}, {1,4,4},
{3,4,3},
{2,4,13 },{2,5,15},
{4,5,14} });
for (int i = 0; i < a.size(); i++) {
int j = a[i][0], k = a[i][1];
int w = a[i][2];
graph.insert(1, w, j, k);
graph.insert(1, w, k, j);
}
graph.dijkstra(0);
graph.getInfo();
}
prim
prim求的是最小生成树,相当于在一个带权图中,用最小的成本,生成一棵树,使得所有的节点都是连通的。思路和dijkstra几乎一样,就是判断条件不一样。
思路:
遍历A的所有邻居,更新他们的权重为边AB, AC的权重(未遍历到的边权重设为正无穷)
选出权重最小的点,此时这个点的parent是A
遍历找到的所有邻居(假设他是B),当BX<weight(X)时,说明有一条更短的路,更新他的权重
循环遍历n次
template<typename Tv, typename Te>
void GraphMatrix<Tv, Te>::prim(Rank s) {
reset(); priority(s) = 0;
for (int i = 0; i < n; i++) {
status(s) = VISITED;
if (-1 < parent(s)) type(parent(s), s) = TREE;
for (Rank j = firstNbr(s); -1 < j; j = nextNbr(s, j)) {
//在所有s邻居里找最短的路径,到自己的最短路径,不一样的地方
if (status(j) == UNDISCOVERED && priority(j) > weight(s, j))
{
priority(j) = weight(s, j);
parent(j) = s;
}
}
//找出最短的路径,也适用于所有的找最小值
for (int shortest = INT_MAX, j = 0; j < n; j++) {
if (status(j) == UNDISCOVERED && shortest > priority(j)) {
shortest = priority(j); s = j;
}
}
}
};