数据结构-实验五

图的操作

实验内容:

(1)采用邻接矩阵/邻接表建立图;

(2)采用深度优先/广度优先搜索方式遍历图;

(3)编程实现Dijkstra最短路径算法。

1.采用邻接表建立图的代码如下

#include<iostream>
#include<cstring>
#include<malloc.h>
#include <algorithm>
#include <queue>

#define MAX_VERTEX 20
#define GQSIZE 20
#define maxnum 120
#define INF 10000000

using namespace std;

typedef char VertexType;  //各个结构体的定义

typedef struct ANode{
	int AdjVex;
	struct ANode *NextArc;
}ArcNode;

typedef struct VNode{
	VertexType Data;
	ArcNode *FirstArc;
}VerNode,AdjList[MAX_VERTEX];

typedef struct Graph{
	AdjList Vertices;   //相当于VerNode Vertices[MAX_VERTEX];
	int VerNum, ArcNum;
}ALGraph;

typedef struct Queue{
	int Base[GQSIZE];
	int front, rear;
}GCQueue;

int LocateVex(ALGraph G, VertexType V)
{
	int i = 0;
	while (i<G.VerNum && V!=G.Vertices[i].Data)
	{
		i++;
	}
	if (i < G.VerNum)
		return i;
	else
	{
		return -1;
	}
}

void CreateGraph(ALGraph &G)   //创建无向图(包括生成相应的邻接表)
{
	int VNum, ANum;
	VertexType V1, V2;
	cout << "请分别输入顶点数和边数:" << endl;
	cin >> VNum >> ANum;
	G.VerNum = VNum;
	G.ArcNum = ANum;
	cout << "请输入各顶点:" << endl;
	for (int i = 0; i != G.VerNum; i++)
	{
		cin >> G.Vertices[i].Data;
		G.Vertices[i].FirstArc = NULL;
	}
	for (int j = 0; j != G.ArcNum; j++)
	{
		cout << "请输入边所在的两顶点:" << endl;
		cin >> V1 >> V2;
		int k = LocateVex(G, V1);
		int l = LocateVex(G, V2);

		if (k >= 0 && l >= 0)
		{
			ArcNode *P = (ArcNode*)malloc(sizeof(ArcNode));
			P->AdjVex = l;
			P->NextArc = NULL;
			if (!G.Vertices[k].FirstArc)
				G.Vertices[k].FirstArc = P;
			else
			{
				ArcNode *L = G.Vertices[k].FirstArc;
				while (L->NextArc)
				{
					L = L->NextArc;
				}
				L->NextArc = P;
			}
		}
		else
			cout << "没有这条边!!" << endl;
	}

	cout << endl;
	cout << "输出邻接表:" << endl;
	for (int i = 0; i != G.VerNum; i++)
	{
		cout <<i << G.Vertices[i].Data;
		ArcNode *H = G.Vertices[i].FirstArc;
		while (H)
		{
			cout <<"->"<< H->AdjVex;
			H = H->NextArc;
		}
		cout << endl;
	}
}

int FirstAdjvex(ALGraph G, int v)  //查找第一个邻接点
{
	if (G.Vertices[v].FirstArc)
		return G.Vertices[v].FirstArc->AdjVex;
	else return -1;
}

int NextAdjvex(ALGraph G, int v, int w)  //查找下一个邻接点
{
	int flag = 0;
	ArcNode *P = G.Vertices[v].FirstArc;
	while (P)
	{
		if (P->AdjVex == w)
		{
			flag = 1;
			break;
		}
		else
			P = P->NextArc;
	}
	if (flag&&P->NextArc)
		return P->NextArc->AdjVex;
	else return -1;
}

bool Visited[MAX_VERTEX];
void DFS(ALGraph G, int v)  //递归的深度优先搜索
{
	Visited[v] = true;
	cout << G.Vertices[v].Data << " ";
	for (int w = FirstAdjvex(G, v); w >= 0; w = NextAdjvex(G, v, w))
	{
		if (!Visited[w])
			DFS(G, w);
	}
}
void DFSTraverse(ALGraph G)
{
	for (int v = 0; v != G.VerNum; v++)   //此处for语句不可和下面for语句合并,这是先前的初始化,放在下面会导致初始化前就会被赋值
	{
		Visited[v] = false;
	}
	for (int v = 0; v !=G.VerNum; v++)
	{
		if (!Visited[v])
			DFS(G, v);
	}
	cout << endl;
}

void BFSTraverse(ALGraph G)  //基于队列的广度优先搜索
{
	GCQueue Q;
	Q.front = Q.rear = 0;
	for (int v = 0; v != G.VerNum; v++)
	{
		Visited[v] = false;
	}
	for (int v = 0; v != G.VerNum; v++)
	{
		if (!Visited[v])
		{
			Visited[v]=true;
			cout << G.Vertices[v].Data << " ";
			if (((Q.rear + 1) % GQSIZE) == Q.front)
			{
				cout << "队满,不能入队!!!" << endl;
				return;
			}
			Q.Base[Q.rear] = v;
			Q.rear = (Q.rear + 1) % GQSIZE;

			while (Q.rear!=Q.front)
			{
				int u = Q.Base[Q.front];
				Q.front = (Q.front + 1) % GQSIZE;
				for (int w = FirstAdjvex(G, u); w >= 0; w = NextAdjvex(G, u, w))
				{
					if (!Visited[w])
					{
						Visited[w] = true;
						cout << G.Vertices[w].Data << " ";
						if (((Q.rear + 1) % GQSIZE) == Q.front)
						{
							cout << "队满,不能入队!!!" << endl;
							return;
						}
						Q.Base[Q.rear] = w;
						Q.rear = (Q.rear + 1) % GQSIZE;

					}
				}

			}

		}
	}
}
int main()
{
	ALGraph G;
	CreateGraph(G);
	cout << "深度优先遍历为:";
	DFSTraverse(G);
	cout << endl;
	cout << "广度优先遍历为:";
	BFSTraverse(G);
	cout << endl;
	return 0;
}

2.采用邻接矩阵建立图的代码如下:

#include <stdio.h>

#define MAX_VERTEX_NUM 20
#define MaxVex        100            //最大顶点数
#define INFINITY    65535        //表示∞
#define TRUE        1
#define    FALSE        0
typedef char        VertexType;    //顶点类型
typedef    int            EdgeType;    //权值类型
typedef int            Bool;
Bool    visited[MaxVex];

typedef struct {
    VertexType    vexs[MaxVex];            //顶点数组
    EdgeType    arc[MaxVex][MaxVex];    //邻接矩阵
    int    numVertexes, numEdges;            //当前图中的结点数以及边数
}MGraph;


//广度优先遍历需要的循环队列
typedef struct {
    int    data[MaxVex];
    int    front, rear;
}Queue;


/****************************************/
//队列的相关操作

//初始化
void InitQueue(Queue *Q)
{
    Q->front = Q->rear = 0;
}

//入队
void EnQueue(Queue *Q, int e)
{
    if ((Q->rear+1)%MaxVex == Q->front)
        return ;

    Q->data[Q->rear] = e;
    Q->rear = (Q->rear+1)%MaxVex;
}

//判空
Bool QueueEmpty(Queue *Q)
{
    if (Q->front == Q->rear)
        return TRUE;
    else
        return FALSE;
}

//出队
void DeQueue(Queue *Q, int *e)
{
    if (Q->front == Q->rear)
        return ;

    *e = Q->data[Q->front];
    Q->front = (Q->front+1)%MaxVex;
}
/****************************************/


//建立图的邻接矩阵
void CreateMGraph(MGraph *G)
{
    int i, j, k, w;

    printf("输入顶点数和边数: ");
    scanf("%d%d", &G->numVertexes,&G->numEdges);
    fflush(stdin);

    printf("==============================\n");
    printf("输入各个顶点:\n");
    for (i=0; i<G->numVertexes; ++i)
    {
        printf("顶点%d: ",i+1);
        scanf("%c", &G->vexs[i]);
        fflush(stdin);
    }

    for (i=0; i<G->numVertexes; ++i)
    {
        for (j=0; j<G->numVertexes; ++j)
            G->arc[i][j] = INFINITY;
    }

    printf("==============================\n");
    for (k=0; k<G->numEdges; ++k)
    {
        printf("输入边(vi, vj)中的下标i和j和权W: ");
        scanf("%d%d%d", &i,&j,&w);
        G->arc[i][j] = w;
        G->arc[j][i] = G->arc[i][j];
    }
}


//输出
void DisMGraph(MGraph *G)
{
    int i, j, k;
    k = G->numVertexes;
    for (i=0; i<k; ++i)
    {
        for (j=0; j<k; ++j)
        {
            printf("%5d ", G->arc[i][j]);
        }
        putchar('\n');
    }
}


/****************************************/
//图的深度优先遍历
void DFS(MGraph G, int i)
{
    int j;
    visited[i] = TRUE;
    printf("%c ",    G.vexs[i]);

    for (j=0; j<G.numVertexes; ++j)
    {
        if (G.arc[i][j]!=INFINITY  &&  !visited[j])
            DFS(G, j);
    }
}

void DFSTraverse(MGraph G)
{
    int i;
    for (i=0; i<G.numVertexes; ++i)
        visited[i] = FALSE;

    for (i=0; i<G.numVertexes; ++i)
    {
        if (!visited[i])
            DFS(G, i);
    }

}


//图的广度优先遍历
void BFSTraverse(MGraph *G)
{
    int i, j;
    Queue Q;

    for (i=0; i<G->numVertexes; ++i)
        visited[i] = FALSE;

    InitQueue(&Q);

    for (i=0; i<G->numVertexes; ++i)
    {
        if (!visited[i])
        {
            visited[i] = TRUE;
            printf("%c ", G->vexs[i]);
            EnQueue(&Q, i);

            while (!QueueEmpty(&Q))
            {
                DeQueue(&Q, &i);
                for (j=0; j<G->numVertexes; ++j)
                {
                    if (!visited[j] && G->arc[i][j]!=INFINITY)
                    {
                        visited[j] = TRUE;
                        printf("%c ", G->vexs[j]);
                        EnQueue(&Q, j);
                    }
                }
            }
        }
    }
}
/****************************************/


//程序入口
int main(){
    MGraph G;

    CreateMGraph(&G);

    printf("\n图的深度优先遍历为: ");
    DFSTraverse(G);

    printf("\n图的广度优先遍历为: ");
    BFSTraverse(&G);

    printf("\n");

    return 0;
}

 

3.迪杰特斯拉求最短路径代码如下:

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

#define INFINITY 10000      /* 假定弧上权值无穷大时为10000 */
#define MAX_VERTEX_NUM 100  /* 图中最大节点数 */
typedef char VexType;       /* 顶点类型设置为字符型 */
typedef int weight;         /* 弧上权值类型设置为整型 */
typedef struct              /* 弧表节点 */
{
    VexType vex[MAX_VERTEX_NUM];                 /* 图中节点 */
    weight edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];/* 邻接矩阵 */
    int vexnum;                                  /* 节点的数目 */
    int edgenum;                                 /* 弧的数目 */
}MGraph;

void CreateDG(MGraph * DG);          /* 邻接矩阵法创建有向图(directed graph) */
void PrintDG(MGraph DG);             /* 邻接矩阵形式输出图DG */
void ShortestPath_Dijkstra(MGraph DG, VexType StartVex);
                                     /* 从节点StartVex开始求最短路径 */
void locateVex(MGraph DG, VexType vex, int * index);
                                     /* 定位节点vex的下标并赋给index */

int main(void)
{
    MGraph g;

    CreateDG(&g);
    printf("------------------------------\n");
    printf("vexnum = %d ; edgenum = %d\n", g.vexnum, g.edgenum);
    printf("------------------------------\n");
    PrintDG(g);
    printf("------------------------------\n");
    ShortestPath_Dijkstra(g, '0');

    return 0;
}
void CreateDG(MGraph * DG)
{
    int i = 0, j, k, w;                 /* w:权值 */
    char ch;

    printf("请依次输入顶点数、弧数:");
    scanf("%d %d", &(DG->vexnum), &(DG->edgenum));

    printf("请依次输入顶点(以回车结束输入):");
    getchar();
    while ((ch = getchar()) != '\n')    /* 输入顶点信息 */
        DG->vex[i++] = ch;

    for (i = 0; i < DG->vexnum; i++)    /* 初始化邻接矩阵 */
        for (j = 0; j < DG->vexnum; j++)
            DG->edges[i][j] = INFINITY;

    printf("顶点 | 下标\n");
    for (i = 0; i < DG->vexnum; i++)    /* 显示图中顶点及其对应下标 */
    {
        printf("%3c%6d\n", DG->vex[i], i);
    }

    printf("请输入依次每条弧的弧尾下标(不带箭头)、弧头下标(带箭头)、权值(格式:i j w):\n");
    for (k = 0; k < DG->edgenum; k++)   /* 建立邻接矩阵 */
    {
        scanf("\n%d%d%d", &i, &j, &w);  /* 输入弧的两个节点及权值 */
        DG->edges[i][j] = w;            /* 将矩阵对应位置元素置为权值 */
    }
}
void PrintDG(MGraph DG)
{
    int i, j;

    for (i = 0; i < DG.vexnum; i++)         /* 输出邻接矩阵 */
    {
        for (j = 0; j < DG.vexnum; j++)
        {
            if (DG.edges[i][j] == INFINITY) /* 节点不连通时,输出无穷大 */
                printf("    ∞");
            else                            /* 节点连通时,输出弧上权值 */
                printf("%5d", DG.edges[i][j]);
        }
        printf("\n");
    }
}
void ShortestPath_Dijkstra(MGraph DG, VexType StartVex)
{
    int i, j, v, index,k;         /* index:开始节点下标 */
    int min;                    /* 开始节点到指定节点的最短路径权值和 */
    int final[DG.vexnum];       /* 集合S,元素值为1:下标为i的节点以加入集合S;为0:未加入 */
    int P[DG.vexnum][DG.vexnum];/* 开始节点到各节点的最短路径 */
    int D[DG.vexnum];           /* 开始节点到下标为i的节点的最短路径权值之和 */

    locateVex(DG, StartVex, &index);
    for (i = 0; i < DG.vexnum; i++)
    {
        final[i] = 0;                   /* 初始化,刚开始集合S为空 */
        D[i] = DG.edges[index][i];

        for (j = 0; j < DG.vexnum; j++) /* 初始化路径,假设所有节点都不连通 */
            P[i][j] = 0;
        if (D[i] < INFINITY)            /* 若节点连通,则在数组P[i]中标明路径 */
        {
            P[i][index] = 1;
            P[i][i] = 1;
        }
    }
    D[index] = 0; final[index] = 1;     /* 开始节点加入S集 */

    for (i = 1; i < DG.vexnum; i++)
    {
        min = INFINITY;
        for (j = 0; j < DG.vexnum; j++)
            if (!final[j])
                if (D[j] < min) { v = j; min = D[j]; }
        final[v] = 1;                   /* 把离StartVex最近的下标为v的节点加入S */

        for (j = 0; j < DG.vexnum; j++)
            if (!final[j] && (min + DG.edges[v][j] < D[j]))
            {/* 若下标为j的节点为加入S且有更短路径,则更新D[j]和最短路径 */
                D[j] = min + DG.edges[v][j];
                for ( k = 0; k < DG.vexnum; k++)
                   P[j][k] = P[v][k];
                P[j][j] = 1;
            }
    }

    printf("节点 %c 到各节点的最短路径:\n", StartVex);
    for (i = 0; i < DG.vexnum; i++)
    {
        for (j = 0; j < DG.vexnum; j++)
            printf("%5d", P[i][j]);
        printf("\n");
    }

    printf("节点 %c 到各节点的最短路径值:", StartVex);
    for (i = 0; i < DG.vexnum; i++)
    {
        if (D[i] == INFINITY)
            printf("∞, ");
        else
            printf("%d, ", D[i]);
    }
}
void locateVex(MGraph DG, VexType vex, int * index)
{
    int i;

    for (i = 0; i < DG.vexnum; i++)
    {
        if (DG.vex[i] == vex)
        {
            *index = i;
            return;
        }
    }
    printf("节点定位失败!\n");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值