【算法】基于邻接链表的图的遍历BFS(非递归)&DFS(递归/非递归)代码实现

C/C++代码实现

main.cpp
/****************************************************************
C语言实现--邻接链表实现图的创建 遍历 DFS & BFS 递归及非递归方法
*****************************************************************/
#define INF 65535
#define MAX_VERTEX_NUM 20 //最大顶点个数
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"SqStack.h"
#include"SqQueue.h"

typedef int VertexType;
typedef int InfoType;
typedef int AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef enum {
    DG,//有向图
    DN,//有向网
    UDG,//无向图
    UDN//无向网
} GraphKind;

typedef struct ArcNode {
    int adjvex;             //该弧指向的顶点的位置
    struct ArcNode* nextarc;//指向下一条弧的指针
    InfoType info;         //该弧的相关信息
}ArcNode;

typedef struct VNode {
    VertexType data;//顶点信息
    ArcNode* firstarc;//指向第一条依附该顶点的弧的指针
}VNode, AdjList[MAX_VERTEX_NUM];

typedef struct {
    AdjList vertices;
    int vexnum, arcnum;//图的顶点数 和 弧数
    int kind;//图的种类
}ALGraph;
int vis[MAX_VERTEX_NUM];

/*定位元素的位置*/
int LocateVertex(ALGraph& G, VertexType v)
{
    for (int i = 0; i < G.vexnum; i++)
    {
        if (G.vertices[i].data == v)
            return i;
    }
    return -1;
}

/*创建有向图*/
void CreateDG(ALGraph &G)
{
	ArcNode* p;
	for (int i = 0; i < G.vexnum; i++)
	{
		G.vertices[i].data = i + 1;
		G.vertices[i].firstarc = NULL;
	}

	for (int k = 0; k < G.arcnum; k++)
	{
		VertexType v1, v2;
		scanf("%d%d", &v1, &v2);
		int i = LocateVertex(G, v1);
		int j = LocateVertex(G, v2);
		/*j为入i为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j + 1;
		p->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p;
	}
}
/*创建有向网*/
void CreateDN(ALGraph &G)
{
	ArcNode* p;
	for (int i = 0; i < G.vexnum; i++)
	{
		G.vertices[i].data = i + 1;
		G.vertices[i].firstarc = NULL;
	}


	for (int k = 0; k < G.arcnum; k++)
	{
		VertexType v1, v2;
		int w;
		scanf("%d%d%d", &v1, &v2, &w);
		int i = LocateVertex(G, v1);
		int j = LocateVertex(G, v2);
		/*j为入i为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j + 1;
		p->info = w;
		p->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p;
	}
}
/*创建无向图*/
void CreateUDG(ALGraph &G)
{
	ArcNode* p;
	for (int i = 0; i < G.vexnum; i++)
	{
		G.vertices[i].data = i + 1;
		G.vertices[i].firstarc = NULL;
	}

	for (int k = 0; k < G.arcnum; k++)
	{
		VertexType v1, v2;
		scanf("%d%d", &v1, &v2);
		int i = LocateVertex(G, v1);
		int j = LocateVertex(G, v2);
		/*j为入i为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j + 1;
		p->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p;
		/*i为入j为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = i + 1;
		p->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p;
	}
}
/*创建无向网*/
void CreateUDN(ALGraph &G)
{
	ArcNode* p;
	for (int i = 0; i < G.vexnum; i++)
	{
		G.vertices[i].data = i + 1;
		G.vertices[i].firstarc = NULL;
	}

	for (int k = 0; k < G.arcnum; k++)
	{
		VertexType v1, v2;
		int w;
		scanf("%d%d%d", &v1, &v2, &w);
		int i = LocateVertex(G, v1);
		int j = LocateVertex(G, v2);
		/*j为入i为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = j + 1;
		p->info = w;
		p->nextarc = G.vertices[i].firstarc;
		G.vertices[i].firstarc = p;
		/*i为入j为出创建邻接链表*/
		//p = new ArcNode;
		p = (ArcNode*)malloc(sizeof(ArcNode));
		p->adjvex = i + 1;
		p->info = w;
		p->nextarc = G.vertices[j].firstarc;
		G.vertices[j].firstarc = p;
	}
}
/*打印图的邻接链表*/
void DisplayALGraph(ALGraph &G)
{
	ArcNode* p;
	for (int i = 0; i < G.vexnum; i++)
	{
		printf("%d-->", G.vertices[i].data);
		p = G.vertices[i].firstarc;
		if (p == NULL)
			printf("NULL");
		while (p)
		{
			if (G.kind == 1 || G.kind == 3)
				printf("%d ", p->adjvex);
			else if (G.kind == 2 || G.kind == 4)
				printf("%d,%d ", p->adjvex, p->info);
			p = p->nextarc;
		}
		printf("\n");
	}
}
/*
递归深度优先遍历
函数功能:DFS递归遍历图(邻接表)
函数说明:建立一个标记数组vis[], 若该顶点访问过就标记为1,否则置零;
递归的时候,从某个指定定点开始进行,遍历第一个邻接点,然后再遍历
邻接点的第一个邻接点......直到某个顶点没有未访问的邻接点,就退
出该层递归,然后再进入上一层递归,直到所有的顶点都没有未访问的顶点
dfs遍历结束。每一次大的for循环结束就找到了一个连通子集。
*/
void DFSRecursiveTraverse(ALGraph& G, int i)
{
	printf("%d ",G.vertices[i].data);//输出顶点值
	ArcNode* p = G.vertices[i].firstarc; //指向第一个邻接顶点
	vis[i] = 1; //v已经访问过了

	while (p)
	{
		VertexType u = p->adjvex - 1;//顶点序号
		if (!vis[u])//没访问过
		{
			DFSRecursiveTraverse(G, u);//从该节点的邻接点出发继续深度优先遍历
		}
		p = p->nextarc;//从某顶点出发深度优先遍历结束了 回溯到上一个顶点p 指向上一个节点的其他邻接点
	}
}

/*
非递归DFS遍历图
压栈的顺序就是深度优先遍历的顺序
3
8
9

1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 8
6 7
*/
void DFSNonrecursiveTraverse(ALGraph &G, int i){
    vis[i] = 1;//该顶点已经访问
    SqStack S;
    InitStack(S);
    Push(S, G.vertices[i].data);//将顶点压栈
    //printf("%d ",G.vertices[i].data);
    printf("%d 入栈\n", G.vertices[i].data);

    while(!IsEmptyS(S))
    {
        //栈不空
        VertexType e;
        GetTop(S, e);//得到栈顶元素
        int k = LocateVertex(G, e);
        ArcNode *p = G.vertices[k].firstarc;//指向第一个邻接点
        while(p)//只要有邻接点
        {
            int j = LocateVertex(G, p->adjvex);//定位顶点索引
            if(!vis[j])//该顶点没有被访问
            {
                //置访问标志
                vis[j] = 1;
                //压栈
                Push(S, G.vertices[j].data);
                printf("%d 入栈\n", G.vertices[j].data);
                //printf("%d ",G.vertices[j].data);
                p = G.vertices[j].firstarc;//指向下一顶点的第一个邻接点
            }
            else//该顶点已经被访问了
            {
                //继续访问下一个邻接点
                p = p->nextarc;
                //当某个顶点的所有邻接点都访问完之后 p就会变成NULL
            }
        }//此时退出循环
        if(p == NULL)
        {
            VertexType v;
            Pop(S, v);//将所有邻接点都访问完的顶点出栈
            printf("%d 出栈\n", v);
        }
    }

    ClearStack(S);
}


/*递归DFS遍历图*/
void DFSTraverse(ALGraph &G, int type)
{
    memset(vis, 0, sizeof(vis));//初始化为0
	for (int i = 0; i < G.vexnum; i++)
	{
		if (!vis[i] && type == 0)//递归
		{//遍历每个顶点
			DFSRecursiveTraverse(G, i);
		}

		if (!vis[i] && type == 1)//非递归
		{//遍历每个顶点
			DFSNonrecursiveTraverse(G, i);
		}
	}
}

/**************************************************************
函数功能:BFS非递归遍历图(邻接表)
函数说明:建立一个标记数组vis[],若该顶点访问过就标记为1,否则置零;
遍历的时候,首先找到一个未访问的顶点,入队,然后如果队列不空,就
一直循环,并且每次循环都要出队一个元素,再在以该元素为顶点的链表
或者矩阵的某一行中进行查找,如果某个顶点未访问,则进行访问,然后
vis置1,表示已经访问,再入队,直到队为空,退出本次循环,再查找顶
点表中的第二个顶点或者矩阵中的第二行,以此类推得到广度优先搜索序
列,每次大的循环其实就是一个连通子集。
***************************************************************/
void BFS(ALGraph &G, int i)
{
    vis[i] = 1;
    SqQueue Q;
    InitQueue(Q);
    EnQueue(Q, G.vertices[i].data);//入队
    printf("%d 入队\n", G.vertices[i].data);

    while(!IsEmptyQ(Q))
    {
        VertexType e;
        DeQueue(Q, e);
        printf("%d 出队\n", e);
        int k = LocateVertex(G, e);
        ArcNode *p = G.vertices[k].firstarc;
        while(p)
        {
            int j = LocateVertex(G, p->adjvex);
            if(!vis[j])
            {
                vis[j] = 1;//访问过了
                //入队
                EnQueue(Q, G.vertices[j].data);
                printf("%d 入队\n",G.vertices[j].data);
            }
            p = p->nextarc;
        }
    }

    ClearQueue(Q);
}

/*入队序列就是BFS遍历结果*/
void BFSTraverse(ALGraph &G)
{
    memset(vis, 0, sizeof(vis));//初始化为0

	for (int i = 0; i < G.vexnum; i++)
    {
        if(!vis[i])
        {
            BFS(G, i);
        }
    }
}




/*根据图的种类创建图*/
void CreateGraph(ALGraph &G)
{
    printf("请输入图的种类(1-有向图, 2-有向网, 3-无向图, 4-无向网):");
    scanf("%d", &G.kind);
    printf("请输入创建图的顶点数:");
    scanf("%d", &G.vexnum);
    printf("请输入创建的图的边/弧数:");
    scanf("%d", &G.arcnum);

    printf("请输入弧依附的顶点信息:\n");
    switch (G.kind)
    {
    case 1: //DG
        CreateDG(G);
        break;
    case 2: //DN
        CreateDN(G);
        break;
    case 3: //UDG
        CreateUDG(G);
        break;
    case 4: //UDN
        CreateUDN(G);
        break;
    }
}

int main() {
	ALGraph G;
	CreateGraph(G);
	DisplayALGraph(G);
	printf("DFS递归遍历结果:");
	DFSTraverse(G, 0);
	printf("\n");
	printf("DFS非递归遍历结果:\n");
	DFSTraverse(G, 1);
    printf("\n");
    printf("BFS非递归遍历结果:\n");
    BFSTraverse(G);
    printf("\n");
	return 0;
}
SqQueue.h
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define QUEUE_INIT_SIZE 100
#define OVERFLOW -2

typedef int Status;
typedef int QElemType;

typedef struct
{
    QElemType* base;
    int   front;
    int   rear;
} SqQueue; //顺序表实现队列 非循环队列

Status InitQueue(SqQueue& Q);
Status EnQueue(SqQueue& Q, QElemType e);
Status DeQueue(SqQueue& Q, QElemType& e);
Status IsEmptyQ(SqQueue& Q);
Status GetFront(SqQueue& Q, QElemType& e);
void ClearQueue(SqQueue &Q);
SqQueue.cpp
#include<stdio.h>
#include<stdlib.h>
#include"SqQueue.h"

Status InitQueue(SqQueue& Q)
{
    Q.base = (QElemType*)malloc(sizeof(QElemType) * QUEUE_INIT_SIZE);
    if (!Q.base) exit(OVERFLOW);
    Q.front = Q.rear = 0;
    return OK;
}

Status EnQueue(SqQueue& Q, QElemType e)
{
    Q.base[Q.rear] = e;
    Q.rear = Q.rear + 1;
    //循环队列
    //Q.rear = (Q.rear + 1)%(QUEUE_INIT_SIZE + 1);
    return OK;
}

Status DeQueue(SqQueue& Q, QElemType& e)
{
    if (Q.front == Q.rear)
    {
        return ERROR;
    }
    e = Q.base[Q.front];
    //循环队列
    //Q.front = (Q.front + 1) % (QUEUE_INIT_SIZE + 1);
    Q.front = Q.front + 1;

    return OK;
}

Status IsEmptyQ(SqQueue& Q)
{
    if (Q.front == Q.rear) return TRUE;
    return FALSE;
}

Status GetFront(SqQueue& Q, QElemType& e)
{
    if (Q.front == Q.rear)
        return ERROR;
    e = Q.base[Q.front];
    return OK;
}

void ClearQueue(SqQueue &Q)
{
    free(Q.base);
    Q.base = NULL;
    Q.front = Q.rear;
}
SqStack.h
#define ERROR 0
#define OK 1
#define TRUE 1
#define FALSE 0
#define STACK_INIT_SIZE 100
#define STACK_INCREMENT 10
#define OVERFLOW -2

typedef int SElemType;
typedef int Status;

typedef struct
{
    SElemType* base;
    SElemType* top;
    int stacksize;
} SqStack;

Status InitStack(SqStack& S);
Status GetTop(SqStack& S, SElemType& e);
Status Push(SqStack& S, SElemType e);
Status Pop(SqStack& S, SElemType& e);
Status IsEmptyS(SqStack& S);
void ClearStack(SqStack& S);
SqStack.cpp
#include"SqStack.h"
#include<stdio.h>
#include<stdlib.h>

Status InitStack(SqStack& S)
{
    S.base = (SElemType*)malloc(sizeof(SElemType) * STACK_INIT_SIZE);//构造空栈
    if (!S.base) exit(OVERFLOW);
    S.top = S.base;
    S.stacksize = STACK_INIT_SIZE;
    return OK;
}

Status GetTop(SqStack& S, SElemType& e)
{
    if (S.top == S.base)
    {
        return ERROR;
    }
    e = *(S.top - 1);
    return OK;
}

Status Push(SqStack& S, SElemType e)
{
    if (S.top - S.base >= S.stacksize)//栈满
    {
        S.base = (SElemType*)realloc(S.base, (S.stacksize + STACK_INCREMENT)
            * sizeof(SElemType));
        if (!S.base) exit(OVERFLOW);

        S.top = S.base + S.stacksize;//调整栈顶指针
        S.stacksize += STACK_INCREMENT;//改变了
    }
    *S.top++ = e;

    return OK;
}

Status Pop(SqStack& S, SElemType& e)
{
    //判断栈是否为空
    if (S.top == S.base) return ERROR;
    e = *--S.top;
    return OK;
}

Status IsEmptyS(SqStack& S)
{
    if (S.base == S.top)
        return TRUE;
    return FALSE;
}

void ClearStack(SqStack& S)
{
    free(S.base);
    S.base = NULL;
    S.top = S.base;
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值