課程設(shè)計報告
題 目 數(shù)據(jù)結(jié)構(gòu)課程設(shè)計
學(xué)生姓名
學(xué) 號
院 系 計算機與軟件學(xué)院
專 業(yè) 信息安全
指導(dǎo)教師
二O二一年十二月二十四日 ? 目 錄
一、 任務(wù)概述········································5 (一) 棧的應(yīng)用——后綴表達式實現(xiàn)··································5 (二) 圖的應(yīng)用——最小生成樹······································5 (三) 圖的應(yīng)用——活動圖··········································5 (四) 堆排序的應(yīng)用——Top K問題···································6 二、 算法設(shè)計思想····································6 (一) 棧的應(yīng)用——后綴表達式實現(xiàn)··································6 (二) 圖的應(yīng)用——最小生成樹······································6 (三) 圖的應(yīng)用——活動圖··········································7 (四) 堆排序的應(yīng)用——Top K問題···································7 三、 測試結(jié)果········································8 (一) 棧的應(yīng)用——后綴表達式實現(xiàn)··································8 (二) 圖的應(yīng)用——最小生成樹······································8 (三) 圖的應(yīng)用——活動圖··········································9 (四) 堆排序的應(yīng)用——Top K問題··································10
參考文獻·············································10 附件·················································11
數(shù)據(jù)結(jié)構(gòu)課程設(shè)計
摘要:本文主要介紹了數(shù)據(jù)結(jié)構(gòu)中的棧、圖和堆排序在具體案例中的應(yīng)用:利用棧的存儲結(jié)構(gòu)實現(xiàn)了中綴表達式的后綴表示,基于最小生成樹算法實現(xiàn)了無向網(wǎng)中代價最小的路線求解,利用AOE-網(wǎng)求解關(guān)鍵路徑并估算某開發(fā)項目的完成時間,最后利用堆排序算法解決Top K問題。本文針對這些具體案例,有效地組織、存儲和處理數(shù)據(jù),正確地改進或設(shè)計滿足功能需求的算法,旨在通過實際應(yīng)用案例,提升數(shù)據(jù)結(jié)構(gòu)和算法的編程實現(xiàn)能力,增加系統(tǒng)全面的實踐經(jīng)歷。 關(guān)鍵詞:數(shù)據(jù)結(jié)構(gòu);棧 ;圖 ;堆排序
Course design of data structure Abstract:This paper mainly introduces the application of stack, graph and heap sorting in data structure in specific cases: the suffix representation of infix expression is realized by using the storage structure of stack, the route with the lowest cost in undirected network is solved based on the minimum spanning tree algorithm, the critical path is solved by AOE network, and the completion time of a development project is estimated, Finally, the heap sorting algorithm is used to solve the top k problem. Aiming at these specific cases, this paper effectively organizes, stores and processes data, and correctly improves or designs algorithms to meet functional requirements. The purpose is to improve the programming ability of data structure and algorithms and increase the comprehensive practical experience of the system through practical application cases. Key words:Data structure Stack Diagram Sorting
一、任務(wù)概述
(一)棧的應(yīng)用——后綴表達式實現(xiàn)
利用一個棧,實現(xiàn)中綴表達式的后綴表示。例如,輸入a+c/d*(e-f)#,輸出acd/ef-*+。其中#為表達式結(jié)束標志。要求,棧底元素為#,每次對棧操作時,均應(yīng)打印輸出當(dāng)前棧內(nèi)情況。
(二)圖的應(yīng)用——最小生成樹
基于最小生成樹算法(兩種典型算法可任選一種或兩種實現(xiàn)),求解無向有權(quán)圖中代價最小的路線,打印輸出結(jié)果。 請自行選擇圖的存儲結(jié)構(gòu)。 測試用圖如圖1.2.1,1.2.2:
圖1.2.1 圖1.2.2 (三)圖的應(yīng)用——活動圖
圖的應(yīng)用。一個軟件開發(fā)項目的活動圖如下所示,弧上的數(shù)值為需要的開發(fā)天數(shù)。請用鄰接表實現(xiàn)該圖的存儲。(1)計算輸出每條弧最早發(fā)生時間和最遲發(fā)生時間;(2)輸出該開發(fā)項目的最短開發(fā)周期;(2)輸出一旦延期將影響開發(fā)進度的全部路徑。如圖1.3.1
圖1.3.1 (四)堆排序的應(yīng)用——Top K問題 以任務(wù)3中的圖為測試例子,定義有向邊結(jié)構(gòu)體(弧尾,弧頭,權(quán)值),用弧的結(jié)構(gòu)體數(shù)組保存全部弧,并針對該數(shù)組,實現(xiàn)堆排序算法,并用其解決Top K排序問題。(2次課) Top K排序:查找最大的(或最小的)K個元素。 要求分析算法時間復(fù)雜度,討論哪些算法適合TopK排序問題,簡述理由。 注意,算法應(yīng)允許通過參數(shù)設(shè)置,選擇最大K還是最小K個元素; 二、算法設(shè)計思想
(一)棧的應(yīng)用——后綴表達式實現(xiàn)
1.遇到操作數(shù):直接輸出(添加到后綴表達式中); 2.棧為空時,遇到運算符,直接入棧; 3.遇到左括號:將其入棧; 4.遇到右括號:執(zhí)行出棧操作,并將出棧的元素輸出,直到彈出棧的是左括號,左括號不輸出; 5.遇到其他運算符:加減乘除:彈出所有優(yōu)先級大于或者等于該運算符的棧頂元素,然后將該運算符入棧; 6.最終將棧中的元素依次出棧,輸出。
(二) 圖的應(yīng)用——最小生成樹
Prim(普里姆)算法: 算法思想 —— 歸并頂點 1.在圖中任取一個頂點K作為開始點。令U={k},W=V-U,其中V為圖中所有頂點的集合; 2.在U中選取一個頂點,W中選取另一個頂點,使二者對應(yīng)的邊是最短的一條。將該邊作為最小生成樹的邊保存起來,并將該邊頂點全部加入U集合中,并從W中刪去這些頂點; 3.重新調(diào)整U中頂點到W中頂點的距離, 使之保持最小,再重復(fù)此過程,直到W為空集止。
(三) 圖的應(yīng)用——活動圖
1)要找出一個AOE網(wǎng)中的關(guān)鍵路徑,就要先找出網(wǎng)里的關(guān)鍵活動,這些關(guān)鍵活動間的路徑就是關(guān)鍵路徑。 2)判斷一個活動是不是關(guān)鍵活動,方法是要先找到所有活動的最早開始時間和最晚開始時間,并且對它們進行比較,如果二者相等(意味著這個活動在該工程中沒有時間松動),說明這個活動是關(guān)鍵活動。 3)對于活動<Vi, Vk>,它最早的開始時間等于事件Vi最早的發(fā)生時間etv[i](事件v的最早發(fā)生時間用etv[k])。假設(shè)E[Vi]表示所有到達頂點Vi的弧的集合,len<Vi, Vk>表示活動<Vi, Vk>的持續(xù)時間,那么:如圖2.3.1
圖2.3.1 注意,這里假設(shè)頂點下標從0開始,所以Vi==0,則表示它是源點,因此最早的開始時間為0;當(dāng)某個頂點不是源點,那么只有在它前面的事件都發(fā)生完后,才能輪到這個事件,所以用了max。 4)對于活動<Vk, Vj>,它最晚的開始時間等于事件Vj最晚的發(fā)生時間減去這個活動的持續(xù)事件,即ltv[j]-len<Vk, Vj>(事件v的最晚的發(fā)生時間用ltv[k])。假設(shè)S[Vk]表示所有從頂點Vk出發(fā)的弧的集合,len<Vk, Vj>表示活動<Vk, Vj>的持續(xù)時間,那么:如圖2.3.2
圖2.3.2
(四) 堆排序的應(yīng)用——Top K問題
采用順序表存儲表示。 建堆:從最后一個非葉子結(jié)點開始,反復(fù)篩選。 篩選: step 1 得到堆頂元素后,交換堆頂和最后一個元素,此時根結(jié)點的左右子樹均為堆; step 2 自上而下重新調(diào)整為大頂堆:首先以堆頂元素和左右子樹根節(jié)點的值進行比較,若堆頂元素小,則與左右根節(jié)點中值較大的交換,重復(fù)該步驟直至葉子結(jié)點; step 3 重復(fù)上述過程直至結(jié)束。 Top K 問題:設(shè)置函數(shù)參數(shù)flag供選擇查找最大或最小k個元素,利用堆排序結(jié)果 輸出最大或最小k個元素。 時間復(fù)雜度分析:對深度為k的堆,篩選算法中關(guān)鍵字比較次數(shù)最多2(k-1)次,故在建立含n個元素,深度為h的堆時,關(guān)鍵字總的比較次數(shù)不超過4n。而n個結(jié)點的完全二叉樹深度為(log2(n)+1)向下取整,調(diào)整建新堆時調(diào)用heapadjust過程(n-1)次,總比較次數(shù)不超過2n(log2(n)),故堆排序在最壞情況下時間復(fù)雜度為O(nlogn)。 Top K排序問題宜采用算法及理由: 堆排序:用一個小頂堆維護大小為k的數(shù)組,時間復(fù)雜度為O(nlogk),該算法不需要一次將原數(shù)組中的內(nèi)容全部加載到內(nèi)存中,可以處理較大的數(shù)據(jù)量。 快速排序:利用找分割點的方法,時間復(fù)雜度低。 三、測試結(jié)果
(一)棧的應(yīng)用——后綴表達式實現(xiàn)
如圖3.1.1
圖3.1.1
(二)圖的應(yīng)用——最小生成樹
如圖3.2.1,3.2.2:
圖3.2.1
圖3.2.2
(三)圖的應(yīng)用——活動圖
如圖3.3.1
圖3.3.1
(四)堆排序的應(yīng)用——Top K問題
如圖3.4.1
圖3.4.1
參考文獻: 【1】 CSDN 博主遐光 《中綴表達式轉(zhuǎn)后綴表達式算法思想》 【2】 CSDN 博主糖不苦z的原創(chuàng)文章 https://blog.csdn.net/weixin_44203971/article/details/103934109 【3】 程杰《大話數(shù)據(jù)結(jié)構(gòu)》 清華大學(xué)出版社 圖 【4】 CSDN博主「feliciafay」的原創(chuàng)文章 https://blog.csdn.net/feliciafay/article/details/12252727 【5】 嚴蔚敏 吳偉民.《數(shù)據(jù)結(jié)構(gòu)(C語音版)》清華大學(xué)出版社
附件: (一)棧的應(yīng)用——后綴表達式實現(xiàn) 代碼:
#include<stdio.h>
typedef struct{char data[50];int top;
}Stack,*S_ptr;void InitStack(S_ptr S){//初始化棧 for(int i=0;i<50;i++){S->data[i]='\0';}S->top=-1;
}void Push(S_ptr S,char c){//壓入棧中printf("%c入棧\n",c); if(S->top==49){printf("棧滿\n");return ; }S->top++;S->data[S->top]=c;return ;
}void Pop(S_ptr S,char &c){//彈出棧 if(S->top==-1){printf("棧空\n");return;}c=S->data[S->top];printf("%c出棧\n",c);S->top--;return;
}char gettop(S_ptr S){if(S->top==-1){return '\0';}return S->data[S->top];
}void OutputStack(S_ptr S,int top)
{
int i;
for(i=top;i>=0;i--)
{printf("%c",S->data[i]);printf("\n");
}
}int main(){Stack s;S_ptr S=&s;InitStack(S);char e;char a[100];printf("請輸入中綴表達式:");gets(a);Push(S,'#');//棧底元素為#for(int i=0;a[i]!='#';i++){if(a[i]!='+'&&a[i]!='-'&&a[i]!='*'&&a[i]!='/'&&a[i]!='('&&a[i]!=')') {printf("打印%c\n",a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);}//非操作數(shù)直接輸出 else if(a[i]==')'){while(gettop(S)!='('&&gettop(S)!='\0'){//括號匹配 Pop(S,e);printf("%c\n",e);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);}Pop(S,e);}else if(a[i]=='+'||a[i]=='-'){if(gettop(S)=='*'||gettop(S)=='/'){while(gettop(S)!='('&&gettop(S)!='#'){Pop(S,e);printf("打印%c\n",e);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);}Push(S,a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);}else {Push(S,a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);} }else if(a[i]=='*'||a[i]=='/'){if(gettop(S)=='*'||gettop(S)=='/'){Pop(S,e);printf("打印%c\n",e);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);Push(S,a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);}else {Push(S,a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);} } else {Push(S,a[i]);printf("此時棧狀態(tài):\n");OutputStack( S,S->top);} }while(S->data[S->top]!='#'){//將剩余的運算符號出棧Pop(S,e);printf("打印%c\n",e); printf("此時棧狀態(tài):\n"); OutputStack( S,S->top);}return 0;
}數(shù)據(jù):a+b#(二) 圖的應(yīng)用——最小生成樹
代碼:
//2.圖的應(yīng)用——最小生成樹
#include<iostream>
#include<cstdlib>
using namespace std;
#define max_vertex_num 20
int max_weight=0;//記錄無向帶權(quán)圖中最大權(quán)值 typedef struct edgenode{//邊 int adjvex;//該邊所指向的頂點位置 edgenode *nextedge;//指向下一條邊的指針 int weight;//邊上的權(quán)值
}edgenode;typedef struct vnode{//頂點 int data;//頂點信息 edgenode *firstedge;//指向第一條依附該頂點的指針
}vnode,adjlist[max_vertex_num];typedef struct{//圖 adjlist vertices;//頂點向量 int vexnum,edgenum;//圖的當(dāng)前頂點數(shù)和邊數(shù)
}graph;typedef struct node{//輔助數(shù)組,記錄已訪問的頂點及與其相連的邊中最小的權(quán)值 int adjvex;int lowcost;
}node;
node closedge[max_vertex_num];//查找頂點val在頂點向量中的位置
int local(graph G,int val)
{for(int i=0;i<G.vexnum;i++){if(G.vertices[i].data==val)return i;}return -1;
}//鄰接表法構(gòu)造無向圖G
void creatUDG(graph &G)
{ cout<<"請依次輸入頂點數(shù)和邊數(shù):"<<endl;cin>>G.vexnum>>G.edgenum;for(int i=0,j=0;i<G.vexnum;i++,j++)//初始化頂點 {G.vertices[i].data=j;G.vertices[i].firstedge=NULL; }int i,j,k;int v1,v2;edgenode *e=NULL,*p=NULL,*q=NULL;cout<<"請依次輸入邊(Vi,Vj)上的頂點信息及權(quán)值:"<<endl;for(k=0;k<G.edgenum;k++)//初始化邊 {int weights=0;//暫時保存邊上的權(quán)值 cin>>v1>>v2>>weights;i=local(G,v1);//查找兩頂點在頂點向量中的位置 j=local(G,v2); if(G.vertices[i].firstedge==NULL){e=new edgenode;//新建邊結(jié)點 e->adjvex=j;e->nextedge=NULL;e->weight=weights; if(e->weight>max_weight)//尋找最大權(quán)值 max_weight=e->weight;G.vertices[i].firstedge=e;//將該邊結(jié)點接入第i個鏈表 }else{p=G.vertices[i].firstedge;while(p->nextedge!=NULL)//循環(huán)后移p指針,使其指向第i個鏈表中的最后一個結(jié)點 {p=p->nextedge;}e=new edgenode;//新建邊結(jié)點e->adjvex=j;e->nextedge=NULL;e->weight=weights; if(e->weight>max_weight)//尋找最大權(quán)值 max_weight=e->weight;p->nextedge=e;//將該邊結(jié)點接入第i個鏈表的末尾 }if(G.vertices[j].firstedge==NULL){e=new edgenode;e->adjvex=i;e->nextedge=NULL;e->weight=weights;G.vertices[j].firstedge=e;//將該邊結(jié)點接入第i個鏈表 }else{q=G.vertices[j].firstedge;while(q->nextedge!=NULL)//循環(huán)后移p指針,使其指向第i個鏈表中的最后一個結(jié)點 {q=q->nextedge;}e=new edgenode;e->adjvex=i;e->nextedge=NULL;e->weight=weights;q->nextedge=e;//將該邊結(jié)點接入第i個鏈表的末尾 }}max_weight++;for(i=0;i<G.vexnum;i++)//初始化輔助數(shù)組 closedge[i].lowcost=max_weight;//最小代價比最大權(quán)值還大,表示兩頂點無邊連接
}int findmin(graph G)//找權(quán)值最小的邊所關(guān)聯(lián)的頂點
{int i,result=-1;int min=max_weight;for(i=0;i<G.vexnum;i++)//遍歷輔助數(shù)組 {if(closedge[i].lowcost!=0&&min>closedge[i].lowcost){min=closedge[i].lowcost;result=i;}}return result;
}//用普里姆算法從第u個頂點出發(fā)構(gòu)造無向有權(quán)圖G的最小生成樹T并輸出代價最小的路線
void minispantree_prim(graph G,int u)
{int i,j,k,t1,t2;edgenode *p=NULL;k=local(G,u);p=G.vertices[k].firstedge;while(p)//與頂點u相連的邊的權(quán)值和頂點輸入輔助數(shù)組closedge[]{i=p->adjvex; closedge[i].adjvex=u;closedge[i].lowcost=p->weight;p=p->nextedge;}closedge[k].lowcost=0;//訪問過的頂點的邊的權(quán)值標記為0for(i=1;i<G.vexnum;i++) {k=findmin(G);t1=G.vertices[k].data;t2=closedge[k].adjvex;cout<<t2<<"->"<<t1<<endl; closedge[k].lowcost=0;p=G.vertices[k].firstedge;while(p){j=p->adjvex;if(closedge[j].lowcost>p->weight)//與上一頂點比較,輸入權(quán)值小的邊的權(quán)值和與其相連接的頂點{closedge[j].adjvex=G.vertices[k].data;closedge[j].lowcost=p->weight;}p=p->nextedge;}}
}int main()
{graph G;creatUDG(G);cout<<endl<<"請輸入開始頂點:"<<endl;int u;cin>>u;cout<<"代價最小的路線為:"<<endl;minispantree_prim(G,u);return 0;
}
輸入數(shù)據(jù):請依次輸入頂點數(shù)和邊數(shù):7 9
頂點信息和權(quán)值:
0 1 28
1 2 16
2 3 12
3 4 22
4 5 25
5 0 10
1 6 14
3 6 18
4 6 24
輸入開始頂點:0
(三) 圖的應(yīng)用——活動圖
代碼:
include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#include<string.h>
typedef int DataType; /*棧元素類型定義*/
#define MaxSize 50 /*最大頂點個數(shù)*/
#define StackSize 100
typedef struct
{DataType stack[StackSize];int top;
}SeqStack;void InitStack(SeqStack *S)
/*將棧初始化為空棧只需要把棧頂指針top置為0*/
{
S->top=0; /*把棧頂指針置為0*/
}
int StackEmpty(SeqStack S)
/*判斷棧是否為空,棧為空返回1,否則返回0*/
{if(S.top==0) /*判斷棧頂指針top是否為0*/return 1; /*當(dāng)棧為空時,返回1;否則返回0*/elsereturn 0;
}
int GetTop(SeqStack S, DataType *e)
/*取棧頂元素。將棧頂元素值返回給e,并返回1表示成功;否則返回0表示失敗。*/
{if(S.top<=0) /*在取棧頂元素之前,判斷棧是否為空*/
{printf("棧已經(jīng)空!\n");return 0;
}
else
{*e=S.stack[S.top-1]; /*在取棧頂元素*/return 1;
}
}
int PushStack(SeqStack *S,DataType e)
/*將元素e進棧,元素進棧成功返回1,否則返回0.*/
{
if(S->top>=StackSize) /*在元素進棧前,判斷是否棧已經(jīng)滿*/
{printf("棧已滿,不能進棧!\n");return 0;
}
else
{S->stack[S->top]=e; /*元素e進棧*/S->top++; /*修改棧頂指針*/return 1;
}
}
int PopStack(SeqStack *S,DataType *e)
/*出棧操作。將棧頂元素出棧,并將其賦值給e。出棧成功返回1,否則返回0*/
{if(S->top<=0) /*元素出棧之前,判斷棧是否為空*/{printf("棧已經(jīng)沒有元素,不能出棧!\n");return 0;}else
{S->top--; /*先修改棧頂指針,即出棧*/*e=S->stack[S->top]; /*將出棧元素賦值給e*/return 1;}
}
int StackLength(SeqStack S)
/*求棧的長度,即棧中元素個數(shù),棧頂指針的值就等于棧中元素的個數(shù)*/
{return S.top;
}
void ClearStack(SeqStack *S)
/*將棧初始化為空棧只需要把棧頂指針top置為0*/
{
S->top=0; /*把棧頂指針置為0*/
}/*圖的鄰接表類型定義*/
typedef char VertexType[4];
typedef int InfoPtr; /*定義為整型,為了存放權(quán)值*/
typedef int VRType;typedef enum{DG,DN,UG,UN}GraphKind; /*圖的類型:有向圖、有向網(wǎng)、無向圖和無向網(wǎng)*/
typedef struct ArcNode /*邊結(jié)點的類型定義*/
{int adjvex; /*弧指向的頂點的位置*/InfoPtr *info; /*弧的權(quán)值*/struct ArcNode *nextarc; /*指示下一個與該頂點相鄰接的頂點*/
}ArcNode;
typedef struct VNode /*頭結(jié)點的類型定義*/
{VertexType data; /*用于存儲頂點*/ArcNode *firstarc; /*指示第一個與該頂點鄰接的頂點*/
}VNode,AdjList[MaxSize];
typedef struct /*圖的類型定義*/
{AdjList vertex;int vexnum,arcnum; /*圖的頂點數(shù)目與弧的數(shù)目*/GraphKind kind; /*圖的類型*/
}AdjGraph;int ve[MaxSize]; /*ve存放事件最早發(fā)生時間*/
int TopologicalOrder(AdjGraph N,SeqStack *T)
/*采用鄰接表存儲結(jié)構(gòu)的有向網(wǎng)N的拓撲排序,并求各頂點對應(yīng)事件的最早發(fā)生時間ve*/
/*如果N無回路,則用用棧T返回N的一個拓撲序列,并返回1,否則為0*/
{int i,k,count=0;int indegree[MaxSize]; /*數(shù)組indegree存儲各頂點的入度*/SeqStack S;ArcNode *p;/*將圖中各頂點的入度保存在數(shù)組indegree中*/for(i=0;i<N.vexnum;i++) /*將數(shù)組indegree賦初值*/indegree[i]=0;for(i=0;i<N.vexnum;i++){p=N.vertex[i].firstarc;while(p!=NULL){k=p->adjvex;indegree[k]++;p=p->nextarc;}}InitStack(&S); /*初始化棧S*/for(i=0;i<N.vexnum;i++)if(!indegree[i]) /*將入度為零的頂點入棧*/PushStack(&S,i);InitStack(T); /*初始化拓撲序列頂點棧*/for(i=0;i<N.vexnum;i++) /*初始化ve*/ve[i]=0;while(!StackEmpty(S)) /*如果棧S不為空*/{PopStack(&S,&i); /*從棧S將已拓撲排序的頂點j彈出*/PushStack(T,i); /*j號頂點入逆拓撲排序棧T*/count++; /*對入棧T的頂點計數(shù)*/for(p=N.vertex[i].firstarc;p;p=p->nextarc) /*處理編號為i的頂點的每個鄰接點*/{k=p->adjvex; /*頂點序號為k*/if(--indegree[k]==0) /*如果k的入度減1后變?yōu)?,則將k入棧S*/PushStack(&S,k);if(ve[i]+*(p->info)>ve[k]) /*計算頂點k對應(yīng)的事件的最早發(fā)生時間*/ve[k]=ve[i]+*(p->info);}}if(count<N.vexnum){printf("該有向網(wǎng)有回路\n");return 0;}elsereturn 1;
}
int CriticalPath(AdjGraph N)
/*輸出N的關(guān)鍵路徑*/
{int vl[MaxSize]; /*事件最晚發(fā)生時間*/SeqStack T;int i,j,k,e,l,dut,value,count,e1[MaxSize],e2[MaxSize];ArcNode *p;if(!TopologicalOrder(N,&T)) /*如果有環(huán)存在,則返回0*/return 0;value=ve[0];for(i=1;i<N.vexnum;i++)if(ve[i]>value)value=ve[i]; /*value為事件的最早發(fā)生時間的最大值*/for(i=0;i<N.vexnum;i++) /*將頂點事件的最晚發(fā)生時間初始化*/vl[i]=value;while(!StackEmpty(T)) /*按逆拓撲排序求各頂點的vl值*/for(PopStack(&T,&j),p=N.vertex[j].firstarc;p;p=p->nextarc)/*彈出棧T的元素,賦給j,p指向j的后繼事件k*/{k=p->adjvex;dut=*(p->info); /*dut為弧<j,k>的權(quán)值*/if(vl[k]-dut<vl[j]) /*計算事件j的最遲發(fā)生時間*/vl[j]=vl[k]-dut;}printf("\n");count=0;printf("計算輸出每條弧最早發(fā)生時間和最遲發(fā)生時間:\n 弧 e l l-e\n");for(j=0;j<N.vexnum;j++) /*求活動的最早開始時間e和最晚開始時間l*/for(p=N.vertex[j].firstarc;p;p=p->nextarc){k=p->adjvex;dut=*(p->info); /*dut為弧<j,k>的權(quán)值*/e=ve[j]; /*e就是活動<j,k>的最早開始時間*/l=vl[k]-dut; /*l就是活動<j,k>的最晚開始時間*/printf("%s→%s %3d %3d %3d\n",N.vertex[j].data,N.vertex[k].data,e,l,l-e);if(e==l) /*將關(guān)鍵活動保存在數(shù)組中*/{e1[count]=j;e2[count]=k;count++;}}printf("輸出該開發(fā)項目的最短開發(fā)周期:%d\n",ve[N.vexnum-1]);printf("計算輸出每條弧最早發(fā)生時間和最遲發(fā)生時間:");for(k=0;k<count;k++) /*輸出關(guān)鍵路徑*/{i=e1[k];j=e2[k];printf("(%s→%s) ",N.vertex[i].data,N.vertex[j].data);}printf("\n");return 1;
}
int LocateVertex(AdjGraph G,VertexType v)
/*返回圖中頂點對應(yīng)的位置*/
{int i;for(i=0;i<G.vexnum;i++)if(strcmp(G.vertex[i].data,v)==0)return i;return -1;
}
void CreateGraph(AdjGraph *N)
/*采用鄰接表存儲結(jié)構(gòu),創(chuàng)建有向網(wǎng)N*/
{int i,j,k,w;VertexType v1,v2; /*定義兩個弧v1和v2*/ArcNode *p;printf("請輸入圖的頂點數(shù),邊數(shù)(以逗號分隔): ");scanf("%d,%d",&(*N).vexnum,&(*N).arcnum);printf("請輸入%d個頂點的值:",N->vexnum);for(i=0;i<N->vexnum;i++) /*將頂點存儲在頭結(jié)點中*/{scanf("%s",N->vertex[i].data);N->vertex[i].firstarc=NULL; /*將相關(guān)聯(lián)的頂點置為空*/}printf("請輸入弧尾、弧頭和權(quán)值(以空格作為分隔):\n");for(k=0;k<N->arcnum;k++) /*建立邊鏈表*/{scanf("%s%s%*c%d",v1,v2,&w);i=LocateVertex(*N,v1);j=LocateVertex(*N,v2);/*j為弧頭i為弧尾創(chuàng)建鄰接表*/p=(ArcNode*)malloc(sizeof(ArcNode));p->adjvex=j;p->info=(InfoPtr*)malloc(sizeof(InfoPtr));*(p->info)=w;/*將p指向的結(jié)點插入到邊表中*/p->nextarc=N->vertex[i].firstarc;N->vertex[i].firstarc=p;}(*N).kind=DN;
}void DestroyGraph(AdjGraph *N)
/*銷毀無向圖G*/
{int i;ArcNode *p,*q;for(i=0;i<N->vexnum;++i) /*釋放網(wǎng)中的邊表結(jié)點*/{p=N->vertex[i].firstarc; /*p指向邊表的第一個結(jié)點*/if(p!=NULL) /*如果邊表不為空,則釋放邊表的結(jié)點*/{q=p->nextarc;free(p);p=q;}}(*N).vexnum=0; /*將頂點數(shù)置為0*/(*N).arcnum=0; /*將邊的數(shù)目置為0*/
}int main()
{AdjGraph N;CreateGraph(&N); /*采用鄰接表存儲結(jié)構(gòu)創(chuàng)建有向網(wǎng)N*/CriticalPath(N); /*求網(wǎng)N的關(guān)鍵路徑*/DestroyGraph(&N); /*銷毀網(wǎng)N*/
}
實驗數(shù)據(jù):
請輸入圖的頂點數(shù),邊數(shù)(以逗號分隔): 8,10
請輸入8個頂點的值:v1 v2 v3 v4 v5 v6 v7 v8
請輸入弧尾、弧頭和權(quán)值(以空格作為分隔):
v1 v2 3
v1 v2 4
v1 v4 6
v2 v5 3
v4 v7 3
v3 v5 1
v5 v7 3
v6 v8 4
v7 v8 5
v5 v6 5
(四)堆排序的應(yīng)用——Top K問題實驗代碼:
//4.堆排序的應(yīng)用——Top K問題
#include<iostream>
#include<string>
using namespace std;
#define max_arc_num 20
typedef struct arcnode{//弧(有向邊結(jié)構(gòu)體) string head,tail;//弧頭,弧尾 string weight;//弧上的權(quán)值
}arcnode;//全局變量
arcnode arc[max_arc_num];//弧的結(jié)構(gòu)體數(shù)組
int arclen=0;//數(shù)組長度 //輸入各條弧
void In_Put()
{int i=1;arc[0].tail="0";arc[0].head="0";arc[0].weight="0";//數(shù)組零號元素不存儲弧 ,用于交換 記錄過程中暫存記錄 cout<<"請輸入各條弧的弧尾,弧頭,權(quán)值(-1表示結(jié)束輸入):"<<endl; while(cin>>arc[i].tail&&arc[i].tail!="-1"){cin>>arc[i].head>>arc[i].weight;i++;}arclen=i-1;
}//已知arc[s...m]中除arc[s]外均滿足堆的特征,自上而下調(diào)整,使arc[s...m]也成為一個大頂堆 void heapadjust(arcnode arcs[],int s,int m){arcs[0]=arcs[s];for(int j=2*s;j<=m;j*=2)//沿著權(quán)值較大的孩子節(jié)點向下篩選 {if(j<m&&arcs[j].weight<arcs[j+1].weight) ++j;//先左右子樹根之間進行相互比較,j為權(quán)值較大的弧的所在下標if(arcs[0].weight>=arcs[j].weight)//根和子樹根之間相互比較 break;//找到arc[0]的插入位置,無需繼續(xù)往下調(diào)整 arcs[s]=arcs[j];//否則記錄上移,尚需繼續(xù)往下調(diào)整 s=j; }arcs[s]=arcs[0];} // 對弧的結(jié)構(gòu)體數(shù)組進行堆排序
void heapsort(arcnode arcs[])
{for(int i=arclen;i>0;--i)heapadjust(arcs,i,arclen);//建大頂堆(自下而上) for(int i=arclen;i>1;--i)//將堆頂記錄和當(dāng)前未經(jīng)排序子序列arc[1...i]中最后一個記錄相互交換 {arcs[0]=arcs[i];arcs[i]=arcs[1];arcs[1]=arcs[0]; heapadjust(arcs,1,i-1); //對arc[1]進行篩選 }
} //輸出排序后的結(jié)果void Out_Put(){cout<<"按弧的權(quán)值由小到大,輸出各條有向弧(箭頭由弧尾指向弧頭):"<<endl; for(int i=1;i<=arclen;i++){cout<<arc[i].tail<<"->"<<arc[i].head<<' ';cout<<"該弧上的權(quán)值為:"<<arc[i].weight<<endl; } } //Top K排序void Top_K(int k,bool flag)//flag=0/1分別表示查找最小/最大K個元素 {if(flag){cout<<"權(quán)值最大的"<<k<<"條弧為:"<<endl; for(int i=arclen;i>arclen-k;i--){cout<<arc[i].tail<<"->"<<arc[i].head<<' ';cout<<"該弧上的權(quán)值為:"<<arc[i].weight<<endl; } }else{cout<<"權(quán)值最小的"<<k<<"條弧為:"<<endl; for(int i=1;i<=k;i++){cout<<arc[i].tail<<"->"<<arc[i].head<<' ';cout<<"該弧上的權(quán)值為:"<<arc[i].weight<<endl; } }} int main(){In_Put();//輸入各條弧 heapsort(arc);Out_Put();//輸出堆排序結(jié)果 int k,flag;cout<<"請輸入k值:"<<endl;cin>>k;cout<<"查找最大"<<k<<"個元素請輸入1,查找最小的"<<k<<"個元素請輸入0:"<<endl;cin>>flag; Top_K(k,flag); return 0;}
輸入數(shù)據(jù):
請輸入各條弧的弧尾,弧頭,權(quán)值(-1表示結(jié)束輸入):
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 4
-1
請輸入k值:5
查找最大5個元素請輸入1,查找最小的5個元素請輸入0:0
總結(jié)
以上是生活随笔 為你收集整理的数据结构——课程设计 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。