图的深度优先遍历

深度优先遍历

  • 和树的先根遍历类似。
  • 指定从一个顶点v开始访问,并用一个状态表来记录顶点是否被访问。当v被访问时,标记被访问。
  • 当其邻接点未访问时,递归地访问其邻接点以及邻接点的邻接点……直到所有顶点都被访问。

这里写图片描述

  • 例如,上图从顶点v0v0开始,深度优先遍历图的结果为:v0v1v3v2v5v6v4v0→v1→v3→v2→v5→v6→v4
template<class T>
void Graph<T>::DepthFirstSearch(int start)      // 从一个起始点开始递归访问
{
    cout << "->V" << VSet[start].value;
    visited[start] = true;                  // 标记被访问
    for (vector<Vertex<T>>::iterator iter=VSet[start].adj_list.begin();
        iter!= VSet[start].adj_list.end(); ++iter)
    {// 遍历起始点的邻接表
        if (!visited[iter->value])
            DepthFirstSearch(iter->value);      // 若其邻接点没被访问则访问
    }
}

附图的深度优先遍历实现C++

#include<iostream>
#include<vector>
#include<iterator>
using namespace std;

template<class T>
class Vertex {      // 创建一个顶点类
public:
    T value;        // 顶点的关键字值
    vector<Vertex<T>> adj_list;     // 顶点的邻接表
    int weight;     // 顶点之间的权重(相邻顶点的连接权值),存放在邻接顶点中,每个顶点与自身的权值为0

    Vertex(T value = 0) :value(value), weight(0){}  // 默认构造函数

    bool operator < (const Vertex<T> &v) const { return value < v.value; }  // 重载 < 操作符比较两顶点值大小
};

template<class T>
class Graph {       // 创建一个图类
public:
    vector<Vertex<T>> VSet;     // 表示顶点的集合
    Graph(int sz) :size(sz) {}  // 构造函数
    bool* visited;              // 创建布尔类型数组,标记顶点是否被访问
    void Construct();       // 创建(无向)图

    void initVisited(); // 初始化访问数组

    int getsize() { return size; }
    void DepthFirstSearch(int start);   // 指定一个顶点开始深度优先搜索
private:
    int size;                   // 图中顶点的个数
};

template<class T>
void Graph<T>::Construct()
{
    // 创建一个点数组
    Vertex<int> V[] = { Vertex<int>(0), Vertex<int>(1), Vertex<int>(2), Vertex<int>(3),
        Vertex<int>(4), Vertex<int>(5), Vertex<int>(6) };

    // 顶点V0的邻接表
    for (int i = 1;i < 4;i++)
        V[0].adj_list.push_back(V[i]);
    V[0].adj_list[0].weight = 2;    // V0与V1的连接权值
    V[0].adj_list[1].weight = 4;    // V0与V2的连接权值
    V[0].adj_list[2].weight = 1;    // V0与V2的连接权值

    V[1].adj_list.push_back(V[0]);  // 顶点V1的邻接表
    V[1].adj_list.push_back(V[3]);
    V[1].adj_list.push_back(V[4]);
    V[1].adj_list[0].weight = 2;    // V1与V0的连接权值
    V[1].adj_list[1].weight = 3;    // V1与V3的连接权值
    V[1].adj_list[2].weight = 10;   // V1与V4的连接权值

    V[2].adj_list.push_back(V[0]);  // 顶点V2的邻接表
    V[2].adj_list.push_back(V[3]);
    V[2].adj_list.push_back(V[5]);
    V[2].adj_list[0].weight = 4;    // V2与V0的连接权值
    V[2].adj_list[1].weight = 2;    // V2与V3的连接权值
    V[2].adj_list[2].weight = 5;    // V2与V5的连接权值

                                    // 顶点V3的邻接表
    for (int i = 0;i < 7;i++)
    {
        if (i == 3)
            continue;
        V[3].adj_list.push_back(V[i]);
    }
    V[3].adj_list[0].weight = 1;    // V3与V0的连接权值
    V[3].adj_list[1].weight = 3;    // V3与V1的连接权值
    V[3].adj_list[2].weight = 2;    // V3与V2的连接权值
    V[3].adj_list[3].weight = 7;    // V3与V4的连接权值
    V[3].adj_list[4].weight = 8;    // V3与V5的连接权值
    V[3].adj_list[5].weight = 4;    // V3与V6的连接权值

    V[4].adj_list.push_back(V[1]);  // 顶点V4的邻接表
    V[4].adj_list.push_back(V[3]);
    V[4].adj_list.push_back(V[6]);
    V[4].adj_list[0].weight = 10;   // V4与V1的连接权值
    V[4].adj_list[1].weight = 7;    // V4与V3的连接权值
    V[4].adj_list[2].weight = 6;    // V4与V6的连接权值

    V[5].adj_list.push_back(V[2]);  // 顶点V5的邻接表
    V[5].adj_list.push_back(V[3]);
    V[5].adj_list.push_back(V[6]);
    V[5].adj_list[0].weight = 5;    // V5与V2的连接权值
    V[5].adj_list[1].weight = 8;    // V5与V3的连接权值
    V[5].adj_list[2].weight = 1;    // V5与V6的连接权值

    // 顶点V6的邻接表
    for (int i = 3;i < 7;i++)
        V[6].adj_list.push_back(V[i]);
    V[6].adj_list[0].weight = 4;    // V6与V3的连接权值
    V[6].adj_list[1].weight = 6;    // V6与V4的连接权值
    V[6].adj_list[2].weight = 1;    // V6与V5的连接权值

    for (int i = 0;i < 7;i++)       // 将每个点储存在图中的点集VSet中
    {
        VSet.push_back(V[i]);
    }
}

template<class T>
void Graph<T>::initVisited()
{
    visited = new bool[size];
    for (int i = 0;i < size;i++)
    {
        visited[i] = false;     // 初始化访问数组
    }
}

template<class T>
void Graph<T>::DepthFirstSearch(int start)      // 从一个起始点开始递归访问
{
    cout << "->V" << VSet[start].value;
    visited[start] = true;                  // 标记被访问
    for (vector<Vertex<T>>::iterator iter=VSet[start].adj_list.begin();iter!= VSet[start].adj_list.end(); ++iter)
    {// 遍历起始点的邻接表
        if (!visited[iter->value])
            DepthFirstSearch(iter->value);      // 若其邻接点没被访问则访问
    }
}

int main()
{
    Graph<int> G(7);            // 创建一个图对象G
    G.Construct();              // 构造图
    G.initVisited();            // 初始化访问列表
    cout << "The depth-first search on the Graph is: \n";
    G.DepthFirstSearch(0);      // 从第0个顶点开始深度优先遍历访问
    cout << endl;
    system("pause");    
    return 0;
}
  • 运行结果
The depth-first search on the Graph is:
->V0->V1->V3->V2->V5->V6->V4
请按任意键继续. . .
2. 系统设计 1.用到的抽象数据类型的定义 的抽象数据类型定义: ADT Graph{ 数据对象V:V是具有相同特性的数据元素的集合,称为顶集 数据关系R: R={VR} VR={<v,w>|v,w∈V且P(v,w),<v,w>表示从v到w的弧, 谓词P(v,w)定义了弧<v,w>的意义或信息} 基本操作P: CreatGraph(&G,V,VR) 初始条件:V是的顶集,VR是中弧的集合 操作结果:按V和VR的定义构造G DestroyGraph(&G) 初始条件:G存在 操作结果:销毁G InsertVex(&G,v) 初始条件:G存在,v和中顶有相同特征 操作结果:在G中增添新顶v …… InsertArc(&G,v,w) 初始条件:G存在,v和w是G中两个顶 操作结果:在G中增添弧<v,w>,若G是无向的则还增添对称弧<w,v> …… DFSTraverse(G,Visit()) 初始条件:G存在,Visit是顶的应用函数 操作结果:对进行深度优先遍历,在遍历过程中对每个顶调用函数Visit一次且仅一次。一旦Visit()失败,则操作失败 BFSTraverse(G,Visit()) 初始条件:G存在,Visit是顶的应用函数 操作结果:对进行广度优先遍历,在遍历过程中对每个顶调用函数Visit一次且仅一次。一旦Visit()失败,则操作失败 }ADT Graph 栈的抽象数据类型定义: ADT Stack{ 数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0} 数据关系:R1={<ai-1,ai>|ai-1,ai∈D,i=2,…,n} 约定an端为栈顶,ai端为栈底 基本操作: InitStack(&S) 操作结果:构造一个空栈S DestroyStack(&S) 初始条件:栈S已存在 操作结果:将S清为空栈 StackEmpty(S) 初始条件:栈S已存在 操作结果:若栈S为空栈,则返回TRUE,否则FALSE …… Push(&S,e) 初始条件:栈S已存在 操作结果:插入元素e为新的栈顶元素 Pop(&S,&e) 初始条件:栈S已存在且非空 操作结果:删除S的栈顶元素,并用e返回其值 StackTraverse(S,visit()) 初始条件:栈S已存在且非空 操作结果:从栈底到栈顶依次对S的每个数据元素调用函数visit(),一旦visit()失败,则操作失效 }ADT Stack 队列的抽象数据类型定义: ADT Queue{ 数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0} 数据关系:Rl={<ai-1,ai>|ai-1,ai∈D,i=2,…,n} 约定其中ai端为队列头,an端为队列尾。 基本操作: InitQueue(&Q) 操作结果:构造一个空队列Q DestroyQueue(&Q) 初始条件:队列Q已存在 操作结果:队列Q被销毁,不再存在 QueueEmpty(Q) 初始条件:队列Q已存在 操作结果:若Q为空队列,则返回TRUE,否则FALSE …… EnQueue(&Q,e) 初始条件:队列Q已存在 操作结果:插入元素e为Q的新的队尾元素 DeQueue(&Q,&e) 初始条件:Q为非空队列 操作结果:删除Q的队头元素,并用e返回其值 }ADT Queue 2.主程序的流程: 调用CreateDN函数创建的邻接表G; 调用PrintDN函数输出邻接表G; 调用DFSTraverse函数深度优先遍历; 调用BFSTraverse函数广度优先遍历
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值