提交 ca0720c1 创建 作者: 宋海霞's avatar 宋海霞

template

上级
流水线 #483 已失败 于阶段
/Debug
/Release
*.bak
image: "registry.cn-hangzhou.aliyuncs.com/engintime/ubuntu_16.04_cpp:latest"
stages:
- make
- case1
- teacher-check
variables:
TEMPLATE_REPO: "engintime/ds-lab/Project-Template/Lab018.git"
.codecode-runner: &codecode-runner
tags:
- ubuntu-16.04
- short-job
make:
stage: make
<<: *codecode-runner
script:
- make
- execscore.sh 40
only:
- master
case1:
stage: case1
<<: *codecode-runner
script:
- make
- ./app > user_output.txt
- diff output.txt user_output.txt -b -B -y -i --suppress-common-lines
- execscore.sh 100
only:
- master
teacher-check:
stage: teacher-check
<<: *codecode-runner
script:
- make
- ./app
- git clone ${CODECODE_PROTOCOL}gitlab-ci-token:${CI_JOB_TOKEN}@${CODECODE_DOMAIN}/${TEMPLATE_REPO} template
- diff template/.gitlab-ci.yml .gitlab-ci.yml -b -B -y -i --suppress-common-lines
- diff template/output.txt output.txt -b -B -y -i --suppress-common-lines
- fileidentity.sh
only:
- master
when: manual
allow_failure: false
<?xml version="1.0" encoding="gb2312"?>
<OSLProject Version="1.00" Name="CriticalPath" SubjectID="cf4dda31-1275-49ef-9b0f-36a6eff372e4" ProjectTemplateID="8f7541ba-50b1-45ba-a0be-327d9b916db7">
<Configurations>
<Configuration Name="Debug">
<Tool Name="PreBuildEventTool"/>
<Tool Name="CustomBuildTool"/>
<Tool Name="GCCCompilerTool" PreprocessorDefinitions="_DEBUG" GenerateDebugInformation="-1"/>
<Tool Name="PreLinkEventTool"/>
<Tool Name="GCCLinkerTool" AdditionalDependencies="&quot;$(DSLInstallDir)Dump\lib\TopoSort_CriticalPath_Demo.o&quot;"/>
<Tool Name="PostBuildEventTool"/>
<VisualContext>
<WatchPoints>
<WatchPoint FunctionName="CriticalPath" ObserverID="882D621D-8D72-4cb5-AAEE-C4ED8485C852">
</WatchPoint>
</WatchPoints>
</VisualContext>
</Configuration>
<Configuration Name="Release">
<Tool Name="PreBuildEventTool"/>
<Tool Name="CustomBuildTool"/>
<Tool Name="GCCCompilerTool" PreprocessorDefinitions="NDEBUG"/>
<Tool Name="PreLinkEventTool"/>
<Tool Name="GCCLinkerTool"/>
<Tool Name="PostBuildEventTool"/>
</Configuration>
</Configurations>
<Files>
<Filter Name="ͷļ" Filter="h;hpp;hxx">
<File RelativePath=".\CriticalPath.h">
</File>
<File RelativePath=".\Stack.h">
</File>
</Filter>
<Filter Name="Դļ" Filter="cpp;c;cc;cxx">
<File RelativePath=".\main.c">
</File>
<File RelativePath=".\Stack.c">
</File>
</Filter>
<File RelativePath=".\makefile">
</File>
<File RelativePath=".\output.txt">
</File>
<File RelativePath=".\readme.md">
</File>
</Files>
</OSLProject>
#ifndef _CRITICALPATH_H_
#define _CRITICALPATH_H_
//
// 在此处包含 C 标准库头文件
//
#include <stdio.h>
//
// 在此处包含其他头文件
//
#include "Stack.h"
//
// 在此处定义数据结构
//
#define MAX_VERTEX_NUM 50 // 顶点最大数量
typedef long BOOL;
#define TRUE 1
#define FALSE 0
// 边(弧)
typedef struct EdgeNode {
int vertex; // 顶点域。即顶点在顶点数组中的下标。
int weight; // 边的权值
struct EdgeNode* nextedge; // 链域。指向下一条边(弧)。
BOOL isCritical; // 是否为关键活动。TURE 是,FALSE 不是
const char* name; // 边(弧)活动名称
}EdgeNode;
// 顶点
typedef struct VexNode {
const char* name; // 使用一个字符串作为顶点保存的值。也可以认为是顶点的名字。
EdgeNode* firstarc; // 指向第一条边(弧)。
int Indegree; // 顶点的入度。
}VexNode;
// 图。使用邻接表存储
typedef struct GraphList {
VexNode vexlist[MAX_VERTEX_NUM]; // 顶点表
int length; // 顶点数量
}GraphList;
//
// 在此处声明函数
//
void InitGraph(GraphList* pGraphList);
void DeleteGraph(GraphList* pGraphList);
void FindInDegree(GraphList* pGraphList);
int CriticalPath(GraphList* pGraphList);
void OutputResult(GraphList* pGraphList);
//
// 在此处声明全局变量
//
extern Stack stack;
extern Stack TopoSortResult;
extern int Ve[MAX_VERTEX_NUM];
extern int Vl[MAX_VERTEX_NUM];
#endif /* _CRITICALPATH_H_ */
#include "Stack.h"
/*
功能:
初始化栈。
参数:
pS -- 栈的指针
*/
void InitStack(Stack* pS)
{
pS->top = -1;
}
/*
功能:
将元素入栈。
参数:
pS -- 栈的指针
Elem -- 入栈的元素
返回值:
如果插入成功返回入栈元素的值。
如果插入失败返回 -1。
*/
int Push(Stack* pS, int Elem)
{
//
// 栈满,入栈失败。
//
if(MAX_STACK_LENGTH-1 < pS->top)
return -1;
pS->top++;
pS->buffer[pS->top] = Elem; // 将元素插入栈顶
return Elem;
}
/*
功能:
将栈顶元素出栈
参数:
pS -- 栈的指针
返回值:
如果出栈成功返回出栈元素的值。
如果出栈失败返回 -1。
*/
int Pop(Stack* pS)
{
int Elem;
//
// 栈为空,出栈失败
//
if(StackEmpty(pS))
return -1;
Elem = pS->buffer[pS->top];
pS->top--;
return Elem;
}
/*
功能:
判断栈是否为空。
参数:
pQ -- 栈的指针
返回值:
如果栈空返回 1(真)
如果栈非空返回 0(假)
*/
int StackEmpty(Stack* pS)
{
return -1 == pS->top ? 1 : 0;
}
#ifndef _STACK_H_
#define _STACK_H_
//
// 在此处包含 C 标准库头文件
//
//
// 在此处包含其他头文件
//
//
// 在此处定义数据结构
//
#define MAX_STACK_LENGTH 64 // 栈的最大长度
// 栈
typedef struct Stack{
int buffer[MAX_STACK_LENGTH]; // 栈的缓冲区
int top; // 指示栈顶的位置,而不是栈中元素的个数
}Stack;
//
// 在此处声明函数
//
void InitStack(Stack* pS);
int Push(Stack* pS, int Elem);
int Pop(Stack* pS);
int StackEmpty(Stack* pS);
//
// 在此处声明全局变量
//
#endif /* _STACK_H_ */
#include "CriticalPath.h"
Stack stack, TopoSortResult;
int Ve[MAX_VERTEX_NUM]; // 事件最早发生时间数组
int Vl[MAX_VERTEX_NUM]; // 事件最迟发生时间数组
int main(int argc, char* argv[])
{
GraphList GraphList;
//
// 初始化图
//
InitGraph(&GraphList);
//
// 调用 InitStack 函数初始化栈
//
InitStack(&stack);
InitStack(&TopoSortResult);
//
// 关键路径
//
CriticalPath(&GraphList);
//
// 输出结果
//
OutputResult(&GraphList);
//
// 销毁图
//
DeleteGraph(&GraphList);
return 0;
}
/*
功能:
求图中所有顶点的入度
参数:
pGraphList -- 图指针
*/
void FindInDegree(GraphList *pGraphList)
{
//
// TODO: 在此添加代码
//
}
/*
功能:
拓扑排序。将排序结果(顶点下标)压入栈 TopoSortResult 中
并计算事件最早发生时间的数组
参数:
pGraphList -- 图指针
返回值:
如果排序成功返回 1
如果排序失败返回 0
*/
int TopologicalSort(GraphList* pGraphList)
{
FindInDegree(pGraphList); // 求图中所有顶点的入度
//
// TODO: 在此添加代码
//
return 0;
}
/*
功能:
关键路径
参数:
pGraphList -- 图指针
返回值:
如果计算关键路径成功返回 1
如果计算关键路径失败返回 0
*/
int CriticalPath(GraphList* pGraphList)
{
EdgeNode* pEdgeNode; // 边(弧)节点指针
int i, k; // 游标
int ee, el; // 临时变量
TopologicalSort(pGraphList); // 拓扑排序
//
// 初始化事件的最迟发生时间数组
//
for(i = 0; i < pGraphList->length; i++)
Vl[i] = Ve[pGraphList->length - 1];
//
// TODO: 在此添加代码
//
return 0;
}
/*
功能:
使用给定的数据初始化图的邻接表
参数:
pGraphList -- 图指针
*/
typedef struct Arc{
int Weight; // 权值。
int VexIndex; // 与该顶点邻接的顶点序列。
const char* Name; // 边(弧)活动名称
}Arc;
typedef struct VertexArrayEntry {
const char* Name; // 顶点名称。NULL 表示顶点序列结束。
Arc ArcArray[MAX_VERTEX_NUM]; // 边节点数组。
}VertexArrayEntry;
const VertexArrayEntry VertexArray[] =
{
{ "V1", { {4, 2, "a2"}, {6, 1, "a1"}, {5, 3, "a3"} } },
{ "V2", { {1, 4, "a4"} } },
{ "V3", { {1, 4, "a5"} } },
{ "V4", { {2, 5, "a6"} } },
{ "V5", { {9, 6, "a7"}, {7, 7, "a8"} } },
{ "V6", { {4, 7, "a9"} } },
{ "V7", { {2, 8, "a10"}} },
{ "V8", { {4, 8, "a11"}} },
{ "V9", { } },
{ NULL } // 结束标志
};
/*
功能:
初始化图
参数:
pGraphList -- 图指针
*/
void InitGraph(GraphList* pGraphList)
{
int i, j; // 游标
EdgeNode** pEdgeNodePtr; // 指向边(弧)节点指针的指针
//
// 重置图中的数据 length
//
pGraphList->length = 0;
//
// 使用给定的数据初始化图的邻接表
//
for(i=0; i<MAX_VERTEX_NUM ;i++)
{
if(NULL == VertexArray[i].Name) // 顶点名称。NULL表示顶点序列结束。
break;
pGraphList->vexlist[i].name = VertexArray[i].Name;
pEdgeNodePtr = &pGraphList->vexlist[i].firstarc; // 使指针指向顶点数组的第一条边(初始化指针的位置)
for(j=0; j<MAX_VERTEX_NUM; j++)
{
if(NULL == VertexArray[i].ArcArray[j].Name)
{
*pEdgeNodePtr = NULL;
break;
}
*pEdgeNodePtr = (EdgeNode*)malloc(sizeof(EdgeNode));
(*pEdgeNodePtr)->vertex = VertexArray[i].ArcArray[j].VexIndex;
(*pEdgeNodePtr)->weight = VertexArray[i].ArcArray[j].Weight;
(*pEdgeNodePtr)->name = VertexArray[i].ArcArray[j].Name;
(*pEdgeNodePtr)->isCritical = FALSE;
pEdgeNodePtr = &(*pEdgeNodePtr)->nextedge;
}
pGraphList->length++;
}
}
/*
功能:
销毁图
参数:
pGraphList -- 图指针
*/
void DeleteGraph(GraphList* pGraphList)
{
int i;
EdgeNode* pEdgeNode;
for(i=0; i<pGraphList->length; i++)
{
while(pGraphList->vexlist[i].firstarc != NULL)
{
pEdgeNode = pGraphList->vexlist[i].firstarc;
pGraphList->vexlist[i].firstarc = pEdgeNode->nextedge;
free(pEdgeNode);
}
}
pGraphList->length = 0;
}
/*
功能:
输出结果
参数:
*/
void OutputResult(GraphList* pGraphList)
{
EdgeNode* pEdgeNode; // 边(弧)节点指针
int i, k; // 下标
int ee, el; // 临时变量
printf("VertexSeq:\t\t\t\t\t\t\t\t\t");
for(i = 0; i < pGraphList->length; i++)
{
printf("\t%s", pGraphList->vexlist[i].name);
}
printf("\n");
printf("An array of the earliest events to occur Ve:");
for(i = 0; i < pGraphList->length; i++)
{
printf("\t%d ", Ve[i]);
}
printf("\n");
printf("Event latest occurrentce time array Vl:\t\t");
for(i = 0; i < pGraphList->length; i++)
{
printf("\t%d ", Vl[i]);
}
printf("\n");
printf("AdjacencyList:\n");
printf("Vertex (VertexSubscript ActivityName Weight)...\n");
for(i = 0; i < pGraphList->length; i++)
{
printf("%s",pGraphList->vexlist[i].name);
for(pEdgeNode = pGraphList->vexlist[i].firstarc; pEdgeNode!=NULL; pEdgeNode = pEdgeNode->nextedge)
{
//
// 将边(弧)节点指针指向的顶点下标保存到 k 中
//
k = pEdgeNode->vertex;
//
// ee 保存 Ve[i] 的值,le 保存 Vl[k] 值并减去边节点指针对应的权值
//
ee = Ve[i];
el = Vl[k] - pEdgeNode->weight;
if(ee == el)
{
printf(" -> (%2d [%s=%d])", pEdgeNode->vertex, pEdgeNode->name, pEdgeNode->weight);
pEdgeNode->isCritical = TRUE;
}
else
{
printf(" -> (%2d %s=%d )", pEdgeNode->vertex, pEdgeNode->name, pEdgeNode->weight);
}
}
printf(" -> NULL \n");
}
}
app:main.o Stack.o
gcc main.o Stack.o -o app
main.o:main.c CriticalPath.h
gcc -c -w -O3 -std=c99 -fsigned-char main.c -o main.o
Stack.o:Stack.c Stack.h
gcc -c -w -O3 -std=c99 -fsigned-char Stack.c -o Stack.o
\ No newline at end of file
VertexSeq: V1 V2 V3 V4 V5 V6 V7 V8 V9
An array of the earliest events to occur Ve: 0 6 4 5 7 7 16 14 18
Event latest occurrentce time array Vl: 0 6 6 8 7 10 16 14 18
AdjacencyList:
Vertex (VertexSubscript ActivityName Weight)...
V1 -> ( 2 a2=4 ) -> ( 1 [a1=6]) -> ( 3 a3=5 ) -> NULL
V2 -> ( 4 [a4=1]) -> NULL
V3 -> ( 4 a5=1 ) -> NULL
V4 -> ( 5 a6=2 ) -> NULL
V5 -> ( 6 [a7=9]) -> ( 7 [a8=7]) -> NULL
V6 -> ( 7 a9=4 ) -> NULL
V7 -> ( 8 [a10=2]) -> NULL
V8 -> ( 8 [a11=4]) -> NULL
V9 -> NULL
# 阅读实验源代码
**main.c文件**
在 main 函数中首先初始化了图和栈,然后调用CriticalPath函数查找图中关键路径,最后销毁了图。
在main函数的后面,分别定义了计算图中顶点入度函数FindInDegree和图的拓扑排序函数TopologicalSort和图的关键路径查找函数CriticalPath,以及图的初始化函数和销毁函数。其中,计算顶点入度函数FindInDegree和拓扑排序函数TopologicalSort以及图中关键路径查找函数CriticalPath的函数体还不完整,留给读者完成。
**CriticalPath.h文件**
定义了与图相关的数据结构并声明了相关的操作函数和全局变量。注意,此头文件中还包含了栈模块的头文件Stack.h。
**Stack.h文件**
定义了与栈相关的数据结构并声明了相关的操作函数。
**Stack.c文件**
定义了与栈相关的操作函数。
# 在演示模式下调试项目
**按照下面的步骤调试项目:**
1. 按F7生成项目。
2. 在演示模式下,按F5启动调试项目。程序会在观察点函数的开始位置中断。
3. 重复按F5,直到调试过程结束。
在调试的过程中,每执行“演示流程”窗口中的一行后,仔细观察“可视化数据”窗口内容所发生的变化,理解关键路径函数的执行过程。“可视化数据”窗口显示的数据信息(如下图所示),包括:
- 求图中关键路径所需的事件最早发生时间数组和事件最迟发生时间数组。
- 图的邻接表。
a) 包括顶点名称字符串,如果该顶点是关键路径上关联的顶点,该顶点的填充色为蓝色,字体颜色为白色;如果该顶点在栈中,该顶点的填充色为绿色。
b) 顶点的邻接点(即图中的边、或者弧),和邻接点中包含的权值、 顶点下标和活动名称,如果该邻接顶点所包含的活动为关键路径上活动,该邻接点的填充色为蓝色,字体颜色为白色。
c) 在调试的过程中,可以看到游标的移动。
- 计算事件最迟发生时间数组时使用的栈。
- 在图中,栈中的顶点的填充色为绿色;关键路径上的顶点的填充色为蓝色,字体的颜色为白色;关键路径上边的颜色为红色;游标指向的当前边的颜色为红色;在调试的过程中,可以看到游标的移动。
![关键路径1](./img/18_1.png)
![关键路径2](./img/18_2.png)
# 编写源代码并通过验证
**按照下面的步骤继续实验:**
1. 为FindInDegree、TopologicalSort和CriticalPath函数编写源代码。注意,尽量使用已定义的局部变量。
2. 按F7生成项目。如果生成失败,根据“输出”窗口中的提示信息修改源代码中的语法错误。
3. 按Alt+F5启动验证。如果验证失败,可以使用“输出”窗口中的“比较”功能,或者在“非演示模式”下按F5启动调试后重复按F10单步调试读者编写的源代码,从而定位错误的位置,然后回到步骤1。
>
**`提示:`**在搜索关键路径的过程中,把边(或者弧)的isCritical域设置为TRUE,表示这条边(或者弧)是关键路径上的关键活动。
>
# 教师参考答案
访问教师参考答案[domain relative url](engintime/ds-lab/teachers-packet/Lab018.git)
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论