0
点赞
收藏
分享

微信扫一扫

数据结构复习

舟海君 2022-03-11 阅读 42

线性表

1.顺序表L删除所有值为x的元素,时间复杂度O(n),空间复杂度O(1)

void delx(SqlList* L,ElemType x){
    i=0,j=0;
    while(i<L->last){
        if(L->elem[i]!=x){
            L->elem[j]=L->elem[i];
            i++,j++;
        }else{
            i++;
        }
    }
    L->last=j-1;
}

2.带头结点单链表就地逆置

void ReserveList(LinkList L){
    p=L->next;
    L->next=NULL;
    while(p){
        q=p->next;	//保留当前处理节点的下一个节点
        p->next=L->next;
        L-next=p;
        p=q;
    }
}

3.带头结点单链表L,以表中第一个元素值为标准,将表中所有值小于第一个元素放在第一个元素之前,大于放在之后

void changeList(LinkList L){
    if(L->next==NULL){
        return;
    }
    p1=L->next;
    pre=p1;	//pre始终指向正在处理元素的前一个位置
    p=p1->next;		//p为当前处理节点
    while(p){
        q=p->next;	//保存当前处理节点的下一个节点
        if(p->data>=p1->data){
            pre=p;
            p=q;
        }else{
            pre->next=p->next;
            p->next=L->next;
            L->next=p;
            p=q;
        }
    }
}

栈与队列

1.括号匹配算法

void BracketMatch(char* str){	//str为输入字符
    Stack S;
    int i;char ch;
    InitStack(&S);
    for(i=0;str[i]!='\0';i++){
        switch(str[i]){
            case '(':
            case '[':
            case '{':
            	Push($S,str[i]);
                break;
            case ')':
            case ']':
            case '}':
            	if(isEmpty(S)){
                    printf("右括号多余");
                }else{
                    GetTop(S,&ch);
                    if(Match(ch,str[i])){
                        Pop(&S,&ch);
                    }else{
                        printf("左右括号不同类");
                    }
                }
                break;
        }
    }
    if(IsEmpty(S)){
        printf("括号匹配");
    }else{
        printf("左括号多余");
    }
}

2.无括号算术表达式处理

//读入一个简单表达式计算值,OPTR为运算符栈,OVS为运算数栈
int ExpEvaluation(){
    InitStack($OPTR);
    InitStack(&OVS);
    Push($OPTR,'#');
    ch=getchar();
    while(ch!='#'||GetTop(OPTR)!='#'){
        if(!In(ch,OPSet)){	//不是操作符 是操作数
            n=GetNumber(ch);
            Push(&OVS,n);
            ch=getchar();
        }else{
            switch(Compare(ch,GetTop(&OPTR))){
                case '>':Push(&OPTR,ch);ch=getchar();break;
                case '=':
                case '<':Pop(&OPTR,&op);Pop(&OVS,&b);
                    	 Pop(&OVS,&a);v=Excute(a,op,b);
                    	 Push(&OVS,v);break;
            }
        }
    }
    v=GetTop(&OVS);
    return v;
}

3.汉诺塔递归算法

//将X上从上到下编号1至n,直径由小到大叠放的n个圆盘,按规则借助Y移动到Z上
void hannoi(int n,char X,char Y,cahr Z){
    if(n==1){
        move(X,1,Z);
    }else{
        hannoi(n-1,X,Z,Y);
        move(X,n,Z);
        honnoi(n-1,Y,X,Z);
    }
}

4.打印杨辉三角形前n行元素

void YangHuiTriangle(){
    SeqQueue Q;
    InitQueue(&Q);
    EnterQueue(&Q,1);		//第1行元素入队
    for(n=2;n<=N;n++){
        EnterQueue(&Q,1);	//第n行第一个元素入队
        for(i=1;i<=n-2;i++){//利用n-1行元素产生第n行中间n-2个元素
            DeleteQueue(&Q,&tmp);
            printf(tmp);
            GetHead(Q,&x);
            tmp+=x;
            EnterQueue(&Q,tmp);
        }
        DeleteQueue(&Q,&x);
        printf(x);
        EnterQueue(&Q,1);	//第n行最后一个元素入队
    }
    while(!IsEmpty(Q)){
        DeleteQueue(&Q,&x);
        printf(x);
    }
}

树与二叉树

一、二叉树的遍历与线索化

1.输出二叉树中的节点
void PreOrder(BiTree root){
    if(root!=NULL){
        printf(root->data);
        PreOrder(root->LChild);
        PreOrder(root->RChild);
    }
}
2.输出二叉树中的叶子节点
void PreOrder(BiTree root){
    if(root!=NULL){
        if(root->LChild==NULL&&root->RChild==NULL){
            printf(root->data);
        }
        PreOrder(root->LChild);
        PreOrder(root->RChild);
    }
}
3.统计叶子节点的数目

方法一:后序遍历实现

//leafCount为保存叶子节点数目的全局变量 初始值为0
void leaf(BiTree root){
    if(root!=NULL){
        leaf(root->LChild);
        leaf(root->RChild);
        if(root->LChild==NULL&&root->RChild==NULL){
            leafCount++;
        }
    }
}

方法二:分治算法

void leaf(BiTree root){
    int leafCount;
    if(root==NULL){
        leafCount=0;
    }else if(root->LChild==NULL&&root->RChild==NULL){
        leafCount=1;
    }else{
        leafCount=leaf(root->LChild)+leaf(root->RChild);
    }
    return leafCount;
}
4.拓展先序序列创建二叉树
void CreateBiTree(BiTree* bt){
    char ch;
    ch=getchar();
    if(ch=='.'){
        *bt=NULL;
    }else{
        *bt=(BiTree)malloc(sizeof(BiTNode));
        (*bt)->data=ch;
        CreateBiTree(&((*bt)->LChild));
        CreateBiTree(&((*bt)->RChild));
    }
}
5.求二叉树高度

分治法

int PostTreeDepth(BiTree bt){
    int hr,hl,max;
    if(bt!=NULL){
        hl=PostTreeDepth(bt->LChild);	//求左子树的深度
        hr=PostTreeDepth(bt->RChild);	//求右子树的深度
        max=hr>hl?hr:hl;
        return max+1;	//加树根的高度
    }else{
        return 0;
    }
}

先序遍历实现

//depth为全局变量 为当前求得的最大层次
void PreTreeDepth(BiTree bt,int h){
    if(bt!=NULL){
        if(h>depth){
            depth=h;
        }
        PreTreeDepth(bt->LChild,h+1);
        PreTreeDepth(bt->RChild,h+1);
    }
}
6.按横向树形显示二叉树
//二叉树的横向显示是竖向显示的逆时针90度旋转,分析可知输出的节点序列正好为逆中序顺序
void PrintTree(BiTree bt,int nLayer){
    if(bt==NULL){
        return;
    }
    PrintTree(bt->RChild,nLayer+1);
    for(i=0;i<nLayer;i++){
        printf(" ");
    }
    printf(bt->data);
    PrintTree(bt->LChild,nLayer+1);
}

二、基于栈的递归消除

1.中序遍历二叉树的非递归算法
void InOrder(BiTree root){
    InitStack(&S);
    p=root;
    while(p!=NULL||!IsEmpty(S)){
        if(p!=NULL){
            Push(&S,p);
            p=p->LChild;
        }else{
            Pop(&S,&p);
            Visit(p->data);
            p=p->RChild;
        }
    }
}
2.后序遍历二叉树的非递归算法
void PostOrder(BiTree root){
    InitStack(&S);
    p=root;
    while(p!=NULL||!IsEmpty(S)){
        if(p!=NULL){
            Push(&S,p);
            p=p->LChild;
        }else{
            GetTop(s,&p);
            if(p->RChild==NULL||p->RChild==q){	//右子树为空或访问过
               visit(p->data);
                q=p;	//将访问过的节点保存在q中,作为处理下一个节点的前驱
                Pop(&S,&p);
                p=NULL;	//p置空方可继续退层,否则会重复进入刚访问的左子树
            }else{
                p=p->RChild;
            }
        }
    }
}

三、线索二叉树

1.建立中序序列
//pre始终指向刚访问过的节点 初值为NULL
void InThread(BiTree root){
    if(root!=NULL){
        InThread(root->LChild);
        if(root->LChild==NULL){
            root->LChild=pre;
            root->Ltag=1;
        }
        if(pre!=NULL&&pre->RChild==NULL){
            pre->RChild=root;
            pre->Rtag=1;
        }
        InThread(root->RChild);
    }
}
2.在中序线索树中寻找节点的前驱节点
BiTNode* InPre(BiTNode* p){
    if(p->Ltag==1){
        pre=p->LChild;
    }else{
        //在p的左子树寻找 最右下端 节点
        for(q=p->LChild;q->Rtag==0;q=q->RChild);
        pre=q;
    }
    return pre;
}
3.在中序线索树寻找节点的后继节点
BiTNode* InNext(BiTNode* p){
    if(p->RChild==1){
        next=p->RChild;
    }else{
        //在p右子树寻找 最左下端 节点
        for(q=p->RChild;q->Ltag==0;q=q->LChild);
        next=q;
    }
    return next;
}
4.在中序线索树中求中序遍历的第一个节点
BiTNode* InFirst(BiTree bt){
    p=bt;
    if(!p)	return NULL;
    while(p->Ltag==0){
        p=p->LChild;
    }
    return p;
}
5.遍历中序二叉线索树
void TInOrder(BiTree bt){
    p=InFirst(bt);
    while(p){
        visit(p->data);
        p=InNext(p);
    }
}

总结与提高

1.二叉树相似性判断
//两颗二叉树都为空或者左右子树相似
int like(BiTree t1,BiTree t2){
    int like1,like2;
    if(t1==NULL&&t2==NULL){
        return 1;
    }else if(t1==NULL||t2==NULL){
        return 0;
    }else{
        like1=like(t1->left,t2->left);
        like2=like(t1->right,t2->right);
        return like1&&like2;
    }
}
2.求二叉树根节点到r节点之间的路径

这里的路径包括r节点的所有祖先,采用后序遍历的方法

void path(BiTree root,BiTNode* r){
    InitStack(&S);
    q=NULL;	//q保存刚遍历过的节点,初始为空
    p=root;
    while(p!=NULL||top!=0){
        while(p!=NULL){
            Push(&S,p);
            p=p->LChild;
        }
        if(!IsEmpty(S)){
            p=GetTop(S);
            if(p->RChild==NULL||p->RChild==q){
                //===================================
                if(p==r){
                    while(!IsEmpty){
                        tmp=Pop(&S);
                        printf(tmp);
                    }
                    return;
                }else{
                	q=p;
                    Pop(&S);
                    p=NULL;
            	}
                //=====================================
            }else{
                p=p->RChild;
            }
        }
    }
}
3.层次遍历二叉树

队列实现

int LayerOrder(InTree bt){
    SeqQueue Q;
    BiTNode* p;
    InitQueue(&Q);
    if(bt==NULL){
        return ERROR;
    }
    EnterQueue(&Q,bt);
    while(!IsEmpty(Q)){
        DeleteQueue(&Q,&p);
        visit(p->data);
        if(p->LChild){
            EnterQueue(&Q,p->LChild);
        }
        if(p->RChild){
            EnterQueue(&Q,p->RChild);
        }
    }
    return OK;
}

一、图的存储结构

#define MAX_VERTEX_NUM 20
#define INFINTY 32768
//DG有向图 DN有向网 UDG无向图 UDN无向网
typedef enum{DG,DN,UDG,UDN} GraphKind;
typedef char VertexData;

邻接矩阵表示法

typedef struct ArcNode{
    AdjType adj;
    OtherInfo info;
}ArcNode;
typedef struct{
    VertexData vertex[MAX_VERTEX_NUM];
    ArcNode arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
    int vexnum,arcnum;
    GraphKind kind;
}AdjMatrix;

邻接表 -->边稀疏时比邻接矩阵节省空间

typedef struct ArcNode{
    int adjvex;
    struct ArcNode* nextarc;
    OtherInfo info;
}ArcNode;
typedef struct VertexNode{
    VertexData data;
    ArcNode* firstarc;
}VertexNode;
typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];
    int vexnum,arcnum;
    GraphKind kind;
}AdjList;

十字链表 -->邻接表与逆邻接表结合

typedef struct ArcNode{
    int tailvex,headvex;	//顶点在图中位置
    struct ArcNode* hlink,tlink;
}ArcNode;
typedef struct VertexNode{
    VertexData data;
    ArcNode* finstin,* firstout;
}VertexNode;
typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];
    int vexnum,arcnum;
    GraphKind kind;
}OrthList;

邻接多重表 -->提供更为方便的边处理信息

typedef struct EdgeNode{
    int mark,ivex,jvex;
    struct EdgeNode* ilink,* jlink;
}EdgeNode;
typedef struct{
    VertexData data;
    EdgeNode* firstedge;
}VertexNode;
typedef struct{
    VertexNode vertex[MAX_VERTEX_NUM];
    int vexnum,arcnum;
    GraphKind kind;
}AdjMultiList;

二、图的遍历

图的联通性问题、拓扑排序和关键路径等问题

访问标志数组作用:保证图中各顶点在遍历过程中访问且仅访问一次。

1.深度优先搜索
void TraverseGraph(Graph g){
    for(vi=0;vi<g.vexnum;vi++){
        visited[vi]=False;
    }
    //循环调用深度优先遍历连通子图,若g是联通图,此调用只执行一次
    for(vi=0;vi<g.vexnum;vi++){
        if(!visited[vi]){
            DFS(g,vi);
        }
    }
}
void DFS(Graph g,int v0){
    visit(v0);
    visited[v0]=True;
    w=FirstAdjVertex(g,v0);
    while(w!=-1){	//邻接点存在
        if(!visited[w]){
            DFS(g,w);
        }
        w=NextAdjVertex(g,v0,w);
    }
}

邻接矩阵DFS

void DFS(AdjMatrix g,int v0){
    visit(v0);visited[v0]=True;
    for(vi=0;vi<g.vexnum;vi++){
        if(!visited[vi]&&g.arcs[v0][vi].adj==1){
            DFS(g,vi);
        }
    }
}

邻接表DFS

void DFS(AdjList g,int v0){
    visit(v0);visited[v0]=True;
    p=g.vertex[v0].firstarc;
    while(p!=NULL){
        if(!visited[p->adjvex]){
            DFS(g,p->adjvex);
        }
        p=p->nextarc;
    }
}

实现非递归DFS

void DFS(Graph g,int v0){
    InitStack(&S);
    Push(&S,v0);
    while(!IsEmpty(s)){
        Pop(&S,&v);
        if(!visited[v]){
            visit(v);
            visited[v]=True;
            w=FirstAdjVertex(g,v);
            while(w!=-1){
                if(!visited[w]){
                    Push(&S,w);
                }
                w=NextAdjVertex(g,v,w);
            }
        }
    }
}
2.广度优先搜索

队列实现非递归BFS

void BFS(Graph g,int v0){
    visit(v0);visited[v0]=True;
    InitQueue(&Q);
    EnterQueue(&Q,v0);
    while(!ISEmpty(Q)){
        DeleteQueue(&Q,&v);
        w=FirstAdiVertex(g,v);
        while(w!=-1){
            if(!visited[w]){
                visite(w);
                visited[w]=True;
                EnterQueue(&Q,w);
            }
            w=NextAdjVertex(g,v,w);
        }
    }
}

三、图的应用

1.图的连通性问题

简单路径:路径中顶点均不相同

int pre[MAX_VERTEX_NUM]={-1};	//-1表示未被访问 pre记录的是vi-->vj时pre[j]=i
void Path(Graph g,int u,int v){
    pre[u]=u;
    DFS(G,u,v);
}
void DFS(Graph g,int u,int v){
    if(u==v){
        //找到终点,反向输出路径
        print_path(pre,v);return;
    }
    w=FirstAdjVertx(g,u);
    while(w!=-1){
        if(!visited[w]){
            pre[w]=u;
            DFS(g,w,v);
        }
        w=NextAdjVertx(g,u,w);
    }
}

MST:在一个连通图的所有生成树中,各边代价之和最小的那颗生成树

Prim算法

1.将连通网中的所有顶点分为两类(假设为 A 类和 B 类)。初始状态下,所有顶点位于 B 类

2.选择任意一个顶点,将其从 B 类移动到 A 类

3.将图中的所有顶点分为 A 类和 B 类,从 B 类的所有顶点出发,找出一条连接着 A 类中的某个顶点且权值最小的边,将此边连接着的 A 类中的顶点移动到 B 类

4.重复执行第 3 步,直至 B 类中的所有顶点全部移动到 A 类,恰好可以找到 N-1 条边

//辅助数组,0单元不用
struct{
    int adjvex;
    int lowcost;
}closedge[MAX_VERTEX_NUM+1];
//从顶点u出发,构造最小生成树,输出生成树每条边
MiniSpanTree_Prim(AdjMatrix gn,int u){
    closedge[u].lowcost=0;
    //初始化B类
    for(i=1;i<=gn.vexnum;i++){
        if(i!=u){
            closedge[i].adjvex=u;
            closedge[i].lowcost=gn.arcs[u][i].adj;
        }
    }
    //需要找到n-1条边
    for(e=1;e<=gn.vexnum-1;e++){
        v=Minium(closedge);
        u=closedge[v].adjvex;
        printf(u,v);
        //将顶点v并入A类
        closedge[v].lowcost=0;
        //更新B类
        for(i=1;i<=gn.vexnum;i++){
            if(gn.arcs[v][i].adj<closedge[i].lowcost){
                closedge[i].lowcost=gn.arcs[v][i].adj;
                closedge[i].adjvex=v;
            }
        }
    }
}

kruskal算法 -->更适合于求边稀疏的网的最小生成树

将连通网中所有的边按照权值大小做升序排序,从权值最小的边开始选择,只要此边不和已选择的边一起构成环路,就可以选择它组成最小生成树。对于 N 个顶点的连通网,挑选出 N-1 条符合条件的边,这些边组成的生成树就是最小生成树。

2.有向无环图的应用

AOV网:Activity on vertex network

不能存在回路 拓扑序列不唯一

AOE网:Acvity on edge network

通俗来说,AOV网边无权值,AOE网边有权值

1.求出各个顶点的入度,将入度为0的节点入栈

2.当栈不为空的时候:

a.栈顶顶点i打印并出栈

b.将顶点i的每一个邻接点k入度减1,如果顶点k的入度变为0,将k入栈

int TopoSort(AdjList G){
    Stack S;
    int indegree[MAX_VERTEX_NUM];
    ArcNode* p;
    FindID(G,indegree);	//求各顶点入度
    InitStack(&S);
    for(i=0;i<G.vexnum;i++){
        if(indegree[i]==0){
            Push(&S,i);
        }
    }
    count=0;
    while(!IsEmpty(S)){
        Pop(&S,&i);
        printf(G.vertex[i].data);
        count++;
        p=G.vertex[i].firstarc;
        while(p!=NULL){
            k=p->adjvex;
            indegree[k]--;
            if(indegree[k]==0){
                Push(&S,k);
            }
            p=p->nextarc;
        }
    }
    if(count<G.vexnum){
        return ERROR;	//该有向图有回路
    }else{
        return OK;
    }
}

求入度算法

void FindID(AdjList G,int indegree[MAX_VERTEX_NUM]){
    for(i=0;i<G.vexnum;i++){
        indegree[i]=0;
    }
    for(i=0;i<G.vexnum;i++){
        p=G.vertex[i].firstarc;
        while(p!=NULL){
            indegree[p->adjvex]++;
            p=p->nextarc;
        }
    }
}

在AOE网中,所有活动都完成才能到达终点,因此完成整个工程所必须花费的时间(即最短工期)应该为源点到终点的最大路径长度。具有最大路径长度的路径称为关键路径。关键路径上的活动称为关键活动

事件的最早发生时间:ve[k]
根据AOE网的性质,只有进入Vk的所有活动<Vj, Vk>都结束,Vk代表的事件才能发生,而活动<Vj, Vk>的最早结束时间为ve[j]+len<Vj, Vk>。所以,计算Vk的最早发生时间的方法为:

ve[0] = 0

ve[k] = max(ve[j] + len<Vj, Vk>)

事件的最迟发生时间:vl[k]
vl[k]是指在不推迟整个工期的前提下,事件Vk允许的最迟发生时间。根据AOE网的性质,只有顶点Vk代表的事件发生,从Vk出发的活动<Vk, Vj>才能开始,而活动<Vk, Vj>的最晚开始时间为vl[j] - len<Vk, Vj>。

活动的最早发生时间:ee[i]
ai由有向边<Vk, Vj>,根据AOE网的性质,只有顶点Vk代表的事件发生,活动ai才能开始,即活动ai的最早开始时间等于事件Vk的最早开始时间。

活动的最迟发生时间:el[i]
el[i]是指在不推迟真个工期的前提下,活动ai必须开始的最晚时间。若活动ai由有向边<Vk, Vj>表示,则ai的最晚开始时间要保证事件vj的最迟发生时间不拖后。

修改后的拓扑排序算法

int ve[MAX_VERTEX_NUM];	//每个顶点的最早发生时间
//G为有向网 T为返回逆拓扑序列的栈 并计算ve
int TopoOrder(AdjList G,Stack* T){
    int indegree[MAX_VERTEX_NUM];
    Stack S;
    InitStack(&T);InitStack(&S);
    FindID(G,indegree);
    for(i=0;i<G.vexnum;i++){
        if(indegree[i]==0){
            Push(&S,i);
        }
    }
    count=0;
    //初始化最早发生时间
    for(i=0;i<G.vexnum;i++){
        ve[i]=0;
    }
    while(!IsEmpty(S)){
        Pop(&S,&j);
        Push(T,j);	//按拓扑序列进栈
        count++;
        p=vertex[j].firstarc;
        while(p!=NULL){
            k=p->adjvex;
            if(--indegree[k]==0){
                Push(&S,k);
            }
            //按拓扑顺序计算事件ve
            //ve[i]=Max{ve[k]+dut<k,i>}
            if(ve[j]+p->Info.weight>ve[k]){
                ve[k]=ve[j]+p->Info.weight;
            }
            p=p->nextarc;
        }
    }
    if(count<G.vexnum){
        return ERROR;
    }else{
        return OK;
    }
}

关键路径算法

1.调用修改后的拓扑排序算法,求出每个事件的最早发生时间和逆拓扑排序栈T

2.将各顶点的最晚发生时间vl[i]初始化为汇点的最早发生时间

3.只要栈T不空,重复以下

​ a.栈顶顶点j出栈

​ b.对顶点j的每一个邻接点k,根据顶点k的最晚发生时间vl[k]和弧<j,k>的权值,更新节点j的最晚发生时间vl[j]

4.扫描每一条弧,计算最早发生时间ei和最晚发生时间li,如果ei等于li则输出该边

int CriticalPath(AdjList G){
    int vl[MAX_VERTEX_NUM];	//每个顶点最迟发生时间
    Stack S;
    if(!TopoOrder(G,&T)){
        return ERROR;
    }
    //将各顶点事件最迟发生时间初始化为汇点的最早发生时间
    for(i=0;i<G.vexnum;i++){
        vl[i]=ve[G.vexnum-1];
    }
    while(!IsEmpty(S)){
        Pop(S,&j);
        p=G.vertex[j].firstarc;
        while(p!=NULL){
            k=p->adjvex;
            dut=p->weight;
            //vl[i]=Min{vl[k]-dut<i,k>}
            if(vl[k]-dut<vl[j]){
                vl[j]=vl[k]-dut;
            }
            p=p->nextarc;
        }
    }
    //求ei、li关键活动
    for(j=0;j<G.vexnum;j++){
        p=G.vertex[j].firstarc;
        while(p!=NULL){
            k=p->adjvex;
            dut=p->Info.weight;
            tag=(ei==li)?'*':' ';
            printf(G.vertex[j].data,G.vertex[k].data,dut,ei,li,tag);
            p=p->nextarc;
        }
    }
    return OK;
}
3.最短路径问题

迪杰斯特拉算法 Dijkstra

Dijkstra算法适用于边权值为正的情况,如果边权值为负数就才用另一种最短路算法**Bellman-Ford算法。**适用于有向图和无向图。

#define INFINITY 32768
typedef unsigned int WeightType;
typedef WeightType AdjType;
typedef SeqList VertexSet;
//path[i]中存放顶点i当前最短路径 dist[i]存放顶点i的最短路径长度
ShortestPath_DJS(AdjMatrix g,int v0,WeightType dist[MAX_VERTEX_NUM],VertexSet path[MAX_VERTEX_NUM]){
    //S为已找到最短路径的终点集合
    VertexSet S;
    //初始化dist[i] path[i]
    for(i=0;i<g.vexnun;i++){
        InitList(&path[i]);
        dist[i]=g.arcs[v0][i].adj;
        if(dist[i]<INIFINTY){
            //AddTail表尾添加操作
            AddTail(&path[i],g.vertex[v0]);
            AddTail(&path[i],g.vertex[i]);
        }
    }
    InitList(&S);
    //将v0看作第一个已找到最短路径的终点
    AddTail(&S,g.vertex[v0]);
    //求v0到其余n-1个顶点的最短路径
    for(t=1;t<=g.vexnum-1;t++){
        min=INFINITY;
        for(i=0;i<g.vexnum;i++){
            if(!Member(g.vertex[i],S)&&dist[i]<min){
                k=i;
                min=dist[i];
            }
        }
        if(min==INFINITY){
            return;
        }
        AddTail(&S,g.vertex[k]);
        //修正dist[i]
        for(i=0;i<g.vexnum;i++){
            if(!Member(g.vertex[i],s)&&g.argc[k][i].adj!=INFINITY&&(dist[k]+g.argc[k][i].adj<dist[i])){
                dist[i]=disk[k]+g.arcs[k][i].adj;
                path[i]=path[k];
                AddTail(&path[i],g.vertex[i]);
            }
        }
    }
}
typedef SeqList VertexSet;
//path为vi到vj的当前最短路径 dist为vi到vj的当前最短路径长度
ShortestPath_Floyd(AdjMatrix g,WeightType dist[MAX_VERTEX_NUM][MAX_VERTEX_NUM],VertexSet path[MAX_VERTEX_NUM][MAX_VERTEX_NUM]){
    //初始化dist[i][j]与path[i][j]
    for(i=0;i<g.vexnum;i++){
        for(j=0;j<g.vexnum;j++){
            InitList(&path[i][j]);
            dist[i][j]=arcs[i][j].adj;
            if(dist[i][j]<INFINITY){
                AddTail(&path[i][j],g.vertex[i]);
                AddTail(&path[i][j],g.vertex[j]);
            }
        }
    }
    for(k=0;k<g.vexnum;k++){
        for(i=0;i<g.vexnum;i++){
            for(j=0;j<g.vexnum;j++){
                if(dist[i][k]+dist[k][j]<dist[i][j]){
                    dist[i][j]=dist[i][k]+dist[k][j];
                    //JoinList是合并线性表操作
                    path[i][j]=JoinList(path[i][k],path[k][j]);
                }
            }
        }
    }
}
举报

相关推荐

0 条评论