数据结构--图重点
一、定义与术语
图:无序数据结构
基本构成:1.边集(Edge ):a. 有向图,有向边
b. 无向图,无向边(v, w),权值
2.顶点集(Vertices ):a. 无向图:度(TD(v))
b. 有向图:出度(ID(v)),入度(OD(v)),度(TD(v) = ID(v) + OD(v))
无向完全图:n 个顶点,(1)2
n n -条边 有向完全图:n 个顶点,(1)n n -条边
网:带权图
连通分量:无向图中的极大连通子图(多个),无向完全图的连通分量就是本身(一个) 强连通分量:有向图中的极大连通子图,其中i v 到j v 以及j v 到i v 都有路径
生成树:图的极小连通子图,含有图的全部n 个顶点,只有n-1条边,少一条则不能连通,
多一条则形成回路
生成森林:不完全图中的各个连通分量的生成树,构成图的生成森林
二、存储结构
顶点:可采用链表或数组存储顶点列表,一般采用链表存储
边:1. 邻接矩阵(数组)
a. 无向图:对称阵,可采用矩阵压缩存储方式。A[i][j] = 0表示i v 和j v 没有连接;
A[i][j] = 1表示i v 和j v 有边连接;第i 行的和表示顶点i v 的度
b. 有向图:不对称阵。,[][]i j A i j w =表示顶点i v 到j v 的有向弧的权值;[][]A i j =∞
表示表示顶点i v 到j v 没有弧连接或者i = j
2. 邻接表(链表,有向无向都可用)
边结点:adjvex (邻接点),nextarc (下一条边),info (权值)
顶点结点:data (顶点数据),firstarc (第一条边)
3. 十字链表(Othogonal List )
弧结点:tailvex (弧尾结点),headvex (弧头结点),tlink (弧尾相同的下一条弧),hlink
(弧头相同的下一条弧),info (权值)
顶点结点:data (顶点数据),firstin (第一条入弧),firstout (第一条出弧)
三、图的遍历(每个顶点只被访问一次)
1. 深度优先遍历(类似树的先根遍历)
基本思想:假设初始状态是图中所有顶点未曾被访问,则深度优先搜索可从图中某个顶
点v 出发,访问此结点,然后依次从v 的未被访问的邻接点出发深度优先遍
历图,直至图中所有和v 有路径相通的顶点都被访问到;若此时图中尚有顶
点未被访问(非连通图),则另选图中一个未曾被访问的顶点作起始点,重
复上述过程,直至图中所有顶点都被访问到为止。
代码:
void DFS(Graph& G, int v, bool first, bool visited[]) {
visit(getValue(G, v));
visited[v] = true;
int = getFirstNeighbor(G, v);
while(w != -1) {
if(!visited[w]) DFS(G, w, visited);
w = getNextNeighbor(G, v, w);
}
}
2. 广度优先搜索(类似于树的层次遍历)
基本思想:假设从图中某顶点v出发,在访问了v之后依次访问v的各个未曾访问过的邻接点,然后分别从这些邻接点出发依次访问它们的邻接点,并使“先被访问的顶点
的邻接点”先于“后被访问的顶点的邻接点”被访问,直至图中所有已被访问的
顶点的邻接点都被访问到。若此时图中尚有顶点未被访问(非连通图),则另选图
中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问
到为止。
代码:
viod BFS(Graph& G, int v) {
int i, w, n = G.vexnum;
bool* visited = new bool[n];
for(i = 0; i < n; i++) visited[i] = false;
visit(getValue(G, v));
visited[v] = true;
Queue Q; initQueue(Q); enQueue(Q, v);
while (!isEmpty(Q)) {
deQueue(Q, v);
w = getFirstNeighbor(G, v);
while (w != -1) {
if (!visited[w]) {
visit(getValue(G, w));
enQueue(Q, w);
}
w = getNextNeighbor(G, v, w);
}
}
delete[] visited;
}
四、图的连通性问题(无向图)
1. 深度优先生成树(深度优先搜索形成),广度优先生成树(广度优先搜索形成)
深度优先生成森林算法:
void DFSForest(Graph G, CSTree& T) {
CSTree q = null;
int n = G.vexnum;
bool* visited = new bool[n];
for (int i = 0; i < n; i++) visited[i] = false;
for (int v = 0; v < n; v++) {
if (!visited[v]) {
CSTree p = (CSTree) malloc(sizeof(CSNode));
*p = {getValue(G, v), null, null};
if (T == null) T = p;
else q->nextSibling = p;
q = p;
DFSTree(G, v, p, visited);
}
}
}
深度优先生成树算法:
void DFSTree(Graph G, int v, CSTree T, bool& visited[]) {
visited[v] = true;
bool first = true;
CSTree q = null;
for (int w = getFirstNeighbor(G, v); w != -1; w = getNextNeighbor(G, v, w))
if (!visited[w]) {
CSTree p = (CSTree) malloc(sizeof(CSNode));
*p = {getValue(G, w), null, null};
if (first) {
T->lchild = p;
first = false;
}
else q->nextSibling = p;
q = p;
DFSTree(G, w, q, visited);
}
}
2. 最小生成树(Mini Cost Spanning Tree,MST)
定义:一棵生成树的代价就是树上各边的代价之和,最小生成树就是代价最小的生成树MST性质:假设N = (V, {E})是个连通网,U是顶点集V的一个非空子集。若(u, v)是一条具有最小权值(代价)的边,其中u∈U,v∈V-U,则必存在一棵包含边(u, v)的
最小生成树。
a. Prim 算法
基本思想:假设N = (V , {E})是连通网,TE 是N 上最小生成树中边的集合。算法从
00{}()U u u V =∈,{}TE =开始,重复执行下述操作:在所有u ∈U ,v ∈V-U
的边(u, v)∈E 中找一条代价最小的边00(,)u v 并入集合TE ,同时0v 并入U ,直
至U=V 为止。此时VE 必有n-1条边,则T=(V, {TE})为N 的最小生成树。为了
实现这个算法需要引入一个辅助数组closedge ,记录从U 到V-U 具有最小代价
的边。对每个顶点i v V U ∈-,在辅助数组中存在一个相应的分量
closedge[i-1],它包括两个域,其中lowcost 存储该边上的权。显然
closedge[i-1].lowcost = Min{cost(u, i v )|u ∈U}。vex 域存储该边依附的在
U 中的顶点。
算法分析:时间复杂度2()O n ,与网中边数无关,适用于求边稠密的网的最小生成树。 代码:
void miniSpanTree_Prim(Graph G, VertexType u) {
int n = G.vexnum;
// gain vertex index
int k = locateVex(G, u);
// initialize auxiliary array
struct {
VertexType adjvex;
VRType lowcost;
} closedge[n];
for (int i = 0; i < n; i++)
if (i != k) closedge[i] = {u, G.arcs[k][j].adj};
closedge[k].lowcost = 0;
for (int i = 0; i < n; i++) {
// find the edge with minimum cost, and meanwhile,
// one vertex belongs to U, the other belongs to V-U
k = minimum(closedge);
// closedge[k].adjvex: u belongs to U
// G.vexs[k]: v belongs to V-U
printf(closedge[k].adjvex, G.vexs[k]);
// add v to U
closedge[k].lowcost = 0;
// modify closedge, reselect minimum edge
for (int j = 0; j < G.vexnum; j++)
if (G.arcs[k][j] < closedge[j].lowcost)
closedge[j] = { G.vexs[k], G.arcs[k][j].adj};
}
}
b. Kruskal算法
基本思想:假设连通网N = (V, {E}),则令最小生成树的初始状态为只有n个顶点而无边的非连通图T = (V, {}),图中每个顶点自成一个连通分量。在E中选择代价最小的
边,若该边依附的顶点落在T中不同的连通分量上(该条件保证了不可能产生
回路,可使用并查集的Find与Union函数实现),则将此边加入到T中,否则
舍去此边而选择下一条代价最小的边。依次类推,直至T中所有的顶点都在同
一连通分量上为止。
O e e(e为网中边的数目),适用于求边稀疏的网的最小生成树。算法分析:时间复杂度(log)
3. 关节点和重连通分量
关节点(割点):假若在删去顶点v以及和v相关联的各边之后,将图的一个连通分量分割成两个或两个以上的连通分量,则称顶点v为该图的一个关节点。
重连通图:没有关节点的连通图称为重连通图。
连通度:若在连通图上至少删去k个顶点才能破坏图的连通性,则称此图的连通度为k。由此可知生成树的连通度为1。
关节点特性:a. 若生成树的根有多棵子树,则此根顶点必为关节点;
b. 若生成树中某个非叶子顶点v,其某棵子树的根和子树中的其他结点均没有
指向v的祖先的回边,则v为关节点。
五、有向无环图及其应用
1. 拓扑排序(工程能否顺利进行)
定义:由某个集合上的偏序得到该集合上的一个全序,偏序指集合中仅有部分成员之间可比较,而全序指集合中全体成员之间均可比较。
用途:一个表示偏序的有向图可用来表示一个流程图,图中每一条有向边表示两个子工程之间的次序关系(领先关系)。
AOV-网:用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网(Activity On Vertex Network),从顶点i到顶点j有一条有向路径,则i是j的前
驱,j是i的后继。
条件:在AOV-网中,不应该出现有向环,因为存在环意味着某项活动应以自己为先决条件。
检测的办法是对有向图构造其顶点的拓扑有序序列,若网中所有顶点都在它的拓
扑有序序列中,则该AOV-网中必定不存在环。
基本思想:a. 在有向图中选一个没有前驱的顶点且输出之
b. 从图中删除该顶点和所有以它为尾的弧
c. 重复上述两步,直至全部顶点均已输出(无环),或者当前图中不存在无前驱
的顶点为止(有环)。
代码:使用邻接表作为有向图的存储结构,使用辅助数组indegree存放每个顶点的入度,入度为0的顶点即为没有前驱的顶点,删除顶点及以它为尾的弧的操作,则可换以弧头顶点的入度减1来实现。
Status topologicalSort(Graph G) {
int i, n = G.vexnum;
int* indegree = new int[n];
findInDegree(G, indegree);
Stack S;
initStack(S);
for (i = 0; i < n; i++)
if (!indegree[i]) push(S, i);
int count = 0;
while (!isEmpty(s)) {
pop(S, i);
printf(i, G .vexs[i].data);
count++;
for (ArcNode p = G .vexs[i].firstArc; p; p = p->nextArc) {
int k = p->adjVex;
if (!(--indegree[k])) push(S, k);
}
}
if (count < n) return ERROR;
else return OK;
}
2. 关键路径(估算整个工程完成所必须的最短时间)
AOE-网:Activity On Edge ,是一个带权的有向无环图,其中,顶点表示事件(Event ),弧
表示活动,权表示活动持续的时间。
源点:在正常情况下(无环),网中只有一个入度为0的点,称作源点。
汇点:在正常情况下(无环),网中只有一个出度为0的点,称作汇点。
关键路径:完成工程的最短时间是从源点到汇点的最长路径的长度(活动持续时间最长),
整个最长路径就叫做关键路径。
最早发生/开始时间:假设源点是1v ,从1v 到i v 的最长路径长度叫做事件i v 的最早发生时间,
这个时间决定了所有以i v 为尾的弧所表示的活动的最早开始时间。
最迟发生/开始时间:这是在不推迟整个工程完成的前提下,活动i a 最迟必须开始进行的时
间。
时间余量:()()l i e i -,意味着完成活动i a 的时间余量。
关键活动:()()l i e i =的活动,关键路径上的所有活动都是关键活动,因此提前完成非关键
活动并不能加快工程的进度。
基本思想:如果活动i a 由弧
弧:()()ee i ve i =,()()(,)el i vl k dut j k =-<>,
顶点:(1)从ve(0) = 0(源点)开始向前递推(拓扑有序)
(){()(,)},,,1,2,...,1i
ve j Max ve i dut i j i j T j n =+<><>∈=- 其中T 是所有以第j 个顶点为头的弧的集合
(2)从vl(n-1) = ve(n-1)(汇点)起向后递推(逆拓扑有序)
(){()(,)},,,2, 0
vl i Min vl j dut i j i j S i n =-<><>∈=- 其中S 是所有以第i 个顶点为尾的弧的集合
算法步骤:
(1)输入e 条弧,建立AOE-网的存储结构
(2)从源点0v 出发,令ve[0] = 0,按拓扑有序求其余各顶点的最早发生时间ve[i](i ∈[1,
n-1])。如果得到的拓扑有序序列中顶点个数小于网中顶点数n ,则说明网中存在环,不能求关键路径,算法终止;否则执行步骤(3)
(3)从汇点n v 出发,令vl[n-1] = ve[n-1],按逆拓扑有序求其余各顶点的最迟发生时间vl[i]
(i ∈[n-2, 2])
(4)根据各顶点的ve 值和vl 值,求每条弧s 的最早开始时间ee(s)和最迟开始时间el(s)。
若某条弧满足条件ee(s) = el(s),则为关键活动
代码:
Status topologicalOrder(Graph G , Stack& T, int& *ve) {
int i, n = G.vexnum, count = 0;
int* indegree = new int[n];
findInDegree(G , indegree);
Stack S;
initStack(S);
for (i = 0; i < n; i++) {
if (!indegree[i]) push(S, i);
}
while (!isEmpty(S)) {
pop(S, i);
push(T, i);
count++;
for (ArcNode p = G .vexs[i].firstArc; p; p = p->nextArc) {
int k = p->adjVex;
if (!(--indegree[k])) push(S, k);
if (ve[i] + p->info > ve[k]) ve[k] = ve[i] + p->info;
}
}
if (count < n) return ERROR;
else return OK;
}
Status criticalPath(Graph G) {
int i, n = G.vexnum;
Stack T;
initStack(T);
int* ve = new int[n];
for (i = 0; i < n; i++) ve[i] = 0;
if (!topologicalOrder(G , T, ve) return ERROR;
int* vl = new int[n];
for (i = 0; i < n; i++) vl[i] = ve[n-1];
while (!isEmpty(T)) {
pop(T, i);
for (ArcNode p = G .vexs[i].firstArc; p; p = p->nextArc)
int k = p->adjVex;
if (vl[k] – p->info < vl[i]) vl[i] = vl[k] – p->info;
}
for (i = 0; i < n; i++)
for (ArcNode p = G .vexs[i].firstArc; p; p = p->nextArc) {
int k = p->adjVex;
int ee = ve[i];
int el = vl[k] – p->info;
tag = (ee == el) ? ‘*’ : ‘’;
printf(i, k, p->info,ee, el, tag);
}
}
算法分析:时间复杂度为()O n e -,只有在不改变网的关键路径的情况下,提高关键活动
的速度才有效。
六、最短路径(有向图)
1. 单源点最短路径问题
问题描述:给定带权有向图G 和源点v ,求从v 到G 中其余各顶点的最短路径。 算法描述:引进辅助向量D ,每个分量D[i]表示当前所找到的从源点v 到每个终点i v 的最短
路径长度。它的初态为:若从v 到i v 有弧,则D[i]为弧上的权值;否则置D[i]为∞。显然,长度为[]{[]|}i i
D j Min D i v V =∈的路径就是从v 出发的长度最短的一条最短路径,此路径为(,)j v v 。假设S 为已求得最短路径的终点的集合,则下一条最短路径(设其终点为x )或者是弧(v, x),或者是中间只经过S 中的顶点而最后到达顶点x 的路径,所以下一条长度次短的最短路径的长度必是
[]{[]|}i i
D j Min D i v V S =∈-,其中()D i 或者是弧(,)i v v 上的权值,或者是()()k D k v S ∈和弧(,)k i v v 上的权值之和。
算法步骤:
(1)假设用带权的邻接矩阵arcs 来表示带权有向图,arcs[i][j]表示弧,i j v v <>上的权值。
若,i j v v <>不存在,则置arcs[i][j]为∞(在计算机上可用允许的最大值代替)。S 为已
找到从v 出发的最短路径的终点的集合,它的初始状态为空集。那么,从v 出发到图上其余各顶点(终点)i v 可能达到的最短路径长度的初值为:[][(,)][],i D i a r c s L o c a t e V e x G v i v V
=∈ (2)选择j v ,使得[]{[]|}i D j Min D i v V S =∈-,其中j v 就是当前求得的一条从v 出发
的最短路径的终点。令{}S S j =
(3)修改从v 出发到集合V-S 上任一顶点k v 可达的最短路径长度。如果D[j] + arcs[j][k] <
D[k],则修改D[k]为D[k] = D[j] + arcs[j][k]
(4)重复操作(2)、(3)共n-1次。由此求得从v 到图上其余各顶点的最短路径是依路径
长度递增的序列
Dijkstra 算法代码:
void shortestPath_Dij(Graph G , int v0, PathMatrix& P, ShortPathTable& D) {
// D: each element stores the shortest path that each vertex connects to v0
// P: if P[v][w] is true, that means the shortest path from v0 to v contains vertex w
// initialize P and D
for (v = 0; v < G .vexnum; v++) {
final[v] = false;
D[v] = G .arcs[v0][v];
for (w = 0; w < G .vexnum; w++) P[v][w] = false;
if (D[v] < INFINITY) {
P[v][v0] = true;
P[v][v] = true;
}
}
// start processing
D[v0] = 0;
final[v0] = true;
for (i = 1; i < G .vexnum; i++) {
min = INFINITY;
// get the nearest v that directly connects to v0
for (w = 0; w < G .vexnum; w++)
if (!final[w]) // if w belongs to V-S
if (D[w] < min) {
v = w;
min = D[w];
}
final[v] = true; // add v to S
// modify D and P
for (w = 0; w < G .vexnum; w++)
if (!final[w] && (min + G .arcs[v][w] < D[w])) {
D[w] = min + G .arcs[v][w];
P[w] = P[v];
P[w][w] = true;
}
}
}
算法分析:总的时间复杂度是2()O n
2. 每对顶点之间的最短路径问题
解决方法A :每次以一个顶点为源点,重复执行Dijkstra 算法n 次,总的执行时间为3()O n 解决方法B :Floyd 算法
基本思想:假设求从顶点i v 到j v 的最短路径。如果从i v 到j v 有弧,则从i v 到j v 存在一条长度为arcs[i][j]的路径,该路径不一定是最短路径,需要进行n 次试探。首先考虑路径0(,,)i j v v v 是否存在(即判别弧0(,)i v v 和0(,)j v v 是否存在)。如果存在,则比较(,)i j v v 和0(,,)i j v v v 的路径长度,取长度较短者为从i v 到j v 的中间顶点的序号不大于0的最短路径。在一般情况下,若(,...,)i k v v 和(,...,)k j v v 分别是从i v 到k v 和从k v 到j v 的中间顶点的序号不大于k-1的最短路径,则将(,...,,...,)i k j v v v 和已经得到的从i v 到j v 且中间顶点序号不大于k-1的最短路径相比较,其长度较短者便是从i v 到j v 的中间顶点的序号不大于k 的最短路径。这样,在经过n 次比较后,最后求得的必是从i v 到j v 的最短路径。定义一个n 阶方阵序列(1)(0)(1)()(1),,,...,,...,k n D D D D D --,其中(1)[][].[][]D i j G arcs i j -=,()(1)(1)(1)[][]{[][],[][][][]},01k k k k D i j Min D i j D i k D k j k n ---=+≤≤-
Floyd 算法代码:
void shortestPath_Floyd(Graph G, PathMatrix& P[], DistanceMatrix& D) {
// the value of D[v][w] means the shortest path from v to w
// P[v][w][u] = true means the shortest path from v to w contains vertex u
for (v = 0; v < G.vexnum; v++)
for (w = 0; w < G .vexnum; w++) {
D[v][w] = G .arcs[v][w];
for (u = 0; u < G .vexnum; u++) P[v][w][u] = false;
if (D[v][w] < INFINITY) {
P[v][w][v] = true;
P[v][w][w] = true;
}
}
// modify P and D
for (u = 0; u < G.vexnum; u++)
for (v = 0; v < G .vexnum; v++)
for (w = 0; w < G .vexnum; w++)
if (D[v][u] + D[u][w] < D[v][w]) {
D[v][w] = D[v][u] + D[u][w];
for (i = 0; i < G .vexnum; i++) P[v][w][i] = P[v][u][i] || P[u][w][i]; }
}
算法分析:时间复杂度为3()O n
数据结构实验报告
数据结构实验报告 一.题目要求 1)编程实现二叉排序树,包括生成、插入,删除; 2)对二叉排序树进行先根、中根、和后根非递归遍历; 3)每次对树的修改操作和遍历操作的显示结果都需要在屏幕上用树的形状表示出来。 4)分别用二叉排序树和数组去存储一个班(50人以上)的成员信息(至少包括学号、姓名、成绩3项),对比查找效率,并说明在什么情况下二叉排序树效率高,为什么? 二.解决方案 对于前三个题目要求,我们用一个程序实现代码如下 #include . 西华大学实验报告(计算机类) 开课学院及实验室:实验时间:年月日 一、实验目的 通过练习让学生对数据库、数据库和表的关系、数据词典、参照完整性和视图有较好的理解和掌握。 二、内容与设计思想 实验内容: 1.数据库设计器 2.数据库的创建 3.设定数据词典 4.参照完整性的设置 5.视图的创建和修改 三、使用环境 Windos XP操作系统;Visual ProFox 6.0 四、核心代码及调试过程 例3-27创建项目管理器SBGL,要求添入数据库sbsj,并查看该数据库。 图一 图二、“项目管理器”的数据选项卡 图三、“项目管理器”中的数据库与数据库表 例3-28从sbsj数据库所属的sb和zz两个表中抽取编号、名称和增值3个字段。,组成名称 为“我的视图”的SQL视图。 open database sbsj create sql view 我的视图; as select sb.编号,sb.名称,zz.增值from sb,zz where sb.编号=zz.编号 如有你有帮助,请购买下载,谢谢! 例3-29根据例3-28的查询要求,用视图设计器建立视图1,然后修改其中车床的增值来更新zz表原来的增值 图一、视图设计器-视图1 图二、视图设计器-视图1 图三、增值表 图四 图五、视图设计器更新源表数据 19.根据图3.30所示数据库sbsj的永久关系,若利用参照完整性生成器来删除sb。dbf的第一个记录,对其他3个表会否产生影响,是分级、限制和忽略3中情况来说明。 图一、数据库设计器 图二、sbsj.dbc“永久关系的参照完整性生成器” 级联:相关子表中的记录将自动删除 限制:子表有相关记录,在父表中删除记录就会产生“触发器失败”的提示信息 忽略:父表删除记录,与子表记录无关 五、总结 (自己写一些收获和体会) 通过这次上机练习让我学会了怎样在数据库中添加项目管理器、表的数据完整性的概念以及视图的各种操作,让我更容易的掌握理论知识的难点和一些基本命令的使用方法,以及一些平时在课堂上不注意的问题。在上机练习的过程中需要对每个细节都要留心,认真做好每一步这样才不至于出错,这就加强了平时不注意的问题得到回应,从而加深了细节问题的处理方式。在上机的学习之后更加了解了数据库表及其数据完整性是vfp重要的一个对象,命令熟练操作直接关系到数据库的成败。 第三次的上机操作,我了解了命令的使用方式对于建立数据库表及其数据完整性很重要,要学好各种命令以及数据库表及其数据完整性的使用方法,还需在多做习题加强学习。 六、附录 一,实验题目 实验十一:图实验 采用邻接表存储有向图,设计算法判断任意两个顶点间手否存在路径。 二,问题分析 本程序要求采用邻接表存储有向图,设计算法判断任意两个顶点间手否存在路径,完成这些操作需要解决的关键问题是:用邻接表的形式存储有向图并输出该邻接表。用一个函数实现判断任意两点间是否存在路径。 1,数据的输入形式和输入值的范围:输入的图的结点均为整型。 2,结果的输出形式:输出的是两结点间是否存在路径的情况。 3,测试数据:输入的图的结点个数为:4 输入的图的边得个数为:3 边的信息为:1 2,2 3,3 1 三,概要设计 (1)为了实现上述程序的功能,需要: A,用邻接表的方式构建图 B,深度优先遍历该图的结点 C,判断任意两结点间是否存在路径 (2)本程序包含6个函数: a,主函数main() b,用邻接表建立图函数create_adjlistgraph() c,深度优先搜索遍历函数dfs() d,初始化遍历数组并判断有无通路函数dfs_trave() e,输出邻接表函数print() f,释放邻接表结点空间函数freealgraph() 各函数间关系如右图所示: 四,详细设计 (1)邻接表中的结点类型定义: typedef struct arcnode{ int adjvex; arcnode *nextarc; }arcnode; (2)邻接表中头结点的类型定义: typedef struct{ char vexdata; arcnode *firstarc; }adjlist; (3)邻接表类型定义: typedef struct{ adjlist vextices[max]; int vexnum,arcnum; }algraph; (4)深度优先搜索遍历函数伪代码: int dfs(algraph *alg,int i,int n){ arcnode *p; visited[i]=1; p=alg->vextices[i].firstarc; while(p!=NULL) { if(visited[p->adjvex]==0){ if(p->adjvex==n) {flag=1; } dfs(alg,p->adjvex,n); if(flag==1) return 1; } p=p->nextarc; } return 0; } (5)初始化遍历数组并判断有无通路函数伪代码: void dfs_trave(algraph *alg,int x,int y){ int i; for(i=0;i<=alg->vexnum;i++) visited[i]=0; dfs(alg,x,y); } 五,源代码 #include "stdio.h" #include "stdlib.h" #include "malloc.h" #define max 100 typedef struct arcnode{ //定义邻接表中的结点类型 int adjvex; //定点信息 arcnode *nextarc; //指向下一个结点的指针nextarc }arcnode; typedef struct{ //定义邻接表中头结点的类型 char vexdata; //头结点的序号 arcnode *firstarc; //定义一个arcnode型指针指向头结点所对应的下一个结点}adjlist; typedef struct{ //定义邻接表类型 adjlist vextices[max]; //定义表头结点数组 #include 邻接矩阵的实现 1. 实验目的 (1)掌握图的逻辑结构 (2)掌握图的邻接矩阵的存储结构 (3)验证图的邻接矩阵存储及其遍历操作的实现2. 实验内容 (1)建立无向图的邻接矩阵存储 (2)进行深度优先遍历 (3)进行广度优先遍历3.设计与编码MGraph.h #ifndef MGraph_H #define MGraph_H const int MaxSize = 10; template int vertexNum, arcNum; }; #endif MGraph.cpp #include 数据结构实验---图的储存与遍历 学号: 姓名: 实验日期: 2016.1.7 实验名称: 图的存贮与遍历 一、实验目的 掌握图这种复杂的非线性结构的邻接矩阵和邻接表的存储表示,以及在此两种常用存储方式下深度优先遍历(DFS)和广度优先遍历(BFS)操作的实现。 二、实验内容与实验步骤 题目1:对以邻接矩阵为存储结构的图进行DFS 和BFS 遍历 问题描述:以邻接矩阵为图的存储结构,实现图的DFS 和BFS 遍历。 基本要求:建立一个图的邻接矩阵表示,输出顶点的一种DFS 和BFS 序列。 测试数据:如图所示 题目2:对以邻接表为存储结构的图进行DFS 和BFS 遍历 问题描述:以邻接表为图的存储结构,实现图的DFS 和BFS 遍历。 基本要求:建立一个图的邻接表存贮,输出顶点的一种DFS 和BFS 序列。 测试数据:如图所示 V0 V1 V2 V3 V4 三、附录: 在此贴上调试好的程序。 #include #define M 100 typedef struct node { char vex[M][2]; int edge[M ][ M ]; int n,e; }Graph; int visited[M]; Graph *Create_Graph() { Graph *GA; int i,j,k,w; GA=(Graph*)malloc(sizeof(Graph)); printf ("请输入矩阵的顶点数和边数(用逗号隔开):\n"); scanf("%d,%d",&GA->n,&GA->e); printf ("请输入矩阵顶点信息:\n"); for(i = 0;i 实验六图的应用 一、实验目的 1、使学生可以巩固所学的有关图的基本知识。 2、熟练掌握图的存储结构。 3、掌握如何应用图解决各种实际问题。 二、实验内容 本次实验提供2个题目,学生可以任选一个! 题目一:最小生成树问题 [问题描述] 若要在n个城市之间建设通信网络,只需要假设n-1条线路即可。如何以最低的经济代价建设这个通信网,是一个网的最小生成树问题。 [基本要求] 1.利用克鲁斯卡尔算法求网的最小生成树。 2.要求输出各条边及它们的权值。 [实现提示] 通信线路一旦建成,必然是双向的。因此,构造最小生成树的网一定是无向网。设图的顶点数不超过30个,并为简单起见,网中边的权值设成小于100的整数。 图的存储结构的选取应和所作操作相适应。为了便于选择权值最小的边,此题的存储结构既不选用邻接矩阵的数组表示法,也不选用邻接表,而是以存储边(带权)的数组表示图。 [测试数据] 由学生依据软件工程的测试技术自己确定。 题目二:最短路径问题 [问题描述] 给定一个无向网,可以求得单源最短路径。 [基本要求] 以邻接矩阵为存储结构,用迪杰斯特拉算法求解从某一源点到其它顶点之间的最短路径及最短路径长度。 [测试数据] 由学生依据软件工程的测试技术自己确定。 题目三:拓扑排序问题 [问题描述] 给定一个有向图,判断其有无回路。 [基本要求] 以邻接表为存储结构,用拓扑排序算法判断其有无回路。[测试数据] 由学生依据软件工程的测试技术自己确定。 三、实验前的准备工作 1、掌握图的相关概念。 2、掌握图的逻辑结构和存储结构。 3、掌握图的各种应用的实现。 四、实验报告要求 1、实验报告要按照实验报告格式规范书写。 2、实验上要写出多批测试数据的运行结果。 3、结合运行结果,对程序进行分析。 第4章 1.简述需求分析中现行系统调查、新系统逻辑方案的提出等活动的详细内容、关键问题、主要成果及其描述方法。 系统调查 (1)组织机构的调查 了解组织的机构状况。即各部门的划分及其相互关系、人员配备、业务分工、信息流和物流的关系等等。组织机构状况可以通过组织结构图来反映。所谓组织机构图就是把组织分成若干部分,同时标明行政隶属关系,信息流动关系和其他关系。 (2)业务处理状况调查 为了弄清楚各部门的信息处理工作,哪些与系统建设有关,哪些无关,就必须了解组织的业务流程。系统分析人员应按照业务活动中信息流动过程,逐个调查所有环节的处理业务、处理内容、处理顺序和对处理时间的要求,弄清楚各个环节需要的信息内容、信息来源、去向、处理方法、提供信息的时间和信息形态等。 (3)现行系统的目标、主要功能和用户需求调查 只有充分了解现行系统的目标和功能以及用户需求,才能发现存在的问题,寻找解决问题的途径,也使新系统开发成为可能。 (4)信息流程调查 开发信息系统必须了解信息流程。业务流程虽然在一定程度上表达了信息的流动和存储情况,但仍含有物资、材料等内容。为了用计算机对组织的信息进行控制,必须舍去其他内容,把信息的流动、加工、存储等过程流抽象出来,得出组织中信息流的综合情况。描述这种情况的就是数据流图。 (5)数据及功能分析 有了数据流图后,要对图中所出现的数据和信息的属性进一步分析,包括编制数据词典、数据存储情况分析及使用情况分析。同时还要对数据流图中的各个加工逻辑进行描述。可用的工具有决策树、决策表、结构化语言等。 (6)系统运营环境分析 目前我国许多企业组织的信息系统处于停滞状态的主要原因是系统对环境环境的适 应性而非技术问题。因此,必须对系统的应用环境进行认真地调查分析,充分考虑各种可能发生的变化,以提高系统开发的质量。 新系统逻辑方案的提出 (1) 现行系统的薄弱环节 (2) 新系统的总体功能需求 实验六图的应用及其实现 (相关知识点:拓扑排序、关键路径、最小生成树和最短路径) 一、实验目的 1.进一步功固图常用的存储结构。 2.熟练掌握在图的邻接表实现图的基本操作。 3.理解掌握AOV网、AOE网在邻接表上的实现以及解决简单的应用问题。 二、实验内容 一>.基础题目:(本类题目属于验证性的,要求学生独立完成) [题目一]:从键盘上输入AOV网的顶点和有向边的信息,建立其邻接表存储结构,然后对该图拓扑排序,并输出拓扑序列. 试设计程序实现上述AOV网的类型定义和基本操作,完成上述功能。 测试数据:教材图7.28 [题目二]:从键盘上输入AOE网的顶点和有向边的信息,建立其邻接表存储结构,输出其关键路径和关键路径长度。试设计程序实现上述AOE网类型定义和基本操作,完成上述功能。 测试数据:教材图7.29 二>.简单应用题目:(ACM/ICPC训练题,本类题目属于设计性的,要求学生三人为一个团队,分工协作完成)) 【题目三】高速公路 描述 某国共有n个城市(n不超过200),有些城市之间直接有一条高速公路相连,高速公路都是双向的,总共有m条。每条高速公路都有自己的载重限制,即载重最大值。通过车辆的载重不能超过公路的载重限制。如今我们想了解的是,从某一起点城市出发,到达目标城市,车辆最多能带多重的货物。 输入 输入的第一行为两个整数n和m。以下有m行,每行三个整数描述一条公路,分别是首尾相连的城市以及载重限制。然后是一个整数k,即问题个数。接下来k行描述k个问题,每行两个整数表示起点城市和目标城市。问题数不超过一百。 输出 输出包括k行,每行对应一个问题,输出从起点到目标的最大载重量。如果两城市间无路径则输出-1。 样例输入 3 3 1 2 100 2 3 100 1 3 50 2 1 3 2 3 样例输出 100 100 【题目四】最短的旅程 描述 在Byteland有n个城市(编号从1到n),它们之间通过双向的道路相连。Byteland 的国王并不大方,所以,那里只有n -1条道路,但是,它们的连接方式使得从任意城市都可以走到其他的任何城市。 一天,starhder到了编号为k的城市。他计划从城市k开始,游遍城市m1,m2,m3……,mj(不一定要按这个顺序旅游)。每个城市mi都是不同的,并且,也与k不同。Starhder ——就像每一个旅行家一样,携带的钱总是有限的,所以,他要以最短的路程旅行完所有的城市(从城市k开始)。于是,他请你帮助计算一下,旅游完上述的城市最短需要多少路程。 输入 图实验 一,邻接矩阵的实现 1.实验目的 (1)掌握图的逻辑结构 (2)掌握图的邻接矩阵的存储结构 (3)验证图的邻接矩阵存储及其遍历操作的实现 2.实验内容 (1)建立无向图的邻接矩阵存储 (2)进行深度优先遍历 (3)进行广度优先遍历 3.设计与编码 #ifndef MGraph_H #define MGraph_H const int MaxSize = 10; template 实验1 (C语言补充实验) 有顺序表A和B,其元素值均按从小到大的升序排列,要求将它们合并成一 个顺序表C,且C的元素也是从小到大的升序排列。 #include 求A QB #include 本科实验报告 课程名称:数据结构 实验项目:线性结构、树形结构、图结构、查找、排序实验地点: 专业班级:学号: 学生姓名: 指导教师: 2011年12 月24 日 实验项目:线性结构 实验目的和要求 熟练掌握线性结构的基本操作在顺序表和链式表上的实现。 二、实验内容和原理 设顺序表递增有序,编写一个程序,将x插入,使之仍然有序。 三、主要仪器设备 使用的计算机:Nopated++ 四、操作方法与实验步骤 #include A[n]=x; } else { while(A[i] 实验六图的应用及其实现 一、实验目的 1.进一步功固图常用的存储结构。 2.熟练掌握在图的邻接表实现图的基本操作。 3.理解掌握AOE网在邻接表上的实现及解决简单的应用问题。 二、实验内容 [题目]:从键盘上输入AOE网的顶点和有向边的信息,建立其邻接表存储结构,输出其关键路径和关键路径长度。试设计程序实现上述AOE网类型定义和基本操作,完成上述功能。 三、实验步骤 (一)、数据结构与核心算法的设计描述 本实验题目是基于图的基本操作以及邻接表的存储结构之上,着重拓扑排序算法的应用,做好本实验的关键在于理解拓扑排序算法的实质及其代码的实现。 (二)、函数调用及主函数设计 以下是头文件中数据结构的设计和相关函数的声明: typedef struct ArcNode // 弧结点 { int adjvex; struct ArcNode *nextarc; InfoType info; }ArcNode; typedef struct VNode //表头结点 { VertexType vexdata; ArcNode *firstarc; }VNode,AdjList[MAX_VERTEX_NUM]; typedef struct //图的定义 { AdjList vertices; int vexnum,arcnum; int kind; }MGraph; typedef struct SqStack //栈的定义 { SElemType *base; SElemType *top; int stacksize; }SqStack; int CreateGraph(MGraph &G);//AOE网的创建 int CriticalPath(MGraph &G);//输出关键路径 (三)、程序调试及运行结果分析 (四)、实验总结 在做本实验的过程中,拓扑排具体代码的实现起着很重要的作用,反复的调试和测试占据着实验大量的时间,每次对错误的修改都加深了对实验和具体算法的理解,自己的查错能力以及其他各方面的能力也都得到了很好的提高。最终实验结果也符合实验的预期效果。 四、主要算法流程图及程序清单 1、主要算法流程图: 2、程序清单: 创建AOE网模块: int CreateGraph(MGraph &G) //创建有向网 { int i,j,k,Vi,Vj; ArcNode *p; cout<<"\n请输入顶点的数目、边的数目"< 附件2: 北京理工大学珠海学院实验报告 ZHUHAI CAMPAUS OF BEIJING INSTITUTE OF TECHNOLOGY 实验题目图及其应用实验时间 2011.5.10 一、实验目的、意义 (1)熟悉图的邻接矩阵(或邻接表)的表示方法; (2)掌握建立图的邻接矩阵(或邻接表)算法; (3)掌握图的基本运算,熟悉对图遍历算法; (4)加深对图的理解,逐步培养解决实际问题的编程能力 二、实验内容及要求 说明1:学生在上机实验时,需要自己设计出所涉及到的函数,同时设计多组输入数据并编写主程序分别调用这些函数,调试程序并对相应的输出作出分析;修改输入数据,预期输出并验证输出的结果,加深对有关算法的理解。 具体要求: (1)建立图的邻接矩阵(或邻接表); (2)对其进行深度优先及广度优先遍历。 三、实验所涉及的知识点 1.创建一个图: CreateUDN(MGraph &G) 2.查找v顶点的第一个邻接点: FirstAdjVex(MGraph G,int v) 3. 查找基于v顶点的w邻接点的下一个邻接点: NextAdjVex(MGraph G,int v,int w) 4.图的矩阵输出: printArcs(MGraph G) 5:顶点定位: LocateVex(MGraph G,char v) 6. 访问顶点v输出: printAdjVex(MGraph G,int v) 7. 深度优先遍历: DFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v)) 8. 广度优先遍历BFSTraverse(MGraph G,Status (*Visit)(MGraph G,int v)) 9. DFS,从第v个顶点出发递归深度优先遍历图G: DFS(MGraph G,int v) 四、实验记录 1.对顶点的定位其数组下标,利用了找到之后用return立即返回,在当图顶点 多的情况下节省了搜索时间,程序如下 //对顶点v定位,返回该顶点在数组的下标索引,若找不到则返回-1 int LocateVex(MGraph G,char v){ for (int i=0;i 数据结构教程 上机实验报告 实验七、图算法上机实现 一、实验目的: 1.了解熟知图的定义和图的基本术语,掌握图的几种存储结构。 2.掌握邻接矩阵和邻接表定义及特点,并通过实例解析掌握邻接 矩阵和邻接表的类型定义。 3.掌握图的遍历的定义、复杂性分析及应用,并掌握图的遍历方 法及其基本思想。 二、实验内容: 1.建立无向图的邻接矩阵 2.图的深度优先搜索 3.图的广度优先搜索 三、实验步骤及结果: 1.建立无向图的邻接矩阵: 1)源代码: #include "" #include "" #define MAXSIZE 30 typedef struct { char vertex[MAXSIZE]; ertex=i; irstedge=NULL; irstedge; irstedge=p; p=(EdgeNode*)malloc(sizeof(EdgeNode)); p->adjvex=i; irstedge; irstedge=p; } } int visited[MAXSIZE]; ertex); irstedge; ertex=i; irstedge=NULL; irstedge;irstedge=p; p=(EdgeNode *)malloc(sizeof(EdgeNode)); p->adjvex=i; irstedge; irstedge=p; } } typedef struct node { int data; struct node *next; }QNode; ertex); irstedge;ertex); //输出这个邻接边结点的顶点信息 visited[p->adjvex]=1; //置该邻接边结点为访问过标志 In_LQueue(Q,p->adjvex); //将该邻接边结点送人队Q } 附录A 实验报告 课程:数据结构(c语言)实验名称:图的建立、基本操作以及遍历系别:数字媒体技术实验日期: 12月13号 12月20号 专业班级:媒体161 组别:无 姓名:学号: 实验报告内容 验证性实验 一、预习准备: 实验目的: 1、熟练掌握图的结构特性,熟悉图的各种存储结构的特点及适用范围; 2、熟练掌握几种常见图的遍历方法及遍历算法; 实验环境:Widows操作系统、VC6.0 实验原理: 1.定义: 基本定义和术语 图(Graph)——图G是由两个集合V(G)和E(G)组成的,记为G=(V,E),其中:V(G)是顶点(V ertex)的非空有限集E(G)是边(Edge)的有限集合,边是顶点的无序对(即:无方向的,(v0,v2))或有序对(即:有方向的, 无向图中顶点V i的度TD(V i)是邻接矩阵A中第i行元素之和有向图中, 顶点V i的出度是A中第i行元素之和 顶点V i的入度是A中第i列元素之和 邻接表 实现:为图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点Vi的边(有向图中指以Vi为尾的弧) 特点: 无向图中顶点Vi的度为第i个单链表中的结点数有向图中 顶点Vi的出度为第i个单链表中的结点个数 顶点Vi的入度为整个单链表中邻接点域值是i的结点个数 逆邻接表:有向图中对每个结点建立以Vi为头的弧的单链表。 图的遍历 从图中某个顶点出发访遍图中其余顶点,并且使图中的每个顶点仅被访问一次过程.。遍历图的过程实质上是通过边或弧对每个顶点查找其邻接点的过程,其耗费的时间取决于所采用的存储结构。图的遍历有两条路径:深度优先搜索和广度优先搜索。当用邻接矩阵作图的存储结构时,查找每个顶点的邻接点所需要时间为O(n2),n为图中顶点数;而当以邻接表作图的存储结构时,找邻接点所需时间为O(e),e 为无向图中边的数或有向图中弧的数。 实验内容和要求: 选用任一种图的存储结构,建立如下图所示的带权有向图: 要求:1、建立边的条数为零的图; 数据结构教案第七章图 第7章图 【学习目标】 1.领会图的类型定义。 2.熟悉图的各种存储结构及其构造算法,了解各种存储结构的特点及其选用原则。 3.熟练掌握图的两种遍历算法。 4.理解各种图的应用问题的算法。 【重点和难点】 图的应用极为广泛,而且图的各种应用问题的算法都比较经典,因此本章重点在于理解各种图的算法及其应用场合。 【知识点】 图的类型定义、图的存储表示、图的深度优先搜索遍历和图的广度优先搜索遍历、无向网的最小生成树、最短路径、拓扑排序、关键路径 【学习指南】 离散数学中的图论是专门研究图性质的一个数学分支,但图论注重研究图的纯数学性质,而数据结构中对图的讨论则侧重于在计算机中如何表示图以及如何实现图的操作和应用等。图是较线性表和树更为复杂的数据结构,因此和线性表、树不同,虽然在遍历图的同时可以对顶点或弧进行各种操作,但更多图的应用问题如求最小生成树和最短路径等在图论的研究中都早已有了特定算法,在本章中主要是介绍它们在计算机中的具体实现。这些算法乍一看都比较难,应多对照具体图例的存储结构进行学习。而图遍历的两种搜索路径和树遍历的两种搜索路径极为相似,应将两者的算法对照学习以便提高学习的效益。 【课前思考】 1. 你有没有发现现在的十字路口的交通灯已从过去的一对改为三对,即每个方向的直行、左拐和右拐能否通行都有相应的交通灯指明。你能否对某个丁字路口的6条通路画出和第一章绪论中介绍的"五叉路口交通管理示意图"相类似的图? 2. 如果每次让三条路同时通行,那么从图看出哪些路可以同时通行? 同时可通行的路为:(AB,BC,CA),(AB,BC,BA),(AB,AC,CA),(CB,CA,BC) 精品文档数据结构 实 验 报 告 目的要求 1.掌握图的存储思想及其存储实现。 2.掌握图的深度、广度优先遍历算法思想及其程序实现。 3.掌握图的常见应用算法的思想及其程序实现。 实验内容 1.键盘输入数据,建立一个有向图的邻接表。 2.输出该邻接表。 3.在有向图的邻接表的基础上计算各顶点的度,并输出。 4.以有向图的邻接表为基础实现输出它的拓扑排序序列。 5.采用邻接表存储实现无向图的深度优先递归遍历。 6.采用邻接表存储实现无向图的广度优先遍历。 7.在主函数中设计一个简单的菜单,分别调试上述算法。 源程序: 主程序的头文件:队列 #include 实验四图的存储、遍历与应用姓名:班级: 学号:日期:一、实验目的: 二、实验内容: 三、基本思想,原理和算法描述: 四、源程序: (1)邻接矩阵的存储: #include 图的实验报告 班级:电子091 学号:0908140620 姓名:何洁编号:19 (一)实验要求 创建一个图。能够实现图的输入,插入顶点和边,利用队列进行深度和广度遍历。(二)需求分析 功能:1,输入图的信息;2,插入一个顶点;3插入一个边;4,删除一个顶点;5,删除一个边;6,深度优先遍历;7,广度优先遍历;8退出。 (三)概要设计 本程序采用的是模板类,抽象数据类型有:T,E。 类: template 数据库和数据结构实验报告
数据结构实验十一:图实验
数据结构图的建立和应用代码
数据结构实验报告图实验
数据结构实验---图的储存与遍历
数据结构 图的应用
数据流图的构成与绘制步骤
数据结构--图的应用及其实现
数据结构实验报告图实验
数据结构实验
华仔数据结构实验报告
数据结构实验六 图的应用及其实现
数据结构图及其应用实验报告+代码
数据结构图实验报告
数据结构实验报告(图)
(完整版)数据结构详细教案——图
数据结构实验—图实验报告
数据结构 图的存储、遍历与应用 源代码
数据结构--图的实验报告