算法与数据结构课设(有向图,无向图,有向网,无向网)
数据结构中有向图和无向图的c语言实现

#include<iostream.h>
#include<malloc.h>
#define M 50
typedef char vextype;//顶点数据类型char
typedef struct node //定义表结点类型
{
int adjvex;//邻接点域
struct node *link;//指针域
}
cout<<"以(0,0)为输入结束符"<<endl;
cout<<"输入一条边依附的两个顶点序号:";
cin>>i>>j;
while((i>0)&&(j>0))//输入的(i,j)为(0,0)作为结束符号
{
p=(edgenode*)malloc(sizeof(edgenode));//生成邻接序号为j的表结点
break;
default:cout<<"输入错误,程序结束!"<<endl;
return;
}
cout<<endl;
cout<<"是否继续?(输入n结束,输入y有效!)"<<endl;
cin>>flag;
}
cout<<"程序结束,再见!"<<endl;
}
}edgenode,*Edgenode;
typedef struct headnode//定义表头结点类型
{
vextype vexdata;//顶点数据域
算法与数据结构大纲

算法与数据结构大纲一、课程简介算法与数据结构是计算机科学中的核心基础课程,旨在介绍算法设计和数据结构的基本概念、原理和方法,培养学生的算法思维和问题解决能力。
二、教学目标1. 了解算法与数据结构的基本概念和原理;2. 掌握常见的数据结构及其操作;3. 学习常见的算法设计策略和分析方法;4. 能够运用所学知识解决实际问题。
三、教学内容1. 算法基础- 算法的概念和特征- 算法的表示方法- 算法的分析:时间复杂度和空间复杂度2. 数据结构基础- 数据结构的概念和分类- 抽象数据类型- 数据结构的操作和实现3. 线性结构- 数组- 链表- 栈和队列4. 树状结构- 树的概念和基本操作- 二叉树- 二叉搜索树- 平衡二叉树5. 图状结构- 图的概念和基本操作- 图的存储和表示- 图的遍历6. 排序算法- 插入排序- 选择排序- 冒泡排序- 快速排序- 归并排序7. 查找算法- 顺序查找- 二分查找- 哈希查找8. 算法设计策略- 分治法- 动态规划法- 回溯法- 贪心算法四、教学方法1. 理论讲解:通过课堂讲解,介绍算法与数据结构的基本概念、原理和方法;2. 编程实践:通过编程练习,让学生掌握数据结构的实现和算法的应用;3. 案例分析:通过实际问题的解决,让学生学会运用所学知识解决实际问题;4. 小组讨论:通过小组讨论,培养学生的团队合作和问题解决能力。
五、考核方式1. 平时作业:包括课后作业、编程练习和课堂表现等;2. 期中考试:考核学生对前半部分教学内容的掌握程度;3. 期末考试:考核学生对整个课程内容的掌握程度。
六、教学资料1. 教材:《算法与数据结构》(教材名称),(作者)著,(出版社)出版;2. 参考资料:《数据结构与算法分析》(参考书名称),(作者)著,(出版社)出版。
七、教学设备1. 计算机实验室;2. 投影仪;3. 编程软件。
《数据结构》教案(精华版)

《数据结构》教案(精华版)《数据结构》教案(精华版)前言数据结构是计算机学科中的重要基础课程,它涉及到数据的存储、组织和管理。
本教案旨在帮助学生掌握数据结构的基本概念、算法和应用,提高其解决实际问题的能力。
第一章:引言在本章中,我们将介绍数据结构的基本概念和重要性。
学生将了解到数据结构在计算机科学中的作用,以及为什么学习数据结构对于他们的职业发展至关重要。
1.1 数据结构的定义数据结构是一种组织和存储数据的方式,它涉及到数据元素之间的关系,以及对这些关系的操作。
1.2 数据结构的分类数据结构可以分为线性结构和非线性结构。
线性结构中的数据元素之间存在一个明确的顺序关系,而非线性结构中的数据元素之间没有固定的顺序关系。
1.3 数据结构的应用数据结构在计算机科学中有广泛的应用。
例如,在数据库管理系统中,数据结构被用来组织和管理大量的数据;在图形图像处理中,数据结构被用来存储和操作图像数据。
第二章:线性结构本章将介绍线性结构,包括线性表、栈和队列。
学生将学习这些线性结构的定义、实现和应用。
2.1 线性表线性表是一种最简单的数据结构,它由一组数据元素组成,这些元素按照线性的顺序存储。
2.2 栈栈是一种特殊的线性表,它具有“先进后出”的特点。
学生将学习栈的定义、实现和常见应用。
2.3 队列队列是另一种特殊的线性表,它具有“先进先出”的特点。
学生将学习队列的定义、实现和应用。
第三章:树结构本章将介绍树结构,包括二叉树、搜索树和平衡树。
学生将学习这些树结构的定义、实现和应用。
3.1 二叉树二叉树是一种常见的树结构,它的每个节点最多有两个子节点。
学生将学习二叉树的定义、实现和遍历算法。
3.2 搜索树搜索树是一种特殊的二叉树,它的每个节点都符合一定的大小关系。
学生将学习搜索树的定义、实现和查找算法。
3.3 平衡树平衡树是一种自平衡的二叉树,它可以保持树的高度平衡。
学生将学习平衡树的定义、实现和平衡算法。
第四章:图结构本章将介绍图结构,包括无向图和有向图。
数据结构课设——有向图的深度、广度优先遍历及拓扑排序

数据结构课设——有向图的深度、⼴度优先遍历及拓扑排序任务:给定⼀个有向图,实现图的深度优先, ⼴度优先遍历算法,拓扑有序序列,并输出相关结果。
功能要求:输⼊图的基本信息,并建⽴图存储结构(有相应提⽰),输出遍历序列,然后进⾏拓扑排序,并测试该图是否为有向⽆环图,并输出拓扑序列。
按照惯例,先上代码,注释超详细:#include<stdio.h>#include<stdlib.h>#include<malloc.h>#pragma warning(disable:4996)#define Max 20//定义数组元素最⼤个数(顶点最⼤个数)typedef struct node//边表结点{int adjvex;//该边所指向结点对应的下标struct node* next;//该边所指向下⼀个结点的指针}eNode;typedef struct headnode//顶点表结点{int in;//顶点⼊度char vertex;//顶点数据eNode* firstedge;//指向第⼀条边的指针,边表头指针}hNode;typedef struct//邻接表(图){hNode adjlist[Max];//以数组的形式存储int n, e;//顶点数,边数}linkG;//以邻接表的存储结构创建图linkG* creat(linkG* g){int i, k;eNode* s;//边表结点int n1, e1;char ch;g = (linkG*)malloc(sizeof(linkG));//申请结点空间printf("请输⼊顶点数和边数:");scanf("%d%d", &n1, &e1);g->n = n1;g->e = e1;printf("顶点数:%d 边数:%d\n", g->n, g->e);printf("请输⼊顶点信息(字母):");getchar();//因为接下来要输⼊字符串,所以getchar⽤于承接上⼀条命令的结束符for (i = 0; i < n1; i++){scanf("%c", &ch);g->adjlist[i].vertex = ch;//获得该顶点数据g->adjlist[i].firstedge = NULL;//第⼀条边设为空}printf("\n打印顶点下标及顶点数据:\n");for (i = 0; i < g->n; i++)//循环打印顶点下标及顶点数据{printf("顶点下标:%d 顶点数据:%c\n", i, g->adjlist[i].vertex);}getchar();int i1, j1;//相连接的两个顶点序号for (k = 0; k < e1; k++)//建⽴边表{printf("请输⼊对<i,j>(空格分隔):");scanf("%d%d", &i1, &j1);s = (eNode*)malloc(sizeof(eNode));//申请边结点空间s->adjvex = j1;//边所指向结点的位置,下标为j1s->next = g->adjlist[i1].firstedge;//将当前s的指针指向当前顶点上指向的结点g->adjlist[i1].firstedge = s;//将当前顶点的指针指向s}return g;//返回指针g}int visited[Max];//标记是否访问void DFS(linkG* g, int i)//深度优先遍历{eNode* p;printf("%c ", g->adjlist[i].vertex);visited[i] = 1;//将已访问过的顶点visited值改为1p = g->adjlist[i].firstedge;//p指向顶点i的第⼀条边while (p)//p不为NULL时(边存在){if (visited[p->adjvex] != 1)//如果没有被访问DFS(g, p->adjvex);//递归}p = p->next;//p指向下⼀个结点}}void DFSTravel(linkG* g)//遍历⾮连通图{int i;printf("深度优先遍历;\n");//printf("%d\n",g->n);for (i = 0; i < g->n; i++)//初始化为0{visited[i] = 0;}for (i = 0; i < g->n; i++)//对每个顶点做循环{if (!visited[i])//如果没有被访问{DFS(g, i);//调⽤DFS函数}}}void BFS(linkG* g, int i)//⼴度优先遍历{int j;eNode* p;int q[Max], front = 0, rear = 0;//建⽴顺序队列⽤来存储,并初始化printf("%c ", g->adjlist[i].vertex);visited[i] = 1;//将已经访问过的改成1rear = (rear + 1) % Max;//普通顺序队列的话,这⾥是rear++q[rear] = i;//当前顶点(下标)队尾进队while (front != rear)//队列⾮空{front = (front + 1) % Max;//循环队列,顶点出队j = q[front];p = g->adjlist[j].firstedge;//p指向出队顶点j的第⼀条边while (p != NULL){if (visited[p->adjvex] == 0)//如果未被访问{printf("%c ", g->adjlist[p->adjvex].vertex);visited[p->adjvex] = 1;//将该顶点标记数组值改为1rear = (rear + 1) % Max;//循环队列q[rear] = p->adjvex;//该顶点进队}p = p->next;//指向下⼀个结点}}}void BFSTravel(linkG* g)//遍历⾮连通图{int i;printf("⼴度优先遍历:\n");for (i = 0; i < g->n; i++)//初始化为0{visited[i] = 0;}for (i = 0; i < g->n; i++)//对每个顶点做循环{if (!visited[i])//如果没有被访问过{BFS(g, i);//调⽤BFS函数}}}//因为拓扑排序要求⼊度为0,所以需要先求出每个顶点的⼊度void inDegree(linkG* g)//求图顶点⼊度{eNode* p;int i;for (i = 0; i < g->n; i++)//循环将顶点⼊度初始化为0{g->adjlist[i].in = 0;}for (i = 0; i < g->n; i++)//循环每个顶点{p = g->adjlist[i].firstedge;//获取第i个链表第1个边结点指针while (p != NULL)///当p不为空(边存在){g->adjlist[p->adjvex].in++;//该边终点结点⼊度+1p = p->next;//p指向下⼀个边结点}printf("顶点%c的⼊度为:%d\n", g->adjlist[i].vertex, g->adjlist[i].in);}void topo_sort(linkG *g)//拓扑排序{eNode* p;int i, k, gettop;int top = 0;//⽤于栈指针的下标索引int count = 0;//⽤于统计输出顶点的个数int* stack=(int *)malloc(g->n*sizeof(int));//⽤于存储⼊度为0的顶点for (i=0;i<g->n;i++)//第⼀次搜索⼊度为0的顶点{if (g->adjlist[i].in==0){stack[++top] = i;//将⼊度为0的顶点进栈}}while (top!=0)//当栈不为空时{gettop = stack[top--];//出栈,并保存栈顶元素(下标)printf("%c ",g->adjlist[gettop].vertex);count++;//统计顶点//接下来是将邻接点的⼊度减⼀,并判断该点⼊度是否为0p = g->adjlist[gettop].firstedge;//p指向该顶点的第⼀条边的指针while (p)//当p不为空时{k = p->adjvex;//相连接的顶点(下标)g->adjlist[k].in--;//该顶点⼊度减⼀if (g->adjlist[k].in==0){stack[++top] = k;//如果⼊度为0,则进栈}p = p->next;//指向下⼀条边}}if (count<g->n)//如果输出的顶点数少于总顶点数,则表⽰有环{printf("\n有回路!\n");}free(stack);//释放空间}void menu()//菜单{system("cls");//清屏函数printf("************************************************\n");printf("* 1.建⽴图 *\n");printf("* 2.深度优先遍历 *\n");printf("* 3.⼴度优先遍历 *\n");printf("* 4.求出顶点⼊度 *\n");printf("* 5.拓扑排序 *\n");printf("* 6.退出 *\n");printf("************************************************\n");}int main(){linkG* g = NULL;int c;while (1){menu();printf("请选择:");scanf("%d", &c);switch (c){case1:g = creat(g); system("pause");break;case2:DFSTravel(g); system("pause");break;case3:BFSTravel(g); system("pause");break;case4:inDegree(g); system("pause");break;case5:topo_sort(g); system("pause");break;case6:exit(0);break;}}return0;}实验⽤图:运⾏结果:关于深度优先遍历 a.从图中某个顶点v 出发,访问v 。
有向图与无向图的性质与算法

有向图与无向图的性质与算法1. 引言在图论中,有向图和无向图是两种最基本的图模型。
它们在表达和解决各类实际问题时具有重要的应用价值。
本文将介绍有向图和无向图的性质以及相关算法,以便读者对其有更深入的理解。
2. 有向图的性质有向图是由一系列顶点和有方向的边组成的图模型。
以下是有向图的几个重要性质:2.1 有向边的方向性与无向图不同,有向图中的边是有方向的,它们从一个顶点指向另一个顶点。
这种方向性在描述一些实际问题时非常有用,比如描述物流运输的路径。
2.2 顶点的入度和出度有向图中的每个顶点都有一个入度和一个出度。
顶点的入度是指指向该顶点的边的数量,而出度是指从该顶点出发的边的数量。
通过计算入度和出度,我们可以了解顶点在图中的连接情况。
2.3 有向环和拓扑排序有向图中存在一个重要的概念,即有向环。
有向环是指从一个顶点出发,经过若干个有向边后又回到该顶点的路径。
有向环在一些问题的分析和解决中具有特殊意义。
而拓扑排序是一种常用的对有向无环图进行排序的方法,它可以按照顶点之间的依赖关系进行排序。
3. 无向图的性质无向图是由一系列顶点和无方向的边组成的图模型。
以下是无向图的几个重要性质:3.1 无向边的无方向性与有向图不同,无向图中的边是无方向的,它们连接着两个顶点,代表了两个顶点之间的关系。
无向图可以用来表示一些没有方向性的问题,比如社交网络中的好友关系。
3.2 顶点的度数无向图中的顶点的度数是指与该顶点相连的边的数量。
顶点的度数越高,说明该顶点在图中的重要性越高,具有更多的连接关系。
3.3 联通性和连通分量无向图中有一个关键性质,即联通性。
若两个顶点之间存在一条连接它们的路径,则称这两个顶点是连通的。
连通分量则是将图中所有连通的顶点分为若干个集合,每个集合内的顶点都是连通的。
4. 算法与应用4.1 有向图的最短路径算法有向图中的最短路径算法是指寻找从一个顶点到另一个顶点的最短路径的方法。
其中,Dijkstra算法和Bellman-Ford算法是常用的有向图最短路径算法。
数据结构与算法-图结构

数据结构与算法-图结构数据结构-图图是⼀种数据结构,其中结点可以具有零个或者多个相邻元素。
两个结点的连接称为边,结点也可以称为顶点顶点边路径⽆向图有向图带权图邻接矩阵(⼆维数组)分为两部分:V和E集合,其中,V是顶点,E是边。
因此,⽤⼀个⼀维存放图中所有顶点数据;⽤⼀个⼆维数组存放顶点间关系(边或弧)的数据,这个⼆维数组称为邻接。
邻接表(链表)邻接表,存储⽅法跟树的孩⼦链表⽰法相类似,是⼀种顺序分配和链式分配相结合的。
如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。
所谓遍历,其实就是对结点的访问。
⼀个图的结点有很多,如何全部访问到,需要制定策略,⼀般是深度优先遍历与⼴度优先遍历深度优先遍历(Depth First Search)从初始访问结点出发,⾸先访问第⼀个邻接结点然后再以这个被访问的邻接结点作为初始结点,访问其第⼀个邻接结点即每次都在访问完当前结点后⾸先访问当前结点的第⼀个邻接结点深度优先遍历是⼀个递归的过程访问初始结点v,并标记v为已经访问查找结点v的第⼀个邻接结点w若w存在,则继续,不存在则回到第⼀步,从v的下⼀个结点继续若w未被访问,则对其进⾏深度优先遍历递归查找结点v的w邻接结点的下⼀个邻接结点,重新上述过程⼴度优先遍历(Broad First Search)类似于分层搜索的过程,⼴度优先遍历需求使⽤⼀个队列以保持访问过的结点的顺序,以便按这个顺序来访问这些结点的邻接结点访问初始结点v并标记结点v为已经访问结点v⼊队列队列为⾮空时,则继续执⾏,否则算法结束出队列,取出队列头结点u查找结点u的第⼀个邻接结点w若结点u的邻接结点w不存在,则回到上述步骤,否则继续进⾏若结点w未被访问,则访问结点w并标记为已经访问结点w⼊队列查找结点u的继邻接结点w,转到上述步骤package cn.imut;import java.util.ArrayList;import java.util.Arrays;import java.util.LinkedList;public class Graph {private ArrayList<String> vertexList; //存储顶点集合private int[][] edges; //存储图对应的邻接矩阵private int numOfEdges; //表⽰边的数⽬private boolean[] isVisited; //记录某个结点是否被访问public static void main(String[] args) {//测试⼀把图是否创建okint n = 8; //结点的个数//String Vertexs[] = {"A", "B", "C", "D", "E"};String Vertexs[] = {"1", "2", "3", "4", "5", "6", "7", "8"};//创建图对象Graph graph = new Graph(n);//循环的添加顶点for(String vertex: Vertexs) {graph.insertVertex(vertex);}//添加边//A-B A-C B-C B-D B-E// graph.insertEdge(0, 1, 1); // A-B// graph.insertEdge(0, 2, 1); //// graph.insertEdge(1, 2, 1); //// graph.insertEdge(1, 3, 1); //// graph.insertEdge(1, 4, 1); ////更新边的关系graph.insertEdge(0, 1, 1);graph.insertEdge(0, 2, 1);graph.insertEdge(1, 3, 1);graph.insertEdge(1, 4, 1);graph.insertEdge(3, 7, 1);graph.insertEdge(4, 7, 1);graph.insertEdge(2, 5, 1);graph.insertEdge(2, 6, 1);graph.insertEdge(5, 6, 1);//显⽰⼀把邻结矩阵graph.showGraph();//测试⼀把,我们的dfs遍历是否okSystem.out.println("深度遍历");graph.dfs(); // A->B->C->D->E [1->2->4->8->5->3->6->7]// System.out.println();System.out.println("⼴度优先!");graph.bfs(); // A->B->C->D-E [1->2->3->4->5->6->7->8]}//构造器public Graph(int n) {//初始化矩阵和vertexListedges = new int[n][n];vertexList = new ArrayList<String>(n);numOfEdges = 0;numOfEdges = 0;}/*** 得到第⼀个邻接结点的下标w* @param index 结点* @return 若存在则返回下标,否则返回 -1*/public int getFirstNeighbor(int index) {for(int j = 0; j < vertexList.size(); j++) {if(edges[index][j] > 0) {return j;}}return -1;}/*** 根据前⼀个邻接结点的下标来获取下⼀个邻接结点 * @param v1* @param v2* @return 返回下标或者-1*/public int getNextNeighbor(int v1, int v2) {for(int j = v2 + 1; j < vertexList.size(); j++) {if(edges[v1][j] > 0) {return j;}}return -1;}/**** @param isVisited* @param i 第⼀次是0*/private void dfs(boolean[] isVisited, int i) {//⾸先我们访问该结点,输出System.out.print(getValueByIndex(i) + "->");//将结点设置为已经访问isVisited[i] = true;//查找结点i的第⼀个邻接结点wint w = getFirstNeighbor(i);while(w != -1) {//说明有if(!isVisited[w]) {dfs(isVisited, w);}//如果w结点已经被访问过w = getNextNeighbor(i, w);}}//dfs重载,遍历所有的结点,进⾏dfspublic void dfs() {isVisited = new boolean[vertexList.size()];//遍历所有的结点,进⾏dfs[回溯]for(int i = 0; i < getNumOfVertex(); i++) {if(!isVisited[i]) {dfs(isVisited, i);}}}/**** @param isVisited* @param i*/private void bfs(boolean[] isVisited, int i) {int u ; // 表⽰队列的头结点对应下标int w ; // 邻接结点w//队列,记录结点访问的顺序LinkedList queue = new LinkedList();//访问结点,输出结点信息System.out.print(getValueByIndex(i) + "=>");System.out.print(getValueByIndex(i) + "=>");//标记为已访问isVisited[i] = true;//将结点加⼊队列queue.addLast(i);while( !queue.isEmpty()) {//取出队列的头结点下标u = (Integer)queue.removeFirst();//得到第⼀个邻接结点的下标 ww = getFirstNeighbor(u);while(w != -1) {//找到//是否访问过if(!isVisited[w]) {System.out.print(getValueByIndex(w) + "=>");//标记已经访问isVisited[w] = true;//⼊队queue.addLast(w);}//以u为前驱点,找w后⾯的下⼀个邻结点w = getNextNeighbor(u, w); //体现出我们的⼴度优先 }}}//遍历所有结点public void bfs() {isVisited = new boolean[vertexList.size()];for (int i1 = 0; i1 < getNumOfVertex(); i1++) {if(!isVisited[i1]) {bfs(isVisited, i1);}}}//返回结点个数public int getNumOfVertex() {return vertexList.size();}//显⽰图对应的矩阵public void showGraph() {for (int[] ints : edges) {System.out.println(Arrays.toString(ints));}}//得到边的数⽬public int getNumOfEdges() {return numOfEdges;}//返回结点i(下标)对应的数据public String getValueByIndex(int i) {return vertexList.get(i);}//返回v1,v2的权值public int getWeight(int v1, int v2) {return edges[v1][v2];}//插⼊结点public void insertVertex(String vertex) {vertexList.add(vertex);}/*** 添加边* @param v1 表⽰点的下标:第⼏个顶点* @param v2 第⼆个结点对应的下标* @param weight 表⽰*/public void insertEdge(int v1, int v2, int weight) {public void insertEdge(int v1, int v2, int weight) {edges[v1][v2] = weight;edges[v2][v1] = weight;numOfEdges++;}}深度优先算法遍历顺序:1 -> 2 -> 4 -> 8 -> 5 -> 3 -> 6 -> 7⼴度优先算法遍历顺序:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8。
数据结构与算法课程设计报告---图的算法实现

数据结构与算法课程设计报告课程设计题目:图的算法实现专业班级:信息与计算科学1002班目录摘要 (1)1、引言 (1)2、需求分析 (1)3、概要设计 (2)4、详细设计 (4)5、程序设计 (10)6、运行结果 (18)7、总结体会 (19)摘要(题目): 图的算法实现实验内容图的算法实现问题描述:(1)将图的信息建立文件;(2)从文件读入图的信息,建立邻接矩阵和邻接表;(3)实现Prim、Kruskal、Dijkstra和拓扑排序算法。
关键字:邻接矩阵、Dijkstra和拓扑排序算法1.引言本次数据结构课程设计共完成图的存储结构的建立、Prim、Kruskal、Dijkstra 和拓扑排序算法等问题。
通过本次课程设计,可以巩固和加深对数据结构的理解,通过上机和程序调试,加深对课本知识的理解和熟练实践操作。
(1)通过本课程的学习,能够熟练掌握数据结构中图的几种基本操作;(2)能针对给定题目,选择相应的数据结构,分析并设计算法,进而给出问题的正确求解过程并编写代码实现。
使用语言:CPrim算法思想:从连通网N={V,E}中的某一顶点v0出发,选择与它关联的具有最小权值的边(v0,v),将其顶点加入到生成树的顶点集合V中。
以后每一步从一个顶点在V中,而另一个顶点不在V中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合V中。
如此继续下去,直到网中的所有顶点都加入到生成树顶点集合V中为止。
拓扑排序算法思想:1、从有向图中选取一个没有前驱的顶点,并输出之;2、从有向图中删去此顶点以及所有以它为尾的弧;重复上述两步,直至图空,或者图不空但找不到无前驱的顶点为止。
没有前驱-- 入度为零,删除顶点及以它为尾的弧-- 弧头顶点的入度减1。
2.需求分析1、通过键盘输入建立一个新的有向带权图,建立相应的文件;2、对建立的有向带权图进行处理,要求具有如下功能:(1)用邻接矩阵和邻接表的存储结构输出该有向带权图,并生成相应的输出结果;(2)用Prim、Kruskal算法实现对图的最小生成树的求解,并输出相应的输出结果;(3)用Dijkstra算法实现对图中从某个源点到其余各顶点的最短路径的求解,并输出相应的输出结果;(4)实现该图的拓扑排序算法。
数据结构与算法学习知识网络图解

数据结构与算法学习知识网络图解在计算机科学与软件工程领域中,数据结构与算法是构建高效的软件系统和解决复杂问题的基础。
掌握数据结构与算法的知识是每个计算机专业人员的必备技能。
但是,由于其抽象性和复杂性,学习数据结构与算法常常被认为是困难的。
为了帮助读者更好地理解和掌握这一领域的知识,本文将通过图解的方式,简洁明了地呈现数据结构与算法的核心概念和关系。
一、数据结构的基础概念1. 线性结构线性结构是数据元素之间存在一对一的关系,线性表是其中最常见的一种形式。
线性表可以分为顺序存储结构和链式存储结构两种类型。
其中,顺序存储结构使用连续的内存空间存储数据元素,而链式存储结构使用指针将数据元素链接起来。
2. 树形结构树形结构是数据元素之间存在一对多的关系,树是其中最常见的一种形式。
树由根节点、分支节点和叶节点组成,分支节点连接多个子节点,叶节点没有子节点。
树可以进一步分为二叉树、平衡二叉树和二叉查找树等类型。
3. 图状结构图状结构是数据元素之间存在多对多的关系,图是其中最常见的一种形式。
图由顶点和边组成,边表示顶点之间的连接关系。
图可以分为有向图和无向图两种类型,有向图中的边具有方向性,而无向图中的边没有方向性。
二、常见数据结构的应用场景1. 数组数组是最简单的数据结构之一,可以用于存储同类型的元素,并通过下标进行访问。
数组在实现矩阵、向量和字符串等数据结构时被广泛应用。
2. 链表链表是一种线性结构,可以动态地分配内存空间。
链表在插入和删除元素时具有较好的性能,因此在实现栈、队列和哈希表等数据结构时常常使用链表。
3. 栈栈是一种先进后出(LIFO)的数据结构,可以用于实现函数调用、表达式求值和括号匹配等场景。
4. 队列队列是一种先进先出(FIFO)的数据结构,可以用于实现进程调度、消息传递和缓存管理等应用。
5. 树树可以用于构建文件系统、数据库索引和组织结构等复杂的数据结构。
6. 图图可以用于社交网络分析、路径规划和网络拓扑结构分析等领域。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法与数据结构课程设计报告系(院):计算机科学学院专业班级:教技1001姓名:李##学号: ******### 指导教师:***设计时间:2012.6.16 - 2012.6.24设计地点:4号楼2号机房目录一、设计方案 (1)二、实现过程以及代码 (2)三、测试 (20)四、结论和分析 (23)五、难点和收获 (23)一、 设计方案1.程序设计基本过程:拿到课程设计任务书,按照要求,需要设计有向图、有向网、无向图 、无向网四种图,以及邻接矩阵、邻接表两种数据存储结构,三层以上的显示菜单。
图的操作中又包含了有关线性表、栈和队列的基本操作。
由于显示菜单已给出,剩下的任务就是把函数写入其中。
2.程序流程图:预定义 定义结构体 定义变量 各种函数3.程序设计的原理:图的操作都是以两种存储结构为基础的:邻接矩阵存储结构和邻接表存储结构,如有向图,有向网,无向图,无向网的创建,其他的操作都是在四种图创建后才开始进行的。
所以,首先必须理解两种存储结构的定义。
图的邻接矩阵存储结构即图的数组表示法。
用两个数组分别存储数据元素(如顶点)的信息和数据元素之间的关系(如边或弧)的信息。
用邻接矩阵存储结构的图具有以下几点特征:(一):顶点数:vexnum ,边(弧)数:arcnum ,图的种类:kind ;(二):邻接矩阵:arcs(1顶点关系类型:adj 2相关信息:*info);(三):顶点向量(顶点名):vexs[];其优点是以二维数组表示有n 个顶点的图时,需存放n 个顶点的信息和n*n 条弧的信息存储量。
借助邻接矩阵容易判定任意两个顶点之间是否有边或弧相连,并容易求出各个顶点的度。
缺点是时间复杂度是O (n*n ),例如,构造一个具有n 个顶点和e 条边的无向网的时间复杂度为O (n*n+e*n )。
图的邻接表存储结构是图的一种链式存储结构。
对图中的每个顶点建立一个单链表,每个结点由三个域组成,邻接点域adjvex (弧尾在邻接表链表中的位序),链域nextarc (下一条弧),数据域info(权值)。
还要建立一个邻接表链表,用以存放顶点的data 和后继指针firstarc,表头结点以顺序结构的形式存储,便于随机访问任一顶点的单链表。
邻接表存储结构的优点在于其时间复杂度小。
树的深度优先搜索遍历类似于树的先根遍历,是树的先根遍历的推广。
从图中的某个顶点出发,访问此顶点,然后依次从该顶点出发深度优先搜索遍历图,直至图中所有与该顶点有关的路径都被访问到;此时图中若还有顶点未被访问到,则另选图中的一个未被访问的顶点作为起始点,重述上述过程,直至所有顶点都被访问到。
广度优先搜索遍历类似于树的按层次遍历的过程。
以某个顶点为起始顶点,由近至远,依次访问和该顶点有路径相通的且路径长度为1,2,3,······的顶点。
当图中所有顶点都被访问到后,就完成了图的广度优先搜索遍历。
求无向网的最小生成树问题有两种算法:Prima算法和Kruskal算法。
Prima算法是从网中的某个顶点出发,选择与该顶点有路径的所有顶点中路径最小的一条路径,从该最小路径的另一顶点出发,重复上述过程,直至图中所有顶点都被访问完成。
Kruskal算法是从网中找出所有路径最小的一条路径,记下已访问该路径的两个顶点,再次从图中找出剩下路径中的最小路径,重复上述过程,直至所有顶点都被访问完成,按访问的顺序依次输出各顶点,即构造了一棵最小生成树。
由某个集合上的一个偏序得到该集合的一个全序的操作就叫做拓扑排序。
拓扑排序的过程:(1)在有向图中选择一个没有前驱的顶点并输出;(2)在图中删除该顶点和所有以它为尾的弧。
重复上述两步,直至全部顶点均已输出,就得到了一个拓扑有序序列。
求关键路径的算法如下:(1)输入e条弧,建立AOE网的存储结构;(2)从源点v0出发,令ve[0]=0,按拓扑有序求其余各顶点的最早发生时间。
如果得到的拓扑有序序列中的顶点个数小于网中的顶点数,则说明网中存在环,不能求关键路径,算法终止;否则执行第三步。
(3)从汇点vn出发,令vl[n-1]=ve[n-1],按逆拓扑有序求其余各顶点的最迟发生时间vl[i];(4)根据各顶点的和值,求每条弧的最早开始时间e(s)和最迟开始时间e(s),若某条弧满足条件e(s)=l(s),则为关键活动。
从某个源点到其余各顶点的最短路径问题:若从v到vi有弧,则D[i]为弧上的权值,否则D[i]为无穷大。
显然,长度为D[j]=Min{D[i]|vi属于V}的路径就是从v出发的长度最短的一条路径。
二、实现过程以及代码当电脑运行程序的时候,界面会出现一个提示菜单:请输入你要进行操作的图类型的编码:1:有向图,2:有向网,3:无向图,4:无向网,请输入选择。
操作者根据自己的需要可输入相应的编码来进行操作。
如选择3,则将进入关于无向图的操作。
根据课设指导书要求,无向图有四个基本操作:构建邻接矩阵,构建邻接表,对已构建的邻接表进行深度遍历,对已构建的邻接表进行广度遍历,输出所有操作的结果。
第一步操作就是构建,程序会提示你进行下一步操作,然后再根据各操作提示从外部输入顶点和弧的相关信息。
其他三个图的操作基本与本图的操作时一致的。
代码:#include <stdio.h>#include<stdlib.h>#include<limits.h>#define ERROR 0#define OK 1#define INFINITY INT_MAX#define MAX_VERTEX_NUM 21#define STACK_INIT_SIZE 100#define STACKINCREAMENT 10typedef enum{DG,DN,UDG,UDN}GraphKind;typedef struct ArcCell {int adj;//infotype *info;}ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; typedef struct{char vexs[MAX_VERTEX_NUM];AdjMatrix arcs;int vexnum,arcnum;GraphKind kind;}MGraph; //邻接矩阵typedef struct ArcNode{int adjvex;int quan;struct ArcNode *nextarc;}ArcNode,*AList;typedef struct VNode {char data;AList firstarc;}VNode,AdjList[MAX_VERTEX_NUM];typedef struct{AdjList vertices;int vexnum,arcnum;GraphKind kind;}ALGraph; //邻接表typedef struct QNode{char data;struct QNode *next;}QNode,*QueuePre;typedef struct{QueuePre front;QueuePre rear;}LinkQueue; //队列typedef struct {int *base;int *top;int stacksize;}SqStack; //栈typedef struct {char adjvex;int lowcost;}closedges[MAX_VERTEX_NUM]; //求最小生成树中的辅助数组int option;int visited[MAX_VERTEX_NUM]; //顶点访问标记数组int indegree[MAX_VERTEX_NUM]; //顶点入度记录数组int ve[MAX_VERTEX_NUM]; //顶点权值记录数组int SetGraphKind(MGraph &G,int option){switch(option){case 1: G.kind=DG;break;case 2: G.kind=DN;break;case 3: G.kind=UDG;break;case 4: G.kind=UDN;break;default: return ERROR;}return OK;} //邻接矩阵类型设置int SetGraphKind(ALGraph &G,int option){switch(option){case 1: G.kind=DG;break;case 2: G.kind=DN;break;case 3: G.kind=UDG;break;case 4: G.kind=UDN;break;default: return ERROR;}return OK;} //邻接表类型设置int LocateVex(MGraph G,char v){int m;for(m=1;m<=G.vexnum;m++){if(G.vexs[m]==v) return m;}return ERROR;} //邻接矩阵顶点定位int LocateVex(ALGraph G,char v){int m;for(m=1;m<=G.vexnum;m++){if(G.vertices[m].data==v) return m;}printf("您输入的顶点不存在");return ERROR;} //邻接表顶点定位int InitQueue(LinkQueue &Q){Q.front=Q.rear=(QueuePre)malloc(sizeof(QNode));if(!Q.front) return ERROR;Q.front->next=NULL;return OK;} //队列创建int EnQueue(LinkQueue &Q,int e){QueuePre p;p=(QueuePre)malloc(sizeof(QNode));if(!p) return OK;p->data=e;p->next=NULL;Q.rear->next=p;Q.rear=p;return OK;} //元素入队列int DeQueue(LinkQueue &Q,int &e){QueuePre p;if(Q.front==Q.rear) return ERROR;p=Q.front->next;e=p->data;Q.front->next=p->next;if(Q.rear==p) Q.rear=Q.front;free(p);return OK;} //元素出队列int QueueEmpty(LinkQueue Q){if(Q.front==Q.rear)return OK;return ERROR;} //判断队列是否为空int InitStack(SqStack &S){S.base=(int*)malloc(STACK_INIT_SIZE*sizeof(int));if(!S.base) return ERROR;S.top=S.base;S.stacksize=STACK_INIT_SIZE;return OK;} //栈创建int Push(SqStack &S,int e){if(S.top-S.base>=S.stacksize){S.base=(int*)realloc(S.base,(S.stacksize+STACKINCREAMENT)*sizeof(int));if(!S.base) return ERROR;S.top=S.base+S.stacksize;S.stacksize+=STACKINCREAMENT;}*S.top++=e;return OK;} //元素入栈int Pop(SqStack &S,int &e){if(S.top==S.base) return ERROR;e=*--S.top;return OK;} //元素出栈int StackEmpty(SqStack S){if(S.top==S.base) return OK;return ERROR;} //判断栈是否为空int CreatGraph(MGraph &G){int i,j,k,w;char x,y;if(!SetGraphKind(G,option)) {printf("对图类型的设置失败");return ERROR;}printf("邻接矩阵:请输入定点的个数、弧的个数:");scanf("%d %d",&G.vexnum,&G.arcnum);if(G.vexnum>20){printf("您输入的顶点个数超过最大值");return ERROR;}printf("请输入%d个顶点\n",G.vexnum);for(i=1;i<=G.vexnum;++i) {fflush(stdin); scanf("%c",&G.vexs[i]);}if(G.kind==DG||G.kind==UDG){for(i=1;i<=G.vexnum;i++)for(j=1;j<=G.vexnum;j++)G.arcs[i][j].adj=0;if(G.kind==DG){printf("请输入有向图的两个相邻的顶点<x,y>(如果互相邻接则<x,y>也要输入):\n");for(k=1;k<=G.arcnum;k++){fflush(stdin);scanf("%c%c",&x,&y);i=LocateVex(G,x);j=LocateVex(G,y);G.arcs[i][j].adj=1;}}else{printf("请输入无向图的两个相邻的顶点(x,y):\n");for(k=1;k<=G.arcnum;k++){fflush(stdin);scanf("%c%c",&x,&y);i=LocateVex(G,x); j=LocateVex(G,y);G.arcs[i][j].adj=1; G.arcs[j][i].adj=G.arcs[i][j].adj;}}}else{for(i=1;i<=G.vexnum;i++)for(j=1;j<=G.vexnum;j++)G.arcs[i][j].adj=INT_MAX;if(G.kind==DN){printf("请输入有向网的两个相邻的顶点<x,y>以及相应的权值w(如果互相邻接则<y,x>也要输入):\n");for(k=1;k<=G.arcnum;k++){fflush(stdin);scanf("%c%c %d",&x,&y,&w);i=LocateVex(G,x); j=LocateVex(G,y);G.arcs[i][j].adj=w;}}else{printf("请输入无向网的两个相邻的顶点(x,y)以及相应的权值w:\n");for(k=1;k<=G.arcnum;k++){fflush(stdin);scanf("%c%c %d",&x,&y,&w);i=LocateVex(G,x); j=LocateVex(G,y);G.arcs[i][j].adj=w; G.arcs[j][i].adj=G.arcs[i][j].adj;}}}return OK;} //创建邻接矩阵int CreatAList(ALGraph &G){int i,j,m,n,key[MAX_VERTEX_NUM]; char x,y,w;AList p,q;SetGraphKind(G,option);printf("邻接表:请输入顶点的个数和弧的个数:");scanf("%d %d",&G.vexnum ,&G.arcnum);if(G.vexnum>20){printf("您输入的顶点个数超过最大值");return ERROR;}printf("请输入个顶点:\n");for(i=1;i<=G.vexnum;i++){fflush(stdin);scanf("%c",&G.vertices[i].data);G.vertices[i].firstarc=NULL;key[i]=0;}if(G.kind==DG){printf("请输入弧(如AB,其中AB与BA是不同的弧):\n");for(j=1;j<=G.arcnum;j++){fflush(stdin);scanf("%c%c",&x,&y);m=LocateVex(G,x);n=LocateVex(G,y);p=G.vertices[m].firstarc;q=(AList)malloc(sizeof(ArcNode));if(!q) return ERROR;q->nextarc=NULL;q->adjvex=n;while(key[m]&&p->nextarc){p=p->nextarc;key[m]++;}if(!key[m]){G.vertices[m].firstarc=q;key[m]++;}else p->nextarc=q;}}if(G.kind==UDG){printf("请输入弧(如AB,其中AB与BA是不同的弧):\n");for(j=1;j<=2*G.arcnum;j++){fflush(stdin);scanf("%c%c",&x,&y);m=LocateVex(G,x);n=LocateVex(G,y);p=G.vertices[m].firstarc;q=(AList)malloc(sizeof(ArcNode));if(!q) return ERROR;q->nextarc=NULL;q->adjvex=n;while(key[m]&&p->nextarc){p=p->nextarc;key[m]++;}if(!key[m]){G.vertices[m].firstarc=q;key[m]++;}else p->nextarc=q;}}if(G.kind==DN){printf("请输入依次输入弧以及这条弧的权值(如AB 8,其中AB与BA是不同的弧):\n");for(j=1;j<=G.arcnum;j++){fflush(stdin);scanf("%c%c %d",&x,&y,&w);m=LocateVex(G,x);n=LocateVex(G,y);p=G.vertices[m].firstarc;q=(AList)malloc(sizeof(ArcNode));if(!q) return ERROR;q->nextarc=NULL;q->quan=w;q->adjvex=n;while(key[m]&&p->nextarc){p=p->nextarc;key[m]++;}if(!key[m]){G.vertices[m].firstarc=q;key[m]++;}else p->nextarc=q ;}}if(G.kind==UDN){printf("请输入依次输入弧以及这条弧的权值(如AB 8,其中AB与BA是不同的弧):\n");for(j=1;j<=2*G.arcnum;j++){fflush(stdin);scanf("%c%c %d",&x,&y,&w);m=LocateVex(G,x);n=LocateVex(G,y);p=G.vertices[m].firstarc;q=(AList)malloc(sizeof(ArcNode));if(!q) return ERROR;q->nextarc=NULL;q->quan=w;q->adjvex=n;while(key[m]&&p->nextarc){p=p->nextarc;key[m]++;}if(!key[m]){G.vertices[m].firstarc=q;key[m]++;}else p->nextarc=q ;}}return OK;} //创建邻接表int FirstAdjVex(ALGraph G,int v){if(G.vertices[v].firstarc)return G.vertices[v].firstarc->adjvex;return 0;}int NextAdjVex(ALGraph G,int v,int w){AList s;s=G.vertices[v].firstarc;while(s->adjvex!=w)s=s->nextarc;if(s->nextarc)return s->nextarc->adjvex;return 0;}void DFS(ALGraph G,int v){int w;visited[v]=1; printf("%c ",G.vertices[v]);for(w=FirstAdjVex(G,v);w>=1;w=NextAdjVex(G,v,w)){ if(!visited[w]) DFS(G,w);}}void DFSTraverse(ALGraph G){int v;visited[0]=1;for(v=1;v<=G.vexnum;v++) visited[v]=0;for(v=1;v<=G.vexnum;v++)if(!visited[v]) DFS(G,v);} //图的深度遍历void BFSTraverse(ALGraph G){int v,w,u;LinkQueue Q;for(v=1;v<=G.vexnum;v++) visited[v]=0;visited[0]=1;InitQueue(Q);for(v=1;v<=G.vexnum;v++)if(!visited[v]){visited[v]=1;printf("%c ",G.vertices[v]);EnQueue(Q,v);while(!QueueEmpty(Q)){DeQueue(Q,u);for(w=FirstAdjVex(G,u);w>=1;w=NextAdjVex(G,u,w)){if(!visited[w]){visited[w]=1;printf("%c ",G.vertices[w]);EnQueue(Q,w);}else break;}}}} //图的广度遍历void FindInDegree(ALGraph G,int in[]){int i,j,k;AList p;for(k=1;k<=G.vexnum;k++) in[k]=0;for(i=1;i<=G.vexnum;i++){p=G.vertices[i].firstarc;while(p){j=p->adjvex;in[j]++;p=p->nextarc;}}} //计算各顶点入度int TopologicalSort(ALGraph G){int i,k,count;AList p;SqStack S;FindInDegree(G,indegree);InitStack(S);for(i=1;i<=G.vexnum;i++)if(!indegree[i]) Push(S,i);count=0;if(StackEmpty(S)) printf("此有向图不符合条件!");while(!StackEmpty(S)){Pop(S,i);printf("%c ",G.vertices[i].data);++count;for(p=G.vertices[i].firstarc;p;p=p->nextarc){k=p->adjvex;if(!(--indegree[k])) Push(S,k);}}if(count<=G.vexnum) return ERROR;else return OK;} //拓扑排序int Minimum(MGraph G,closedges m){int i,j,min=INFINITY;for(i=1;i<=G.vexnum;i++){if(m[i].lowcost){if(m[i].lowcost<min){min=m[i].lowcost;j=i;}}}return j;}void MinSpanTree_PRIM(MGraph G,char u){int i,j,k;closedges closedge;k=LocateVex(G,u);for(j=1;j<=G.vexnum;j++)if(j!=k) {closedge[j].adjvex=u;closedge[j].lowcost=G.arcs[k][j].adj;}closedge[k].lowcost=0;for(i=2;i<=G.vexnum;i++){k=Minimum(G,closedge);printf("%c%c ",closedge[k].adjvex,G.vexs[k]);closedge[k].lowcost=0;for(j=1;j<=G.vexnum;j++)if(G.arcs[k][j].adj<closedge[j].lowcost){closedge[j].adjvex=G.vexs[k];closedge[j].lowcost=G.arcs[k][j].adj;}}} //求最小生成树int TopologicalOrder(ALGraph G,SqStack &T){int i,j,k,count; SqStack S; AList p;FindInDegree(G,indegree);InitStack(S);for(i=1;i<=G.vexnum;i++)if(!indegree[i]) Push(S,i);InitStack(T);count=1;for(i=1;i<=G.vexnum;i++) ve[i]=0;while(!StackEmpty(S)){Pop(S,j);Push(T,j);++count;for(p=G.vertices[j].firstarc;p;p=p->nextarc){k=p->adjvex;if(--indegree[k]==0) Push(S,k);if(ve[j]+p->quan>ve[k]) ve[k]=ve[j]+p->quan;}}if(count<=G.vexnum) return ERROR;else return OK;}int CriticalPath(ALGraph G){int i,j,k,ee,el,dut,v1[MAX_VERTEX_NUM]; SqStack T; AList p; char tag;if(!TopologicalOrder(G,T)) return ERROR;for(i=1;i<=G.vexnum;i++){v1[i]=ve[G.vexnum];}while(!StackEmpty(T))for(Pop(T,j),p=G.vertices[j].firstarc;p;p=p->nextarc){k=p->adjvex;dut=p->quan;if(v1[k]-dut<v1[j]) v1[j]=v1[k]-dut;}for(j=1;j<=G.vexnum;j++)for(p=G.vertices[j].firstarc;p;p=p->nextarc){k=p->adjvex;dut=p->quan;ee=ve[j];el=v1[k]-dut;tag=(ee==el)?'*':' ';printf("%d %d %d %d %d %c\n",j,k,dut,ee,el,tag);}return OK;} //求关键路径void DG_(MGraph G1,ALGraph G2){int i,j,k,m,key;AList s;printf("**************************\n");printf("你选择了对有向图的基本操作及应用:\n1创建邻接矩阵\n2创建邻接表\n3拓扑结构\n4退出\n");printf("**************************\n");for(k=0;;){key=0;printf("请选择:");scanf("%d",&m);switch(m){case 1: CreatGraph(G1);printf("有向图的邻接矩阵:\n");for(i=1;i<=G1.vexnum;i++){for(j=1;j<=G1.vexnum;j++){printf(" %d",G1.arcs[i][j].adj);}printf("\n");}break;case 2: CreatAList(G2);printf("有向图的邻接表:\n");for(i=1;i<=G2.vexnum;i++){printf("%c:",G2.vertices[i]);s=G2.vertices[i].firstarc;while(s){j=s->adjvex;fflush(stdin);printf("<%c ",G2.vertices[i]);printf("%c> ",G2.vertices[j]);s=s->nextarc;}printf("\n");}break;case 3:printf("有向图的拓扑排序:\n");TopologicalSort(G2);break;case 4:key=1;break;}printf("\n");if(key) break;}printf("\n\n");} //DGvoid UDG_(MGraph G1,ALGraph G2){int i,j,k,m,key;AList s;printf("**************************\n");printf("你选择了对有向网的基本操作及应用:\n1创建邻接矩阵\n2创建邻接表\n3关键路径\n4退出\n");printf("**************************\n");for(k=0;;){key=0;printf("请选择:");scanf("%d",&m);switch(m){case 1: CreatGraph(G1); printf("有向网的邻接矩阵:\n");for(i=1;i<=G1.vexnum;i++){for(j=1;j<=G1.vexnum;j++){if(G1.arcs[i][j].adj==INT_MAX)printf(" #");else printf(" %d",G1.arcs[i][j].adj);}printf("\n");}break;case 2: CreatAList(G2); printf("有向网的邻接表:\n");for(i=1;i<=G2.vexnum;i++){printf("%c:",G2.vertices[i]);s=G2.vertices[i].firstarc;while(s){j=s->adjvex;fflush(stdin);printf("<%c ",G2.vertices[i]);printf("%c> ",G2.vertices[j]);printf(" %d ",s->quan);s=s->nextarc;}printf("\n");}break;case 3: printf("有向网关键路径:\n");CriticalPath(G2);break;case 4: key=1;break;}printf("\n");if(key) break;}printf("\n\n");} //DNvoid DN_(MGraph G1,ALGraph G2){int i,j,k,m,key;AList s;printf("**************************\n");printf("你选择了对无向图的基本操作及应用:\n1创建邻接矩阵\n2创建邻接表\n3深度遍历\n4广度遍历\n5退出\n");printf("**************************\n");for(k=0;;){key=0;printf("请选择:");scanf("%d",&m);switch(m){case 1:CreatGraph(G1); printf("无向图的邻接矩阵:\n");for(i=1;i<=G1.vexnum;i++){for(j=1;j<=G1.vexnum;j++){printf(" %d",G1.arcs[i][j].adj);}printf("\n");}break;case 2: CreatAList(G2); printf("无向图的邻接表:\n");for(i=1;i<=G2.vexnum;i++){printf("%c:",G2.vertices[i]);s=G2.vertices[i].firstarc;while(s){j=s->adjvex;fflush(stdin);printf("(%c ",G2.vertices[i]);printf("%c) ",G2.vertices[j]);s=s->nextarc;}printf("\n");}break;case 3: printf("无向图的深度优先遍历:\n");DFSTraverse(G2);printf("\n");break;case 4: printf("无向图的广度优先遍历:\n");BFSTraverse(G2);break;case 5: key=1;break;}printf("\n");if(key) break;}printf("\n\n");} //UDGvoid UDN_(MGraph G1,ALGraph G2){int i,j,m,k,key;AList s;char u;printf("**********************************\n");printf("你选择了对无向网的基本操作及应用:\n1创建邻接矩阵\n2创建邻接表\n3最小生成树\n4退出\n");printf("**********************************\n");for(k=0;;){key=0;printf("请选择:");scanf("%d",&m);switch(m){case 1: CreatGraph(G1); printf("无向网的邻接矩阵:\n");for(i=1;i<=G1.vexnum;i++){for(j=1;j<=G1.vexnum;j++){if(G1.arcs[i][j].adj==INT_MAX)printf(" #");else printf(" %d",G1.arcs[i][j].adj);}printf("\n");}break;case 2: CreatAList(G2); printf("无向网的邻接表:\n");for(i=1;i<=G2.vexnum;i++){printf("%c:",G2.vertices[i]);s=G2.vertices[i].firstarc;while(s){j=s->adjvex;fflush(stdin);printf("(%c ",G2.vertices[i]);printf("%c)",G2.vertices[j]);printf(" %d ",s->quan);s=s->nextarc;}printf("\n");}break;case 3: printf("请输入第一个顶点:");fflush(stdin);scanf("%c",&u);printf("无向网的最小生成树:\n");MinSpanTree_PRIM(G1,u);break;case 4: key=1;break;}printf("\n");if(key) break;}printf("\n\n");} //UDNvoid main(){MGraph G1;ALGraph G2;int i,n;for(i=0;;){n=0;printf("\n");printf("**************图的基本操作及应用***************\n1:有向图的基本操作及应用\n2:无向图的基本操作及应用\n3:有向网的基本操作及应用\n4:无向网的基本操作及应用\n5: 退出\n");printf("********************************\n");printf("请选择:");scanf("%d",&option);printf("\n\n");switch(option){case 1: DG_(G1,G2);break;case 2: DN_(G1,G2);break;case 3: UDG_(G1,G2);break;case 4: UDN_(G1,G2);break;case 5: n=1;break;default: printf("你输入的编码有误!"); break;}if(n) break;printf("\n\n");}}三、测试菜单有向图内部菜单有向图邻接矩阵有向图邻接表以及拓扑结构无向网的基本操作无向网邻接矩阵及最小生成树四、结论和分析整个程序最关键和最基本的是对图四种类型的邻接矩阵和邻接表的创建。