数据结构笔记--图的邻接表存储及非递归深度优先遍历

来源:互联网 发布:打字淘宝兼职是真的吗 编辑:程序博客网 时间:2024/05/16 00:28

最近在复习数据结构,看到图的时候就想尝试一下非递归的深度优先遍历,虽然写出来了,但是程序的可读性不高,所以在网上看了别人的实现,发现很多人只给了邻接矩阵存储的图的非递归遍历,所以作者自己实现了邻接表存储的图的创建和非递归遍历,水平有限,可读性健壮性尽量努力提高,图的邻接矩阵存储本文不涉及,仅仅介绍邻接表存储。
1、创建图的邻接表结构
图的邻接表结构可以存储有向图和无向图而不用改任何东西,图的邻接表分为表头节点表和边表,表头节点主要为表头节点数组以及一个指向边表的指针。边表有n个边链表组成。
图的定义如下:

#define MAX_NODE 10typedef char DataType; //存储边信息的链表节点typedef struct ArcNode{    int m_index;    //边表数据域保存顶点下标    struct ArcNode* m_next;}ArcNode;//存储定点信息的结构体定义typedef struct VertexNode{    DataType m_data;    struct ArcNode* m_first;}VertexNode;//图的定义typedef struct Graphic{    VertexNode vertex[MAX_NODE];    int vexnum, arcnum;      //图的顶点和边数量}AdjList;//找值data在数组vArray中的下标int Index(char data, VertexNode* vArray, int len){    for (int i = 0; i < len; ++i)    {        if (data == vArray[i].m_data)            return i;    }    return -1;}//创建图的邻接表存储void Create(AdjList* grap){    cout << "请输入图的顶点数和边数: ";    cin >> grap->vexnum >> grap->arcnum;    if (grap->vexnum > MAX_NODE)    {        cout << "输入顶点过多!!!" << endl;        return;    }    cout << "请输入顶点: ";    for (int i = 0; i < grap->vexnum; ++i)    {        cin >> grap->vertex[i].m_data;        grap->vertex[i].m_first = NULL;    }    cout << "请输入边: " << endl;    for (int i = 0; i < grap->arcnum; ++i)    {        char a1, a2;        cin >> a1 >> a2;        int index1, index2;        index1 = Index(a1, grap->vertex, grap->vexnum);        index2 = Index(a2, grap->vertex, grap->vexnum);        if (index1 == -1 || index2 == -2)        {            cout << "输入参数有误!!!" << endl;            --i;            continue;        }        ArcNode *p = new ArcNode;        p->m_index = index2;        p->m_next = grap->vertex[index1].m_first;        grap->vertex[index1].m_first = p;    }}

2、深度优先搜索的非递归实现
要实现非递归的深度优先搜索,要用到到来存储,用一个数组visited(初始所有元素为false,代表未访问)来做访问的标记。基本思想是:从给定的搜索的第一个顶点index开始,将其压入堆栈,并标记visited[]为true表示已访问;之后循环进行如下操作,只要栈不为空,取出最上方元素,将其打印,然后去遍历所有的邻接顶点,只要还未访问(visited相应值为false),就将其压入栈,并标记为已访问。当栈中元素为0时,算法结束时,而所有访问过的点,均被标记过,并被压入栈中过,只要图是连通的,那么就做到所有点都被输出或记录。
注意:刚才有提过,以上针对于连通的图,而对于图中存在不同的连通分量的情况,可以在一次while循环之后,检查visited判断是否所有元素都被访问过,若存在未被访问的点,则在选取一个点,重复以上操作即可。

//非递归深度优先遍历连通子图void Depth(AdjList* grap, int index, bool* visited){    stack<int> stackIndex;    stackIndex.push(index);    while (!stackIndex.empty())    {        int v0 = stackIndex.top();        stackIndex.pop();        if (!visited[v0])        {            cout << grap->vertex[v0].m_data << " ";            visited[v0] = true;        }        ArcNode* p = grap->vertex[v0].m_first;        while (p)        {            if (!visited[p->m_index])            {                stackIndex.push(p->m_index);            }            p = p->m_next;        }    }}//非递归深度优先遍历图,封装上述函数void DFS1(AdjList* grap, int index, bool* visited){    for (int i = 0; i < grap->vexnum; ++i)    {        visited[i] = false;    }    for (int i = 0; i < grap->vexnum; ++i)    {        if (visited[i] == false)        {            Depth(grap, i, visited);        }    }}

参考:数据结构-C语言描述 耿国华著

0 0
原创粉丝点击