/*** C++: Dijkstra算法获取最短路径(邻接表)** @author judyge* @date 2014/04/24*/#include <iomanip>
#include <iostream>
#include <vector>
using namespace std;// 示例类:边的结构体(用来演示)
class EData
{public:char start; // 边的起点char end;   // 边的终点int weight; // 边的权重public:EData(){}EData(char s, char e, int w):start(s),end(e),weight(w){}
};// 邻接表
class ListUDG
{
#define MAX 100
#define INF         (~(0x1<<31))        // 最大值(即0X7FFFFFFF)private: // 内部类// 邻接表中表对应的链表的顶点class ENode{int ivex;           // 该边所指向的顶点的位置int weight;         // 该边的权ENode *nextEdge;    // 指向下一条弧的指针friend class ListUDG;};// 邻接表中表的顶点class VNode{char data;          // 顶点信息ENode *firstEdge;   // 指向第一条依附该顶点的弧friend class ListUDG;};private: // 私有成员int mVexNum;             // 图的顶点的数目int mEdgNum;             // 图的边的数目VNode mVexs[MAX];public:// 创建邻接表对应的图(自己输入)ListUDG();// 创建邻接表对应的图(用已提供的数据)ListUDG(char vexs[], int vlen, EData *edges[], int elen);~ListUDG();// 深度优先搜索遍历图void DFS();// 广度优先搜索(类似于树的层次遍历)void BFS();// 打印邻接表图void print();// prim最小生成树void prim(int start);// 克鲁斯卡尔(Kruskal)最小生成树void kruskal();// Dijkstra最短路径void dijkstra(int vs, int vexs[], int dist[]);private:// 读取一个输入字符char readChar();// 返回ch的位置int getPosition(char ch);// 深度优先搜索遍历图的递归实现void DFS(int i, int *visited);// 将node节点链接到list的最后void linkLast(ENode *list, ENode *node);// 获取边<start, end>的权值;若start和end不是连通的,则返回无穷大。int getWeight(int start, int end);// 获取图中的边EData* getEdges();// 对边按照权值大小进行排序(由小到大)void sortEdges(EData* edges, int elen);// 获取i的终点int getEnd(int vends[], int i);
};/** 创建邻接表对应的图(自己输入)*/
ListUDG::ListUDG()
{char c1, c2;int v, e;int i, p1, p2;int weight;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 = NULL;}// 初始化"邻接表"的边for(i=0; i<mEdgNum; i++){// 读取边的起始顶点和结束顶点cout << "edge(" << i << "): ";c1 = readChar();c2 = readChar();cin >> weight;p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;node1->weight = weight;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;node2->weight = weight;// 将node2链接到"p2所在链表的末尾"if(mVexs[p2].firstEdge == NULL)mVexs[p2].firstEdge = node2;elselinkLast(mVexs[p2].firstEdge, node2);}
}/** 创建邻接表对应的图(用已提供的数据)*/
ListUDG::ListUDG(char vexs[], int vlen, EData *edges[], int elen)
{char c1, c2;int i, p1, p2;int weight;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]->start;c2 = edges[i]->end;weight = edges[i]->weight;p1 = getPosition(c1);p2 = getPosition(c2);// 初始化node1node1 = new ENode();node1->ivex = p2;node1->weight = weight;// 将node1链接到"p1所在链表的末尾"if(mVexs[p1].firstEdge == NULL)mVexs[p1].firstEdge = node1;elselinkLast(mVexs[p1].firstEdge, node1);// 初始化node2node2 = new ENode();node2->ivex = p1;node2->weight = weight;// 将node2链接到"p2所在链表的末尾"if(mVexs[p2].firstEdge == NULL)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::DFS(int i, int *visited)
{ENode *node;visited[i] = 1;cout << mVexs[i].data << " ";node = mVexs[i].firstEdge;while (node != NULL){if (!visited[node->ivex])DFS(node->ivex, visited);node = node->nextEdge;}
}/** 深度优先搜索遍历图*/
void ListUDG::DFS()
{int i;int visited[MAX];       // 顶点访问标记// 初始化所有顶点都没有被访问for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "DFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i])DFS(i, visited);}cout << endl;
}/** 广度优先搜索(类似于树的层次遍历)*/
void ListUDG::BFS()
{int head = 0;int rear = 0;int queue[MAX];     // 辅组队列int visited[MAX];   // 顶点访问标记int i, j, k;ENode *node;for (i = 0; i < mVexNum; i++)visited[i] = 0;cout << "BFS: ";for (i = 0; i < mVexNum; i++){if (!visited[i]){visited[i] = 1;cout << mVexs[i].data << " ";queue[rear++] = i;  // 入队列}while (head != rear) {j = queue[head++];  // 出队列node = mVexs[j].firstEdge;while (node != NULL){k = node->ivex;if (!visited[k]){visited[k] = 1;cout << mVexs[k].data << " ";queue[rear++] = k;}node = node->nextEdge;}}}cout << endl;
}/** 打印邻接表图*/
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 != NULL){cout << node->ivex << "(" << mVexs[node->ivex].data << ") ";node = node->nextEdge;}cout << endl;}
}/** 获取边<start, end>的权值;若start和end不是连通的,则返回无穷大。*/
int ListUDG::getWeight(int start, int end)
{ENode *node;if (start==end)return 0;node = mVexs[start].firstEdge;while (node!=NULL){if (end==node->ivex)return node->weight;node = node->nextEdge;}return INF;
}/** prim最小生成树** 参数说明:*   start -- 从图中的第start个元素开始,生成最小树*/
void ListUDG::prim(int start)
{int min,i,j,k,m,n,tmp,sum;int index=0;         // prim最小树的索引,即prims数组的索引char prims[MAX];     // prim最小树的结果数组int weights[MAX];    // 顶点间边的权值// prim最小生成树中第一个数是"图中第start个顶点",因为是从start开始的。prims[index++] = mVexs[start].data;// 初始化"顶点的权值数组",// 将每个顶点的权值初始化为"第start个顶点"到"该顶点"的权值。for (i = 0; i < mVexNum; i++ )weights[i] = getWeight(start, i);for (i = 0; i < mVexNum; i++){// 由于从start开始的,因此不需要再对第start个顶点进行处理。if(start == i)continue;j = 0;k = 0;min = INF;// 在未被加入到最小生成树的顶点中,找出权值最小的顶点。while (j < mVexNum){// 若weights[j]=0,意味着"第j个节点已经被排序过"(或者说已经加入了最小生成树中)。if (weights[j] != 0 && weights[j] < min){min = weights[j];k = j;}j++;}// 经过上面的处理后,在未被加入到最小生成树的顶点中,权值最小的顶点是第k个顶点。// 将第k个顶点加入到最小生成树的结果数组中prims[index++] = mVexs[k].data;// 将"第k个顶点的权值"标记为0,意味着第k个顶点已经排序过了(或者说已经加入了最小树结果中)。weights[k] = 0;// 当第k个顶点被加入到最小生成树的结果数组中之后,更新其它顶点的权值。for (j = 0 ; j < mVexNum; j++){// 获取第k个顶点到第j个顶点的权值tmp = getWeight(k, j);// 当第j个节点没有被处理,并且需要更新时才被更新。if (weights[j] != 0 && tmp < weights[j])weights[j] = tmp;}}// 计算最小生成树的权值sum = 0;for (i = 1; i < index; i++){min = INF;// 获取prims[i]在矩阵表中的位置n = getPosition(prims[i]);// 在vexs[0...i]中,找出到j的权值最小的顶点。for (j = 0; j < i; j++){m = getPosition(prims[j]);tmp = getWeight(m, n);if (tmp < min)min = tmp;}sum += min;}// 打印最小生成树cout << "PRIM(" << mVexs[start].data  <<")=" << sum << ": ";for (i = 0; i < index; i++)cout << prims[i] << " ";cout << endl;
}/* * 获取图中的边*/
EData* ListUDG::getEdges()
{int i,j;int index=0;ENode *node;EData *edges;edges = new EData[mEdgNum];for (i=0; i < mVexNum; i++){node = mVexs[i].firstEdge;while (node != NULL){if (node->ivex > i){edges[index].start  = mVexs[i].data;           // 起点edges[index].end    = mVexs[node->ivex].data;  // 终点edges[index].weight = node->weight;            // 权index++;}node = node->nextEdge;}}return edges;
}/* * 对边按照权值大小进行排序(由小到大)*/
void ListUDG::sortEdges(EData* edges, int elen)
{int i,j;for (i=0; i<elen; i++){for (j=i+1; j<elen; j++){if (edges[i].weight > edges[j].weight){// 交换"边i"和"边j"swap(edges[i], edges[j]);}}}
}/** 获取i的终点*/
int ListUDG::getEnd(int vends[], int i)
{while (vends[i] != 0)i = vends[i];return i;
}/** 克鲁斯卡尔(Kruskal)最小生成树*/
void ListUDG::kruskal()
{int i,m,n,p1,p2;int length;int index = 0;          // rets数组的索引int vends[MAX]={0};     // 用于保存"已有最小生成树"中每个顶点在该最小树中的终点。EData rets[MAX];        // 结果数组,保存kruskal最小生成树的边EData *edges;           // 图对应的所有边// 获取"图中所有的边"edges = getEdges();// 将边按照"权"的大小进行排序(从小到大)sortEdges(edges, mEdgNum);for (i=0; i<mEdgNum; i++){p1 = getPosition(edges[i].start);      // 获取第i条边的"起点"的序号p2 = getPosition(edges[i].end);        // 获取第i条边的"终点"的序号m = getEnd(vends, p1);                 // 获取p1在"已有的最小生成树"中的终点n = getEnd(vends, p2);                 // 获取p2在"已有的最小生成树"中的终点// 如果m!=n,意味着"边i"与"已经添加到最小生成树中的顶点"没有形成环路if (m != n){vends[m] = n;                       // 设置m在"已有的最小生成树"中的终点为nrets[index++] = edges[i];           // 保存结果}}delete[] edges;// 统计并打印"kruskal最小生成树"的信息length = 0;for (i = 0; i < index; i++)length += rets[i].weight;cout << "Kruskal=" << length << ": ";for (i = 0; i < index; i++)cout << "(" << rets[i].start << "," << rets[i].end << ") ";cout << endl;
}/** Dijkstra最短路径。* 即,统计图中"顶点vs"到其它各个顶点的最短路径。** 参数说明:*       vs -- 起始顶点(start vertex)。即计算"顶点vs"到其它顶点的最短路径。*     prev -- 前驱顶点数组。即,prev[i]的值是"顶点vs"到"顶点i"的最短路径所经历的全部顶点中,位于"顶点i"之前的那个顶点。*     dist -- 长度数组。即,dist[i]是"顶点vs"到"顶点i"的最短路径的长度。*/
void ListUDG::dijkstra(int vs, int prev[], int dist[])
{int i,j,k;int min;int tmp;int flag[MAX];      // flag[i]=1表示"顶点vs"到"顶点i"的最短路径已成功获取。// 初始化for (i = 0; i < mVexNum; i++){flag[i] = 0;                // 顶点i的最短路径还没获取到。prev[i] = 0;                // 顶点i的前驱顶点为0。dist[i] = getWeight(vs, i);  // 顶点i的最短路径为"顶点vs"到"顶点i"的权。}// 对"顶点vs"自身进行初始化flag[vs] = 1;dist[vs] = 0;// 遍历mVexNum-1次;每次找出一个顶点的最短路径。for (i = 1; i < mVexNum; i++){// 寻找当前最小的路径;// 即,在未获取最短路径的顶点中,找到离vs最近的顶点(k)。min = INF;for (j = 0; j < mVexNum; j++){if (flag[j]==0 && dist[j]<min){min = dist[j];k = j;}}// 标记"顶点k"为已经获取到最短路径flag[k] = 1;// 修正当前最短路径和前驱顶点// 即,当已经"顶点k的最短路径"之后,更新"未获取最短路径的顶点的最短路径和前驱顶点"。for (j = 0; j < mVexNum; j++){tmp = getWeight(k, j);tmp = (tmp==INF ? INF : (min + tmp)); // 防止溢出if (flag[j] == 0 && (tmp  < dist[j]) ){dist[j] = tmp;prev[j] = k;}}}// 打印dijkstra最短路径的结果cout << "dijkstra(" << mVexs[vs].data << "): " << endl;for (i = 0; i < mVexNum; i++)cout << "  shortest(" << mVexs[vs].data << ", " << mVexs[i].data << ")=" << dist[i] << endl;
}int main()
{int prev[MAX] = {0};int dist[MAX] = {0};// 顶点char vexs[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};// 边EData *edges[] = {// 起点 终点 权new EData('A', 'B', 12), new EData('A', 'F', 16), new EData('A', 'G', 14), new EData('B', 'C', 10), new EData('B', 'F',  7), new EData('C', 'D',  3), new EData('C', 'E',  5), new EData('C', 'F',  6), new EData('D', 'E',  4), new EData('E', 'F',  2), new EData('E', 'G',  8), new EData('F', 'G',  9), };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();   // 打印图//pG->DFS();     // 深度优先遍历//pG->BFS();     // 广度优先遍历//pG->prim(0);   // prim算法生成最小生成树//pG->kruskal(); // Kruskal算法生成最小生成树// dijkstra算法获取"第4个顶点"到其它各个顶点的最短距离pG->dijkstra(3, prev, dist);return 0;
}

ACM模板--邻接表 无向图 Prim Kruskal Dijkstra相关推荐

  1. ACM 模板--邻接表 无向图 搜索算法

    图的 广度优先搜索 深度递归与非递归搜索 /*** C++: 邻接表表示的"无向图(List Undirected Graph)"** @author judyge* @date ...

  2. ACM模板--邻接矩阵 无向图 Prim Kruskal Dijkstra

    /*** C++: Dijkstra算法获取最短路径(邻接矩阵)** @author skywang* @date 2014/04/24*/#include <iomanip> #incl ...

  3. ACM 模板--邻接表 有向图 拓扑排序

    /*** C++: 无回路有向图(Directed Acyclic Graph)的拓扑排序* 该DAG图是通过邻接表实现的. ** @author judyge* @date 2014/04/22*/ ...

  4. ACM 模板--邻接表 有向图 搜索算法

    邻接表图的广度优先搜索 深度递归与非递归搜索 /*** C++: 邻接表图** @author judyge* @date 2014/04/19*/#include <iomanip> # ...

  5. java邻接表无向图的创建_邻接表无向图(三) 之Java详解

    前面分别介绍了邻接表无向图的C和C++实现,本文通过Java实现邻接表无向图. 目录 邻接表无向图的介绍 邻接表无向图是指通过邻接表表示的无向图. 上面的图G1包含了"A,B,C,D,E,F ...

  6. java:邻接表无向图的链表实现法

    首先画出邻接表图: 分析: 观察右边的邻接表可以发现,A~E每个顶点都有自己的编号,每个顶点又跟其他数组相关联.我们可以把所有的顶点看做一个数组,而与每个顶点相关联的其他顶点又是一个数组,那么整个邻接 ...

  7. 邻接表实现Prim算法

    Prim算法 Prim算法是通过连通网找最小生成树(mst)的算法 过程: 1.首先选取任意顶点作为树的根 2.遍历其他(不在树中)的顶点,对于每个顶点,找到一条到mst路径最短的边,这样,每个顶点都 ...

  8. 有向图,无向图的邻接矩阵和邻接表模板

    图 图的定义 有向图 概念 模板 邻接矩阵 邻接表 无向图 概念 模板 邻接矩阵 邻接表 简单图 完全图 图的定义 图 GGG 由顶点集 VVV 和边集 EEE 组成,记为 G=(V,E)G=(V,E ...

  9. 数据结构之图的创建(邻接表)

    数据结构之图的基本概念中了解了图的基本概念,接下来对图的代码实现进行详解. 邻接无向图 1. 邻接表无向图介绍 邻接表无向图是指通过邻接表表示的无向图. 上面的图G1包含了"A,B,C,D, ...

最新文章

  1. 理解事件捕获。在限制范围内拖拽div+吸附+事件捕获
  2. windows7基本操作学习笔记
  3. 将zookeeper、Tomcat、redis部署成windos服务
  4. TIOBE 6月编程语言榜单:C语言继续占据第一
  5. Graph Coloring I
  6. 小白也能看懂的 Java 异常处理
  7. Python 最抢手、Java 最流行、Go 最有前途,7000 位程序员揭秘 2019 软件开发现状...
  8. 阿里云泄露 40 家名企源代码!
  9. 2021牛客暑期多校训练营9,签到题HE
  10. POJ1703-Find them, Catch them
  11. win环境sftp软件_在Windows上使用sftp工具—WinSCP
  12. 计算机专硕学硕哪个好考啊,【专硕考研】计算机考研选学硕还是专硕?
  13. 【年终总结】——回忆过往,不畏将来
  14. 无根树的Prufer序列
  15. 2022-03-25 redis组建哨兵及主从高可用的failover
  16. 脑科学研究中常用的神经电信号记录电极介绍
  17. git 撤销提交 撤销暂存区 取消操作
  18. su PK sudo
  19. cs224n 2019 Lecture 9: Practical Tips for Final Projects
  20. 【AI达人创造营三期-Antigen Detector(新冠试剂盒检测)部署】

热门文章

  1. 我的 Serverless 实战 — 云函数与触发器的创建与使用 ( 开通腾讯云 “ 云开发 “ 服务 | 创建云函数 | 创建触发器 | 测试触发器 )
  2. 【Android 安全】DEX 加密 ( 代理 Application 开发 | 加载 dex 文件 | 将系统的 dexElements 与 应用的 dexElements 合并 | 替换操作 )
  3. 设计模式-Decorator模式
  4. redis as session_handler
  5. .net core mvc 区域路由设置(配置)
  6. NHibernate 状态的概念 以及 小测试
  7. 403错误代码导致网站样式全部乱了
  8. weinre调试移动端页面
  9. scanf_s()函数 (是Microsoft公司VS开发工具提供的一个功能相同的安全标准输入函数)
  10. linux每日命令(27):chmod命令