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

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

#define MAX_NODE 10
typedef 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语言描述 耿国华著

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值