最近在复习数据结构,看到图的时候就想尝试一下非递归的深度优先遍历,虽然写出来了,但是程序的可读性不高,所以在网上看了别人的实现,发现很多人只给了邻接矩阵存储的图的非递归遍历,所以作者自己实现了邻接表存储的图的创建和非递归遍历,水平有限,可读性健壮性尽量努力提高,图的邻接矩阵存储本文不涉及,仅仅介绍邻接表存储。
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语言描述 耿国华著