图的邻接表表示法及遍历

来看下面的一个简单的图,

《图的邻接表表示法及遍历》

     

      那么这样的一个图,我们应该用什么存储结构来存储它呢?常用的是邻接矩阵和邻接表,这里邻接矩阵不做讲解,如下所有代码都是以邻接表作为存储结构,所以这里就只讲解下邻接表。那么什么是邻接表呢?如何构造呢?

      邻接表是一种链式存储。就如上图,一共有四个顶点(分别是A,B,C,D),邻接表就是为这四个顶点的每个顶点建立一条单链表,也就是四条单链表,每个链表第一个元素就是该顶点自己。下面就以上面的图为例,具体介绍如何建立邻接表。

       首先看第一条单链表,表头是顶点A。因为顶点A只与顶点B有邻接,因此,该单链表大概描述为A—->B;

       再看第二条单链表,表头是B,而B与A,C,D都有邻接,故而描述为B—–>A——->C——->D;

       依次第三条单链表为C——>B—–>D;

       最后第四条单链表为D——>B—–>C。

代码:

#include <stdio.h>
#include <malloc.h>
#define MAX_SUM 1000
bool visited[MAX_SUM]= {false}; //设置标志数组

struct ArcNode
{
    int adjvex;               //该弧所指向的顶点的位置
    ArcNode * next;           //指向下一条弧的指针
};

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

struct ALGraph
{
    AdjList adjList;
    int vexNum;               //图的顶点数
    int arcNum;               //图的弧数
};

typedef struct node
{
    int data;
    node *next;
} Node,*LinkQueueNode;

typedef struct
{
    LinkQueueNode front; //队头指针
    LinkQueueNode rear;  //队尾指针
} LinkQueue;

bool InitQueue(LinkQueue *Q);//链队列初始化
bool EnterQueue(LinkQueue *Q,int x);//入队,将数据元素x插入到队列Q中
bool DeleteQueue(LinkQueue *Q,int *x);//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
bool IsEmpty(LinkQueue *Q);//判断链队列是否为空
void CreateGraph(ALGraph *graph);//创建图
void PrintGraph(ALGraph *graph);//打印图
void depth_first_search(ALGraph *graph,int v);//深度优先遍历
void breadth_first_search(ALGraph *graph);//广度优先遍历

int main(void)
{
    /*
        请输入图的顶点数:
        4
        请输入图的弧数:
        4
        请输入4个顶点信息:
        ABCD
        请输入4个弧的信息:
        0 1
        0 2
        1 2
        2 3

        邻接表打印为:
        A------>C B
        B------>C A
        C------>D B A
        D------>C

        深度优先搜索DFS:A C D B

        广度优先搜索BFS:A C B D

    */
    ALGraph graph;
    CreateGraph(&graph);
    printf("\n邻接表打印为:\n");
    PrintGraph(&graph);
    printf("\n深度优先搜索DFS:");
    for (int i = 0; i < graph.vexNum; i++)
        if (!visited[i])//如果没有访问
            depth_first_search(&graph,i);
    printf("\n");
    printf("\n广度优先搜索BFS:");
    breadth_first_search(&graph);
    printf("\n");
    return 0;
}

bool InitQueue(LinkQueue *Q)//链队列初始化
{
    Q->front=(LinkQueueNode)malloc(sizeof(Node));
    if(Q->front!=NULL)
    {
        Q->rear=Q->front;
        Q->front->next=NULL;
        return true;
    }
    else
        return false;//溢出
}

bool EnterQueue(LinkQueue *Q,int x)//入队,将数据元素x插入到队列Q中
{
    LinkQueueNode NewNode;
    NewNode=(LinkQueueNode)malloc(sizeof(Node));
    if(NewNode!=NULL)
    {
        NewNode->data=x;
        NewNode->next=NULL;
        Q->rear->next=NewNode;
        Q->rear=NewNode;
    }
    else
        return false;//溢出
}

bool DeleteQueue(LinkQueue *Q,int *x)//出队,将队列Q的队头元素出队并保存到x所指的存储空间中
{
    LinkQueueNode p;
    if(Q->front==Q->rear)//表示队列已空
        return false;
    p=Q->front->next;
    Q->front->next=p->next;//队头元素p出队
    if(Q->rear==p)//如果队中只有一个元素p,则p出队后成为空队
        Q->rear=Q->front;
    *x=p->data;
    free(p);//释放存储空间
    return true;
}

bool IsEmpty(LinkQueue *Q)//判断链队列是否为空
{
    return Q->front == Q->rear;
}

void CreateGraph(ALGraph *graph)//创建图
{
    printf("请输入图的顶点数:\n");
    scanf("%d",&graph->vexNum);
    printf("请输入图的弧数:\n");
    scanf("%d",&graph->arcNum);
    getchar();
    printf("请输入%d个顶点信息:\n",graph->vexNum);
    for (int i = 0; i < graph->vexNum; i++)
    {
        scanf("%c",&graph->adjList[i].vertex);
        graph->adjList[i].firstarc = NULL;
    }
    printf("请输入%d个弧的信息:\n",graph->arcNum);
    int h1, h2;
    ArcNode * temp;
    for (int i = 0; i < graph->arcNum; i++)//根据输入的弧的信息构造邻接表
    {
        scanf("%d%d",&h1,&h2);
        temp = new ArcNode;
        temp->adjvex = h2;
        temp->next = graph->adjList[h1].firstarc;
        graph->adjList[h1].firstarc = temp;
        temp = new ArcNode;
        temp->adjvex = h1;
        temp->next = graph->adjList[h2].firstarc;
        graph->adjList[h2].firstarc = temp;
    }
}

void PrintGraph(ALGraph *graph)//打印图
{
    for (int i = 0; i < graph->vexNum; i++)
    {
        printf("%c------>",graph->adjList[i].vertex);
        ArcNode *p = graph->adjList[i].firstarc;
        while (p)
        {
            printf("%c ",graph->adjList[p->adjvex].vertex);
            p = p->next;
        }
        printf("\n");
    }
}

void depth_first_search(ALGraph *graph,int v)//深度优先遍历
{
    visited[v] = true;
    printf("%c ",graph->adjList[v].vertex);
    ArcNode *p = graph->adjList[v].firstarc;
    while (p)
    {
        if (!visited[p->adjvex])
            depth_first_search(graph, p->adjvex);
        p = p->next;
    }
}

void breadth_first_search(ALGraph *graph)//广度优先遍历
{
    for (int i = 0; i < MAX_SUM; i++)//初始化访问标志数组
        visited[i] = false;
    LinkQueue Queue;
    int x;
    InitQueue(&Queue);
    for (int i = 0; i < graph->vexNum; i++)
        if (!visited[i])//如果没有访问过
        {
            visited[i] = true;
            EnterQueue(&Queue,i);//访问过的入队列
            printf("%c ",graph->adjList[i].vertex);
            while (!IsEmpty(&Queue))//队列不为空时
            {
                DeleteQueue(&Queue,&x);//先取出队首第一个元素,然后将第一个元素删除
                ArcNode *p = graph->adjList[x].firstarc;
                while(p)//访问未被访问过的邻接顶点
                {
                    if (!visited[p->adjvex])
                    {
                        visited[p->adjvex] = true;
                        printf("%c ",graph->adjList[p->adjvex].vertex);
                        EnterQueue(&Queue,p->adjvex);
                    }
                    p = p->next;
                }
            }
        }
}
    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/potential1/article/details/73028538
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞