以邻接表作为存储结构的图的深度优先遍历和广度优先遍历(c++版)

一、图的存储

用邻接表法存储图,存储结构分为两部分,一部分为存储图的所有顶点的数组,另一部分为挂载在数组的每个元素后面的用来表示顶点的邻接点的链表。

1、存储顶点的结构单元为:

class vnode
{
public:
    string nodename;
    bool visted;//进行图的遍历时用于标记图是否被访问过
    node *next;
    vnode()
    {
        visted = false;
        next = NULL;
    }
};

链表的结构单元为:

class node
{
public:
    string nodename;
    int nodeindex;//节点的索引,用于快速定位节点在顶点数组中的位置
    int weight;//权值,用于存储顶点之间的信息
    node *next;
    node() { next = NULL; }
};

2、现在声明Graph这个类,类的声明为(有关图的遍历的成员函数也以包含进来):

class Graph
{
public:
    Graph();
    ~Graph();
    bool DeepFirstSearch(int nodeindex);
    void ClearVisited();
    bool WideFirstSearch(int nodeindex);protected:
    vnode *pvnode;
    int vnumber;
};

3、下面是Graph类的成员函数的定义为(先实现关于图的存储的成员函数):

Graph::Graph()
{
    cout << "请输入节点的个数:";
    cin >> vnumber;
    pvnode = new vnode[vnumber];        //通过new创建顶点数组
    for (int i = 0; i < vnumber; i++)   //通过for循环将图的信息输入
    {
        cout << endl;
        cout << "请输入节点:";
        cin >> pvnode[i].nodename;
        string check;                   //输入某个顶点的邻接点时,以"#"作为输入的结束标志
        while (1)
        {
            cout << "请输入节点的相邻节点:";
            cin >> check;
            if (check == "#") { break; }//如果输入的"#"就跳出输入循环
            node *temp = new node;      //如果不是,就分配节点内存,完善相关信息
            temp->nodename = check;
            cout << "请输入相邻节点的序号和权值:";
            cin >> temp->nodeindex >> temp->weight;
            temp->next = pvnode[i].next;  //并将新输入的节点放到相应的链表中
            pvnode[i].next = temp;
        }
    }
}
Graph::~Graph()                         //释放内存时,先释放链表占用的内存,然后释放数组占用的内存
{
    node*currentnode = NULL;             //释放链表占用的内存
    node*temp = NULL;
    for (int i = 0; i < vnumber; i++)
    {
        currentnode = pvnode[i].next;
        while (currentnode != NULL)
        {
            temp = currentnode->next;    //保存当前节点的下一个节点的内存
            delete currentnode;          //释放当前节点的内存
            currentnode = temp;          //下一个节点作为当前的节点
        }
    }
    delete[]pvnode;                      //释放数组占用的内存
}

二、图的遍历

1、深度优先遍历

深度优先遍历通过递归的算法实现

下面是实现图的深度优先遍历的成员函数的实现:

bool Graph::DeepFirstSearch(int nodeindex)
{
    if (nodeindex < 0 || nodeindex >= vnumber)            //判断指定的起始节点是否合法
    {
        cout << "The nodeindex does not exist..";
        return false;
    }
    if (pvnode[nodeindex].visted == false)                //判断当前节点是否被访问过,如果没有,则继续
    {
        cout << pvnode[nodeindex].nodename << " ";        //输出节点的名字
        pvnode[nodeindex].visted = true;                  //修改访问记录
        node *currentnode=pvnode[nodeindex].next;         //找到当前节点相邻的一个节点
        while (currentnode != NULL)
        {
            DeepFirstSearch(currentnode->nodeindex);      //通过递归继续上述操作
            currentnode = currentnode->next;              //换当前节点的另一个相邻节点试试
        }
    }
    return true;
}

2、广度优先遍历

广度优先遍历需要借助队列这种数据结构。

代码实现:

bool Graph::WideFirstSearch(int nodeindex)
{
    if (nodeindex < 0 || nodeindex >= vnumber)          //判断输入的节点索引是否合法
    {
        cout << "The nodeindex does not exist..";
        return false;
    }
    Queue<int> queue(vnumber);
    cout << "广度优先搜索的遍历结果为:";
    cout << pvnode[nodeindex].nodename << " ";          //将起始节点的名字打印出来
    pvnode[nodeindex].visted = true;                    //更改起始节点的访问记录
    queue.EnQueue(nodeindex);                           //起始节点入队列
    int temp=0;
    node *currentnode = NULL;
    while (queue.QueueEmpty() == false)                 //对于每一个入队的节点,
    {
        queue.DeQueue(temp);
        currentnode = pvnode[temp].next;                //按入队顺序访问其相邻的全部节点
        while (currentnode!= NULL)
        {
            if (pvnode[currentnode->nodeindex].visted == false)
            {
                cout << currentnode->nodename << " ";
                pvnode[currentnode->nodeindex].visted = true;     //已经访问过的节点更改访问记录并入队
                queue.EnQueue(currentnode->nodeindex);
            }
            currentnode = currentnode->next;
        }
    }
    cout << endl;
    return true;
}

3、由于这两种算法都需要对节点的访问记录进行修改,所以每次用这两种的某一种算法实现遍历后需要初始化访问记录才能继续使用。

初始化访问记录的函数代码实现为:

void Graph::ClearVisited()
{
    for (int i = 0; i < vnumber; i++)
    {
        pvnode[i].visted = false;
    }
}

注:完整的代码在下面赋上,另附上实现队列的完整代码

http://files.cnblogs.com/files/Rcchio/Graph.rar

时间: 2024-10-13 01:11:19

以邻接表作为存储结构的图的深度优先遍历和广度优先遍历(c++版)的相关文章

基于邻接表存储的图的深度优先遍历和广度优先遍历

一.深度优先遍历是连通图的一种遍历策略.其基本思想如下: 设x是当前被访问顶点,在对x做过访问标记后,选择一条从x出发的未检测过的边(x,y).若发现顶点y已访问过,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过:然后从y开始搜索,直到搜索完从y出发的所有路径,即访问完所有从y出发可达的顶点之后,才回溯到顶点x,并且再选择一条从x出发的未检测过的边.上述过程直至从x出发的所有边都已检测过为止. 例如下图中: 1.从0开始,首先找到0的关

邻接表来存储一个图

//用邻接表来存储一个图 int n, m, i; int u[6], v[6], w[6]; int first[5], next[5]; scanf("%d%d", &n, &m); //初始化first数组下标1~n的值为-1, 表示1~n顶点暂时都没有边 for(i = 1; i <= n; ++i) first[i] = -1; for(i = 1; i <= m; ++i) { scanf("%d %d %d", &u

SQLServer2012 表IAM存储结构探究

SQLServer2012 表IAM存储结构探究 Author:zfive5(zidong) Email: [email protected] 引子 国庆节期间,一直在翻阅<程序员的自我修养-链接.装载与库>,这本给我的感觉是越看越乱,但总的来说还不错,一句话--优秀程序员就应该知道每一个字节的意义. 看此书前的两本<深入解析SQLServer2008>和<Microsoft SQL Server 2005技术内幕:存储引擎>对IAM解读都是点到为止,让我满脑袋是一堆问

cache数据库之表的存储结构

1.我们已经建了一个person类,接下来就是表的存储结构 2.打开Inspector,先输入rowid名字为p_RowID,选class->Storage 3.新建一个Storage,选择CacheSQLStorage.在SqlIdExpression中输入$i(^mdata("Person"))是\$不是S 意思是设置Rowid为自增,注意StremLocation的写法 4.Caché 以多维数组存储数据,全部数据都是保存Global中.Global以例如以下形式表示:^名

基于邻接矩阵存储的图的深度优先遍历和广度优先遍历

图的存储结构相比较线性表与树来说就复杂很多,对于线性表来说,是一对一的关系,所以用数组或者链表均可简单存放.树结构是一对多的关系,所以我们要将数组和链表的特性结合在一起才能更好的存放. 那么我们的图,是多对多的情况,另外图上的任何一个顶点都可以被看作是第一个顶点,任一顶点的邻接点之间也不存在次序关系. 仔细观察以下几张图,然后深刻领悟一下: 因为任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系(内存物理位置是线性的,图的元素关系是平面的). 如果用多重链表

图的邻接表存储表示,图的深度优先和广度优先遍历

1 #include<stdio.h> 2 #include<stdlib.h> 3 4 #define MAX_VERTAX_SIZE 20 5 #define OK 1 6 #define ERROR 0 7 8 typedef int Status; 9 typedef char ElemType; 10 11 typedef struct EageNode{ 12 int adjacentVertax; 13 struct EageNode* nextAdjacentVer

图的邻接表表示与无环图的拓扑排序

一.  图的最常用的表示方法是邻接矩阵和邻接表. 1,邻接矩阵 邻接矩阵其实就是一个二维数组,对于每条边<u,v>,我们就令A[u][v] = 1,如果图为有权图,我们也可以令A[u][v]等于该权,这么表示的优点是非常简单,但是它的空间需求很大,如果图是稠密的,邻接矩阵是合适的表示方法,如果图是稀疏的,那这种方法就太浪费空间了,下面给出图的邻接矩阵表示例子. 2 邻接表 邻接表是图的常用储存结构之一.邻接表由表头结点和表结点两部分组成,其中图中每个顶点均对应一个存储在数组中的表头结点.如下图

【Java数据结构学习笔记之一】线性表的存储结构及其代码实现

应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关系 图形结构或网状结构:数据元素之间存在多个对多个的关系 对于数据不同的逻辑结构,计算机在物理磁盘上通常有两种屋里存储结构 顺序存储结构 链式存储结构 本篇博文主要讲的是线性结构,而线性结构主要是线性表,非线性结构主要是树和图. 线性表的基本特征: 总存在唯一的第一个数据元素 总存在唯一的最后一个数据元素 除

存储结构与邻接矩阵,深度优先和广度优先遍历及Java实现

如果看完本篇博客任有不明白的地方,可以去看一下<大话数据结构>的7.4以及7.5,讲得比较易懂,不过是用C实现 下面内容来自segmentfault 存储结构 要存储一个图,我们知道图既有结点,又有边,对于有权图来说,每条边上还带有权值.常用的图的存储结构主要有以下二种: 邻接矩阵 邻接表 邻接矩阵 我们知道,要表示结点,我们可以用一个一维数组来表示,然而对于结点和结点之间的关系,则无法简单地用一维数组来表示了,我们可以用二维数组来表示,也就是一个矩阵形式的表示方法. 我们假设A是这个二维数组