数据结构和算法(图)

图(Graph)的定义:由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合

无向边:若顶点Vi到Vj之间的边没有方向,则称这条边为无向边

有向边:若顶点Vi到Vj之间的边有方向,则称这条边为有向边,也称为弧

简单图:图中不存在顶点到其自身的边,且同一条边不重复出现

无向完全图:无向图中任意两个顶点之间都存在边

有向完全图:有向图中任意两个顶点间存在方向相反的弧

稀疏图:边或者弧数小于n*log(n)

稠密图:与上述条件相反

图的顶点与边之间的关系:

无向图:对于无向图G(V,E),如果边(V1,V2)∈E,则称顶点V1和V2互为邻接点,顶点V的度是和V相关联的边的数目,记为TD(V)

有向图:对于无向图G(V,E),如果弧<V1,V2>∈E,则称顶点V1邻接到顶点V2,或者顶点V2邻接自顶点V1,以顶点V为头的弧的数目称为V的入度,记为ID(V),以V为尾的弧的数目称为V的出度,记为OD(V),因此顶点V的度为TD(V) = ID(V)+OD(V)

路径:图中一个顶点到另一个顶点的遍历,长度是路径上的边或弧的数目

简单环:除第一个和最后一个顶点外,其余顶点不重复出现

连通图:无向图中任意两个顶点都有路径连通

连通分量:无向图中的极大连通子图

强连通图:有向图中任意两个顶点都存在路径

如果一个有向图恰有一个顶点入度为0,其余顶点入度均为1,则这是一颗有向树

图的存储结构:

内存物理位置是线性的,图的元素关系是平面的,故无法以数据元素在内存中的位置来表示元素间的关系

邻接矩阵:

用两个数组表示图,一个一维数组存储图中顶点信息,一个二维数组(无向图中为对称矩阵)存储图中边或弧的信息

网:每条边上带有权的图

邻接表:用于边数及顶点相对较少的图

图中顶点用一个一维数组存储,图中每个顶点的所有邻接点构成一个线性表

十字链表:与邻接表类似,增加弧头(或弧尾)的数据以及入度(或出度)的next指针

链接多重表:与邻接表类似,边表结构变为可表示边,next指针指向下一个与该顶点有关的边

边集数组:两个一维数组构成,一个存储顶点信息,一个存储边的信息,边数组每个数据元素由一条边的起点下标、终点下标和权组成

各存储结构的实现形式:

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

/*邻接矩阵定义*/
typedef struct _Graph
{
    unsigned int line[MAXSIZE][MAXSIZE];
    char value[MAXSIZE];
    int n, e;  //记录图中顶点数以及边或弧的数量
}Graph;

/*邻接表定义(对于有向图来说,一个表只能求入度或出度的一个)*/
typedef struct _GraphNode
{
    unsigned int linkvalue;
    struct _GraphNode *next;
}GraphNode;

typedef struct _GraphBox
{
    char value;
    GraphNode *first;
}GraphBox;

typedef struct _GraphTable
{
    GraphBox table[MAXSIZE];
    int n, e;  //记录图中顶点数以及边或弧的数量
}GraphTable;

/*十字链表定义(有向图专用)*/
typedef struct _GraphTenNode
{
    unsigned int tailvalue;     //表示这条弧的尾(数组下标)
    unsigned int headvalue;     //表示这条弧的头
    struct _GraphTenNode *headnext;     //表示该顶点入度的下一个
    struct _GraphTenNode *tailnext;     //表示该顶点出度的下一个
}GraphTenNode;

typedef struct _GraphTenBox
{
    char value;
    GraphTenNode *headfirst;     //表示该顶点入度的第一个
    GraphTenNode *tailfirst;     //表示该顶点出度的第一个
}GraphTenBox;

typedef struct _GraphTenTable
{
    GraphTenBox table[MAXSIZE];
    int n, e;
}GraphTenTable;

/*邻接多重表定义(对边的操作较为轻松)(无向图专用)*/
typedef struct _GraphCoNode
{
    unsigned int ivex;              //边的第一个顶点
    struct _GraphCoNode *ilink;     //上述顶点的下一个邻接边
    unsigned int jvex;              //边的第二个顶点
    struct _GraphCoNode *jlink;     //上述顶点的下一个邻接边
}GraphCoNode;

typedef struct _GraphCoBox
{
    char value;
    GraphCoNode *first;     //此顶点第一个邻接边
}GraphCoBox;

typedef struct _GraphCoTable
{
    GraphCoBox table[MAXSIZE];
    int n, e;
}GraphCoTable;

/*边集数组定义*/
typedef struct _ArrayGraphNode
{
    unsigned int begin;
    unsigned int end;
    unsigned int weight;
}ArrayGraphNode;

typedef struct _ArrayGraph
{
    char value[MAXSIZE];
    ArrayGraphNode edegs[2 * MAXSIZE];
    int n, e;
}

图的遍历:

深度优先遍历:也称为深度优先搜索,简称为DFS,类似于树的前序遍历,需要使用递归

/*邻接矩阵的深度遍历实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 8

typedef struct _Array
{
    char vex[MAXSIZE];
    unsigned int linevalue[MAXSIZE][MAXSIZE];
}Array;

int n = 1;
int flag[MAXSIZE];

void InitArray(Array *a)
{
    int i, j, k;
    char c;
    for(i=0; i<MAXSIZE; i++)
    {
        j = 65 + i;
        (*a).vex[i] = (char) j;
    }

    for(i=0; i<MAXSIZE; i++)
    {
        printf("请输入第%d行的数值:\n", i);
        fflush(stdin);
        for(j=0; j<MAXSIZE; j++)
        {
            scanf("%c", &c);
            k = (int) c;
            k = k - 48;
            (*a).linevalue[i][j] = k;
        }
    }
}

void printArray(Array a)
{
    int i, j;
    printf("顶点依次表示为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%c", a.vex[i]);
    }
    printf("\n");

    printf("表示边的矩阵:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        for(j=0; j<MAXSIZE; j++)
        {
            printf("%d ", a.linevalue[i][j]);
        }
        printf("\n");
    }
}

void DepTra(Array a, int i)
{
    int j;
    for(j=0; j<MAXSIZE; j++)
    {
        if(a.linevalue[i][j] == 1 && flag[j] == 0)
        {
            if(7 > n)
            {
                printf("%c->", a.vex[j]);
            }
            else
            {
                printf("%c", a.vex[j]);
            }
            n++;
            flag[j] = 1;
            DepTra(a, j);
        }
    }
}

int main(void)
{
    Array a;
    int i, x;

    InitArray(&a);
    printArray(a);

    for(i=0; i<MAXSIZE; i++)
    {
        flag[i] = 0;
    }

    printf("请输入开始遍历的行数:\n");
    scanf("%d", &x);
    printf("遍历结果为:\n");
    printf("%c->", a.vex[x]);
    flag[x] = 1;
    DepTra(a, x);

    return 0;
}

/*邻接表的深度遍历实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 8

typedef struct _GraphLink
{
    unsigned int value;
    struct _GraphLink *next;
}GraphLink;

typedef struct _GraphNode
{
    char vex;
    GraphLink *first;
}GraphNode;

typedef struct _GraphList
{
    GraphNode table[MAXSIZE];
    //int n, e;
}GraphList;

int flag[MAXSIZE];
int n = 1;

void InitGraph(GraphList *a)
{
    unsigned int i, j;
    char k;
    GraphLink *temp, *target;

    for(i=0; i<MAXSIZE; i++)
    {
        flag[i] = 0;        //深度遍历的顶点标记

        j = i + 65;
        (*a).table[i].vex = (char) j;       //顶点赋值
        (*a).table[i].first = NULL;
        printf("请输入和顶点%c有关的顶点的下标,以#结束:\n", (*a).table[i].vex);
        fflush(stdin);
        scanf("%c", &k);
        while('#' != k)
        {
            temp = (GraphLink *)malloc(sizeof(GraphLink));
            temp->value = k - 48;

            if((*a).table[i].first == NULL)
            {
                (*a).table[i].first = temp;
                temp->next = NULL;
                target = temp;
            }
            else
            {
                target->next = temp;
                temp->next = NULL;
                target = temp;
            }

            scanf("%c", &k);
        }
    }

    /*
    gra.value[MAXSIZE][MAXSIZE] = {
        {0,1,0,0,0,0,0,1},
        {1,0,0,1,0,1,0,1},
        {0,0,0,1,0,0,0,0},
        {0,1,1,0,0,1,0,1},
        {0,0,0,0,0,1,0,0},
        {0,1,0,1,1,0,0,1},
        {0,0,0,0,0,0,0,1},
        {1,1,0,1,0,1,1,0}};
    */
}

void PrintGraph(GraphList a)
{
    int i, j;
    GraphLink *target;
    int b[MAXSIZE][MAXSIZE];

    printf("\n此图的关系矩阵为:\n");

    for(i=0; i<MAXSIZE; i++)
    {
        target = a.table[i].first;

        printf("%c ", a.table[i].vex);

        for(j=0; j<MAXSIZE; j++)
        {
            b[i][j] = 0;
        }

        while(target != NULL)
        {
            j = (*target).value;
            b[i][j] = 1;
            target = target->next;
        }

        for(j=0; j<MAXSIZE; j++)
        {
            printf("%d ", b[i][j]);
        }
        printf("\n");
    }
}

void TraverseGraph(GraphList a, int x)
{
    int i;
    GraphLink *target;
    target = a.table[x].first;

    while(target != NULL)
    {
        i = (*target).value;
        if(1 != flag[i])
        {
            if(7 > n)
            {
                printf("%c->", a.table[i].vex);
            }
            else
            {
                printf("%c\n", a.table[i].vex);
            }
            flag[i] = 1;
            n++;
            TraverseGraph(a, i);
        }
        target = target->next;
    }
}

int main(void)
{
    int x;

    GraphList a;

    InitGraph(&a);

    PrintGraph(a);

    printf("\n请输入开始遍历的行数:\n");
    scanf("%d", &x);
    printf("\n遍历结果为:\n");
    printf("%c->", a.table[x].vex);
    flag[x] = 1;
    TraverseGraph(a, x);

    return 0;
}

马踏棋盘(图的深度优先遍历+回溯法):

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#define X 6
#define Y 6

int chess[X][Y];

//马的路径寻找过程
int NextTry(int *x, int *y, int count)
{
    switch(count)
    {
    case 0:
        if(*x+2 <= X-1 && *y-1 >= 0 && chess[*x+2][*y-1] == 0)
        {
            *x += 2;
            *y -= 1;
            return 1;
        }
        break;

    case 1:
        if(*x+2 <= X-1 && *y+1 <= Y-1 && chess[*x+2][*y+1] == 0)
        {
            *x += 2;
            *y += 1;
            return 1;
        }
        break;

    case 2:
        if(*x-2 >= 0 && *y-1 >= 0 && chess[*x-2][*y-1] == 0)
        {
            *x -= 2;
            *y -= 1;
            return 1;
        }
        break;

    case 3:
        if(*x-2 >= 0 && *y+1 <= Y-1 && chess[*x-2][*y+1] == 0)
        {
            *x -= 2;
            *y += 1;
            return 1;
        }
        break;

    case 4:
        if(*x+1 <= X-1 && *y-2 >= 0 && chess[*x+1][*y-2] == 0)
        {
            *x += 1;
            *y -= 2;
            return 1;
        }
        break;

    case 5:
        if(*x+1 <= X-1 && *y+2 <= Y-1 && chess[*x+1][*y+2] == 0)
        {
            *x += 1;
            *y += 2;
            return 1;
        }
        break;

    case 6:
        if(*x-1 >= 0 && *y-2 >= 0 && chess[*x-1][*y-2] == 0)
        {
            *x -= 1;
            *y -= 2;
            return 1;
        }
        break;

    case 7:
        if(*x-1 >= 0 && *y+2 <= Y-1 && chess[*x-1][*y+2] == 0)
        {
            *x -= 1;
            *y += 2;
            return 1;
        }
        break;

    default:
        break;
    }
    return 0;
}

void PrintChess()
{
    int i, j;

    for(i=0; i<X; i++)
    {
        for(j=0; j<Y; j++)
        {
            printf("%2d ",chess[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

//深度优先遍历棋盘
//(x,y)为位置坐标
//tag是标记变量,每走一步,tag+1
int TravelChessBoard(int x, int y, int tag)
{
    int x1 = x, y1 = y, flag = 0, count = 0;
    chess[x][y] = tag;

    if(X*Y == tag)
    {
        PrintChess();
        return 1;
    }

    //找到马的下一个可走的坐标(x1,y1),如果找到flag=1,否则为0
    flag = NextTry(&x1, &y1, count);
    while( 0 == flag && count < 7 )
    {
        count++;
        flag = NextTry(&x1, &y1, count);
    }

    while( flag )
    {
        if( TravelChessBoard(x1, y1, tag+1) )
        {
            return 1;
        }

        //继续找,找马的下一个可走坐标
        x1 = x;
        y1 = y;
        count++;

        flag = NextTry(&x1, &y1, count);
        while( 0 == flag && count < 7 )
        {
            count++;
            flag = NextTry(&x1, &y1, count);
        }
    }

    if( 0 == flag )
    {
        chess[x][y] = 0;
    }

    return 0;
}

int main(void)
{
    int i, j;

    clock_t start, finish;

    start = clock();

    for(i=0; i<X; i++)
    {
        for(j=0; j<Y; j++)
        {
            chess[i][j] = 0;
        }
    }

    if( !TravelChessBoard(2, 0, 1) )
    {
        printf("Travel failed!\n");
    }

    finish = clock();
    printf("\nThe run time: %f s\n", (double)(finish-start)/CLOCKS_PER_SEC);

    return 0;
}

广度优先遍历:用队列实现

/*邻接矩阵的广度遍历实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 8

typedef struct _GraphArray
{
    char vex[MAXSIZE];
    unsigned int value[MAXSIZE][MAXSIZE];
}GraphArray;

typedef struct _QNode
{
    char data;
    struct _QNode *next;
}QNode;

typedef struct
{
    QNode *front, *rear;
}LinkQueue;

int flag[MAXSIZE];
int n = 1;

void Initgraph(GraphArray *a)
{
    int i, j, k;
    char c;

    for(i=0; i<MAXSIZE; i++)
    {
        flag[i] = 0;

        k = i + 65;
        (*a).vex[i] = (char) k;

        printf("请输入第%d行的数据,以#结束:\n", i+1);
        fflush(stdin);
        scanf("%c", &c);
        for(j=0; j<MAXSIZE && '#' != c; j++)
        {
            (*a).value[i][j] = c - 48;
            scanf("%c", &c);
        }
    }
}

void InitQueue(LinkQueue *q)
{
    q->front = q->rear = (QNode *)malloc(sizeof(QNode));
    if( !q->front )
    {
        exit(0);
    }
    q->front->next = NULL;
}

void InsertQueue(LinkQueue *q, char c)
{
    QNode *temp;
    temp = (QNode *)malloc(sizeof(QNode));
    if( !temp )
    {
        exit(0);
    }

    temp->data = c;
    temp->next = q->rear->next;
    q->rear->next = temp;
    q->rear = temp;
}

void DeleteQueue(LinkQueue *q, char *c)
{
    QNode *temp;
    if(q->front == q->rear)
    {
        return;
    }

    temp = q->front->next;
    *c = temp->data;
    q->front->next = temp->next;

    if(q->rear == temp)
    {
        q->rear = q->front;
    }
    free(temp);
}

void TraverseWidth(GraphArray a, LinkQueue *q, int x)
{
    int j;
    char c;

    for(j=0; j<MAXSIZE; j++)
    {
        if(1 == a.value[x][j] && flag[j] == 0)
        {
            //j所代表顶点入队列操作
            c = a.vex[j];
            InsertQueue(q, c);
            flag[j] = 1;
        }
    }

    //第一个入队列的顶点出队列
    DeleteQueue(q, &c);

    //记录第一个出队列的顶点下标,为下次递归准备
    for(j=0; j<MAXSIZE; j++)
    {
        if(c == a.vex[j])
        {
            x = j;
        }
    }

    if(7 > n)
    {
        printf("%c->", c);
    }
    else
    {
        printf("%c", c);
        return;
    }
    n++;
    TraverseWidth(a, q, x);
}

int main(void)
{
    GraphArray a;
    LinkQueue q;
    int x;

    InitQueue(&q);

    Initgraph(&a);

    printf("\n请输入开始遍历的行数:\n");
    scanf("%d", &x);
    printf("\n此图的广度遍历结果为:\n");
    printf("%c->", a.vex[x]);
    flag[x] = 1;
    TraverseWidth(a, &q, x);

    return 0;
}
/*邻接表的广度遍历实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 8

typedef struct _GraphLink
{
    unsigned int value;
    struct _GraphLink *next;
}GraphLink;

typedef struct _GraphNode
{
    char vex;
    GraphLink *first;
}GraphNode;

typedef struct _GraphList
{
    GraphNode table[MAXSIZE];
}GraphList;

typedef struct _QNode
{
    char data;
    struct _QNode *next;
}QNode;

typedef struct
{
    QNode *front;
    QNode *rear;
}Queue;

int flag[MAXSIZE];
int n = 0;

void InitQueue(Queue *q)
{
    q->front = q->rear = (QNode *)malloc(sizeof(QNode));

    if( !q->front )
    {
        exit(0);
    }

    q->front->next = NULL;
}

void InsertQueue(Queue *q, char c)
{
    QNode *temp;

    temp = (QNode *)malloc(sizeof(QNode));
    if( !temp )
    {
        exit(0);
    }

    temp->data = c;
    temp->next = q->rear->next;
    q->rear->next = temp;
    q->rear = temp;
}

void DeleteQueue(Queue *q, char *c)
{
    QNode *temp;

    temp = q->front->next;
    *c = temp->data;
    q->front->next = temp->next;

    if(q->rear == temp)
    {
        q->rear = q->front;
    }

    free(temp);
}

void InitGraph(GraphList *l)
{
    GraphLink *temp, *target;
    int i, j;
    char c;

    for(i=0; i<MAXSIZE; i++)
    {
        (*l).table[i].first = NULL;
        flag[i] = 0;

        j = i + 65;
        (*l).table[i].vex = (char) j;

        printf("请输入与顶点%c有关的顶点下标,以#结束:\n", (*l).table[i].vex);
        fflush(stdin);
        scanf("%c", &c);
        while(c != '#')
        {
            temp = (GraphLink *)malloc(sizeof(GraphLink));
            if( !temp )
            {
                exit(0);
            }

            temp->value = c - 48;

            if((*l).table[i].first == NULL)
            {
                (*l).table[i].first = temp;
                temp->next = NULL;
                target = temp;
            }
            else
            {
                target->next = temp;
                temp->next = NULL;
                target = temp;
            }

            scanf("%c", &c);
        }
    }
}

void TraverseGraph(GraphList l, Queue *q, int i)
{
    GraphLink *target;
    int j;
    char c;

    target = l.table[i].first;
    //输入顶点的出队列操作
    if( flag[i] == 0 )
    {
        DeleteQueue(q, &c);
        printf("%c->", c);
        flag[i] = 1;
        n++;
    }
    //遍历该顶点的邻接表
    //将符合条件的顶点入队列
    while(target != NULL)
    {
        j = target->value;
        if(flag[j] == 0)
        {
            c = l.table[j].vex;
            InsertQueue(q, c);
            flag[j] = 1;
        }
        target = target->next;
    }
    //出队列的第一个顶点并记录值
    DeleteQueue(q, &c);

    if(7 > n)
    {
        printf("%c->", c);
    }
    else
    {
        printf("%c", c);
        return;
    }

    for(j=0; j<MAXSIZE; j++)
    {
        if(c == l.table[j].vex)
        {
            i = j;
        }
    }
    //递归
    n++;
    TraverseGraph(l, q, i);
}

int main(void)
{
    GraphList l;
    Queue q;
    int i, j, x;
    x = 1;

    InitQueue(&q);

    InitGraph(&l);

    while(x)
    {
        printf("\n请输入开始遍历的顶点下标:\n");
        scanf("%d", &i);
        InsertQueue(&q, l.table[i].vex);
        printf("\n此图的广度遍历结果为:\n");
        TraverseGraph(l, &q, i);

        n = 0;
        for(j=0; j<MAXSIZE; j++)
        {
            flag[j] = 0;
        }
        printf("\n\n要重新遍历吗?(1/0)\n");
        scanf("%d", &x);
    }

    return 0;
}

最小生成树:

普利姆算法(prime):邻接矩阵实现

/*Prim算法实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 9

typedef struct _Array
{
    char vex[MAXSIZE];
    unsigned int weight[MAXSIZE][MAXSIZE];
}Array;

typedef struct _Adjust
{
    unsigned int value[MAXSIZE];
}Adjust;

int n = 1;

void InitArray(Array *a)
{
    FILE *fp;
    int i, j;
    i = 0;

    if((fp=fopen("c:\\value.txt","r")) == NULL)
    {
        printf("Can not open the file!\n");
        exit(1);
    }

    while( !feof(fp) )
    {
        for(j=0; j<MAXSIZE; j++)
        {
            fscanf(fp, "%d,", &(*a).weight[i][j]);
        }
        (*a).vex[i] = (char) (i+65);
        i++;
    }
    fclose(fp);

    /*
    for(i=0; i<MAXSIZE; i++)
    {
        (*a).vex[i] = (char)(i+65);

        for(j=0; j<MAXSIZE; j++)
        {
            if(i == j)
            {
                (*a).weight[i][j] = 0;
            }
            else
            {
                (*a).weight[i][j] = 1000;
            }
        }

        printf("是否有与顶点%c相连的点?(1/0)\n", (*a).vex[i]);
        scanf("%d", &k);
        while(1 == k)
        {
            printf("\n请输入与顶点%c相连的点的下标:\n", (*a).vex[i]);
            scanf("%d", &j);
            printf("\n请输入与该点的边的权值:\n");
            scanf("%d", &k);
            (*a).weight[i][j] = k;
            printf("\n还有与顶点%c相连的点吗?(1/0)\n", (*a).vex[i]);
            scanf("%d", &k);
        }
        printf("\n");
    }
    */
}

void Print(Array a)
{
    int i, j;

    printf("\n此图的权值矩阵为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%c ", a.vex[i]);
        for(j=0; j<MAXSIZE; j++)
        {
            if(a.weight[i][j] == 1000)
            {
                printf(" * ");
            }
            else
            {
                printf("%2d ", a.weight[i][j]);
            }
        }
        printf("\n");
    }
}

void Prim(Array *a, Adjust *b, int x)
{
    int i, j, k, y, min;
    min = 1000;

    /*用权值数组与原矩阵除开始行外每一行作比较,记录较小值*/
    if(n > 1)
    {
        for(j=0; j<MAXSIZE; j++)
        {
            if(0 != (*b).value[j] && (*b).value[j] > (*a).weight[x][j])
            {
                (*b).value[j] = (*a).weight[x][j];
                y = j;
            }
        }
    }
    /*找到此时权值数组里的最小值并用min记录*/
    for(j=0; j<MAXSIZE; j++)
    {
        if(0 != (*b).value[j] && (*b).value[j] < min)
        {
            min = (*b).value[j];
            y = j;
        }
    }
    (*b).value[y] = 0;

    /*判断选中的边的开头顶点*/
    for(j=0; j<MAXSIZE; j++)
    {
        for(k=0; k<MAXSIZE; k++)
        {
            if((*b).value[j] == 0 && min == (*a).weight[j][k] && j != y)
            {
                i = j;
            }
        }
    }

    if(n < MAXSIZE-1)
    {
        printf("%c->%d->%c  ", (*a).vex[i], min, (*a).vex[y]);
    }
    else
    {
        printf("%c->%d->%c", (*a).vex[i], min, (*a).vex[y]);
        return;
    }
    n++;
    Prim(a, b, y);
}

int main(void)
{
    Array a;
    Adjust b;
    int x, j;

    InitArray(&a);

    Print(a);

    printf("请输入开始计算的行数:\n");
    scanf("%d", &x);

    for(j=0; j<MAXSIZE; j++)
    {
        b.value[j] = a.weight[x][j];
    }

    Prim(&a, &b, x);

    return 0;
}

克鲁斯卡尔算法(Kruskal):边集数组实现

/*克鲁斯卡尔算法实现*/
#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 14

typedef struct _LineNode
{
    unsigned int begin;
    unsigned int end;
    unsigned int weight;
}LineNode;

typedef struct _Array
{
    LineNode edges[MAXSIZE];
}Array;

char vex[9];

void InitArray(Array *a)
{
    FILE *fp;
    int i = 0;

    if((fp=fopen("c:\\edges.txt", "r")) == NULL)
    {
        printf("Can not open file!\n");
        exit(1);
    }

    while( !feof(fp) )
    {
        fscanf(fp, "%d,%d,%d", &(*a).edges[i].begin, &(*a).edges[i].end, &(*a).edges[i].weight);
        i++;
    }
    fclose(fp);

    for(i=0; i<9; i++)
    {
        vex[i] = (char) (i+65);
    }
}

void Print(Array a)
{
    int i, j, k;

    printf("此图的边集数组为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        j = a.edges[i].begin;
        k = a.edges[i].end;
        printf("[%c,%c,%d]\n", vex[j], vex[k], a.edges[i].weight);
    }
    printf("\n");
}

int Find(int *record, int f)
{
    while( record[f] > 0 )
    {
        f = record[f];
    }
    return f;
}

void Kruskal(Array *a)
{
    int i, m, n;
    int x, y;
    int record[9];

    for(i=0; i<9; i++)
    {
        record[i] = 0;
    }

    printf("此图的最小生成树为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        m = Find(record,(*a).edges[i].begin);
        n = Find(record,(*a).edges[i].end);

        if( m != n )
        {
            x = (*a).edges[i].begin;
            y = (*a).edges[i].end;
            printf("(%c, %c) %d\n", vex[x], vex[y], (*a).edges[i].weight);
            record[m] = n;
        }
    }
    printf("\n");
}

int main(void)
{
    Array a;

    InitArray(&a);

    Print(a);

    Kruskal(&a);

    return 0;
}

最短路径:

网图:两顶点经过的边上权值之和最少路径(花费最少)

非网图:两顶点经过边最少的路径(中转最少)

迪杰斯特拉算法(Dijkstra):

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 9

typedef struct _Array
{
    char vex[MAXSIZE];
    unsigned int weight[MAXSIZE][MAXSIZE];
}Array;

int flag[MAXSIZE];
int D[MAXSIZE];
int P[MAXSIZE];

void InitArray(Array *a)
{
    FILE *fp;
    int i, j;
    i = 0;

    if((fp=fopen("c://Dijkstra.txt", "r")) == NULL)
    {
        printf("Can not open file!\n");
        exit(1);
    }

    while( !feof(fp) )
    {
        for(j=0; j<MAXSIZE; j++)
        {
            fscanf(fp, "%d,", &(*a).weight[i][j]);
        }
        i++;
    }

    fclose(fp);

    for(j=0; j<MAXSIZE; j++)
    {
        (*a).vex[j] = (char) (j+65);
        flag[j] = 0;
        D[j] = 0;
        P[j] = 0;
    }
}

void Print(Array a)
{
    int i, j;

    printf("此图的权值矩阵为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%c ", a.vex[i]);
        for(j=0; j<MAXSIZE; j++)
        {
            if(1000 == a.weight[i][j])
            {
                printf("* ");
            }
            else
            {
                printf("%d ", a.weight[i][j]);
            }
        }
        printf("\n");
    }
}

void Dijkstra(Array *a, int x, int y)
{
    int i, j, k, min;

    flag[x] = 1;
    for(i=0; i<MAXSIZE; i++)
    {
        D[i] = (*a).weight[x][i];
    }

    for(j=1; j<MAXSIZE; j++)
    {
        min = 1000;
        for(i=0; i<MAXSIZE; i++)
        {
            if(!flag[i] && D[i] < min)
            {
                min = D[i];
                k = i;
            }
        }
        flag[k] = 1;

        for(i=0; i<MAXSIZE; i++)
        {
            if(!flag[i] && min+(*a).weight[k][i] < D[i])
            {
                D[i] = min + (*a).weight[k][i];
                P[i] = k;
            }
        }
    }

    printf("%c点到%c点的最小距离为%d",(*a).vex[x], (*a).vex[y], D[y]);
}

int main(void)
{
    Array a;
    int x, y;

    InitArray(&a);

    Print(a);

    printf("\n请输入起点下标与终点下标,以空格隔开:\n");
    scanf("%d %d", &x, &y);

    Dijkstra(&a, x, y);

    return 0;
}

弗洛伊德算法(Floyd):

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 9

typedef struct _GraphNode
{
    unsigned int value[MAXSIZE][MAXSIZE];
}GraphNode;

char vex[MAXSIZE];

void InitGraph(GraphNode *g)
{
    FILE *fp;
    int i = 0, j;

    if((fp=fopen("c://Dijkstra.txt", "r")) == NULL)
    {
        printf("Can't open the file");
        exit(1);
    }

    while( !feof(fp) )
    {
        for(j=0; j<MAXSIZE; j++)
        {
            fscanf(fp, "%d,", &(*g).value[i][j]);
            //(*h).value[i][j] = (*g).value[i][j];
        }
        i++;
    }

    fclose(fp);

    for(j=0; j<MAXSIZE; j++)
    {
        vex[j] = (char) (j+65);
    }
}

void PrintGraph(GraphNode g)
{
    int i, j;

    printf("此图的权值矩阵为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%c ", vex[i]);
        for(j=0; j<MAXSIZE; j++)
        {
            if(1000 == g.value[i][j])
            {
                printf("* ");
            }
            else
            {
                printf("%d ", g.value[i][j]);
            }
        }
        printf("\n");
    }
}

void Floyd(GraphNode *g, int x, int y)
{
    GraphNode D, P;
    int i, j, k, v;

    //D数组(最短距离记录数组)和P数组(存放前驱顶点)初始化
    for(i=0; i<MAXSIZE; i++)
    {
        for(j=0; j<MAXSIZE; j++)
        {
            D.value[i][j] = (*g).value[i][j];
            P.value[i][j] = j;
        }
    }

    for(k=0; k<MAXSIZE; k++)
    {
        for(i=0; i<MAXSIZE; i++)
        {
            for(j=0; j<MAXSIZE; j++)
            {
                if( D.value[i][j] > D.value[i][k] + D.value[k][j] )
                {
                    D.value[i][j] = D.value[i][k] + D.value[k][j];    //对值进行比较记录
                    P.value[i][j] = P.value[i][k];              //存放其前驱结点的数字
                }
            }
        }
    }

    printf("\n从%c点到%c点的最短距离为: %d\n", vex[x], vex[y], D.value[x][y]);
    printf("\n路径从终点到起点依次为:\n");
    v = P.value[x][y];
    printf("%c->", vex[x]);
    while( v != y )
    {
        printf("%c->", vex[v]);
        v = P.value[v][y];
    }
    printf("%c\n", vex[y]);
}

int main()
{
    GraphNode g;
    int x, y;

    InitGraph(&g);

    PrintGraph(g);

    printf("\n请输入起点和终点下标:\n");
    scanf("%d %d", &x, &y);

    Floyd(&g, x, y);

    return 0;
}

拓扑排序:

DAG图:一个无环的有向图

活动:工程或者流程当中的若干个小阶段

在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网

拓扑序列:在G=(V, E)是一个具有n个顶点的有向图,V中的顶点序列V1,V2,...,Vn满足若从顶点Vi到Vj有一条路径,则在顶点序列中顶点Vi必在顶点Vj之前,则我们称这样的顶点序列为一个拓扑序列

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 15

typedef struct _TableNode
{
    unsigned int num;
    struct _TableNode *next;
}TableNode;

typedef struct _ArrayNode
{
    int data;
    unsigned int in;
    TableNode *first;
}ArrayNode;

typedef struct
{
    ArrayNode Gra[MAXSIZE];
}ArrayList;

void InitList(ArrayList *g)
{
    FILE *fp;
    TableNode *temp, *target;
    int i = 0, j, k;

    if( (fp = fopen("c://course.txt", "r")) == NULL )
    {
        printf("Can not open the file!\n");
        exit(1);
    }

    while( !feof(fp) )
    {
        fscanf(fp, "%d,%d,%d", &(*g).Gra[i].in, &(*g).Gra[i].data, &j);

        (*g).Gra[i].first = NULL;
        target = (*g).Gra[i].first;

        while( j != 0 )
        {
            temp = (TableNode *)malloc(sizeof(TableNode));

            if( !temp )
            {
                printf("分配动态内存失败!\n");
                exit(1);
            }

            printf("请输入C%d的下一个顶点下标:\n", (*g).Gra[i].data);
            scanf("%d", &k);

            temp->num = k;
            temp->next = NULL;

            if((*g).Gra[i].first == NULL)
            {
                (*g).Gra[i].first = temp;
            }
            else
            {
                target->next = temp;
            }
            target = temp;

            j--;
        }
        i++;
    }

    fclose(fp);
}

void Print(ArrayList g)
{
    TableNode *target;
    int i;

    printf("\n此图的邻接表为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        target = g.Gra[i].first;
        printf("%d,C%d ", g.Gra[i].in, g.Gra[i].data);
        while(target != NULL)
        {
            if(target->next == NULL)
            {
                printf("%d", target->num);
            }
            else
            {
                printf("%d->", target->num);
            }
            target = target->next;
        }
        printf("\n");
    }
}

void TopoSort(ArrayList *g)
{
    TableNode *target;
    int top = 0, count = 0;
    int i, value, n;
    int *stack;

    stack = (int *)malloc(MAXSIZE * sizeof(int));

    for(i=0; i<MAXSIZE; i++)
    {
        if( 0 == (*g).Gra[i].in )
        {
            stack[++top] = i;
        }
    }

    while( 0 != top )   //因此判断条件,不能使用stack[0]这个元素存储数据
    {
        value = stack[top--];
        printf("C%d->", (*g).Gra[value].data);
        count++;

        target = (*g).Gra[value].first;
        while(target != NULL)
        {
            n = target->num - 1;
            (*g).Gra[n].in--;
            if( (*g).Gra[n].in == 0 )
            {
                stack[++top] = n;
            }
            target = target->next;
        }
    }

    if( count < MAXSIZE )
    {
        printf("此图有回环!\n");
    }
    else
    {
        printf("拓扑结束\n");
    }
}

int main(void)
{
    ArrayList g;

    InitList(&g);

    Print(g);

    TopoSort(&g);

    return 0;
}

关键路径:

AOE网:在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间

etv:事件最早发生时间(从前往后算)

ltv:事件最晚发生时间(从后往前算)

ete:活动最早发生时间(从前往后算)

lte:活动最晚发生时间(从后往前算)

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 9

typedef struct _LinkNode
{
    int num;
    int weight;
    struct _LinkNode *next;
}LinkNode;

typedef struct _ArrayNode
{
    int in;
    int data;
    LinkNode *first;
}ArrayNode;

typedef struct _ArrayList
{
    ArrayNode vex[MAXSIZE];
}ArrayList;

int *etv, *ltv;
int *stack2;
int top2 = 0;

void InitList(ArrayList *g)
{
    FILE *fp;
    LinkNode *temp, *target;
    int i = 0;
    int j;

    if( (fp=fopen("c://CriPath.txt", "r"))==NULL )
    {
        printf("Can not open the file!\n");
        exit(1);
    }

    while(!feof(fp))
    {
        fscanf(fp, "%d,%d,%d", &g->vex[i].data, &g->vex[i].in, &j);

        g->vex[i].first = NULL;
        target = g->vex[i].first;
        while(j)
        {
            temp = (LinkNode *)malloc(sizeof(LinkNode));
            printf("请输入与顶点%d相连的点的下标以及它们之间的边的值:\n", g->vex[i].data);
            scanf("%d %d", &temp->num, &temp->weight);
            temp->next = NULL;

            if(g->vex[i].first == NULL)
            {
                g->vex[i].first = temp;
            }
            else
            {
                target->next = temp;
            }
            target = temp;
            j--;
        }
        i++;
    }
}

void PrintList(ArrayList g)
{
    LinkNode *target;
    int i;

    printf("\n此图的邻接表形式为:\n");
    for(i=0; i<MAXSIZE; i++)
    {
        printf("%d %d ", g.vex[i].data, g.vex[i].in);
        target = g.vex[i].first;
        while(target)
        {
            printf("->(%d,%d)", target->num, target->weight);
            target = target->next;
        }
        printf("\n");
    }
}

void TopoSort(ArrayList *g)
{
    LinkNode *target;
    int *stack;
    int top = 0, count = 0;
    int i, j, value;

    stack = (int *)malloc(MAXSIZE * sizeof(int));
    for(i=0; i<MAXSIZE; i++)
    {
        if(g->vex[i].in == 0)
        {
            stack[++top] = i;
        }
    }

    etv = (int *)malloc(MAXSIZE * sizeof(int));
    stack2 = (int *)malloc(MAXSIZE * sizeof(int));

    for(i=0; i<MAXSIZE; i++)
    {
        etv[i] = 0;
    }

    while(top != 0)
    {
        value = stack[top--];
        stack2[++top2] = value;
        count++;
        target = g->vex[value].first;

        while(target)
        {
            j = target->num - 1;
            if((--g->vex[j].in) == 0)
            {
                stack[++top] = j;
            }

            if(etv[value] + target->weight > etv[j])
            {
                etv[j] = etv[value] + target->weight;
            }

            target = target->next;
        }
    }

    if(count < MAXSIZE)
    {
        printf("\n存在回环!\n");
    }
    else
    {
        printf("\n排序完毕,不存在回环\n");
    }
}

void CriPath(ArrayList *g)
{
    LinkNode *target;
    int i, j, value;
    int ete, lte;

    TopoSort(g);

    //初始化ltv
    ltv = (int *)malloc(MAXSIZE * sizeof(int));
    for(i=0; i<MAXSIZE; i++)
    {
        ltv[i] = etv[MAXSIZE-1];
    }

    //从汇点倒过来逐个计算ltv
    while(top2 != 0)
    {
        value = stack2[top2--];
        for(target=g->vex[value].first; target != NULL; target = target->next)
        {
            j = target->num - 1;

            if((ltv[j] - target->weight) < ltv[value])
            {
                ltv[value] = ltv[j] - target->weight;
            }
        }
    }

    //通过etv和ltv求ete和lte
    for(i=0; i<MAXSIZE; i++)
    {
        for(target=g->vex[i].first; target != NULL; target = target->next)
        {
            j = target->num - 1;
            ete = etv[i];
            lte = ltv[j] - target->weight;

            if(ete == lte)
            {
                printf("(%d,%d) length:%d , ", g->vex[i].data, g->vex[j].data, target->weight);
            }
            printf("\n");
        }
    }
}

int main()
{
    ArrayList g;

    InitList(&g);

    PrintList(g);

    CriPath(&g);

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值