数据结构 - 图

来源:互联网 发布:安卓蓝牙调试助手 源码 编辑:程序博客网 时间:2024/06/04 19:50
郝斌版《数据结构》学习笔记
时间:2015.08.31 - 2015.09.05


转载自:http://www.cnblogs.com/matrix-r/
      作者:Matrix_R

图的存储结构有简单的两种:1 邻接矩阵法 2临界表法

邻接矩阵我觉得是非常明了的一种图的表示方法,当然了,其缺点就是,在图的点数多而连接线少的时候,比较浪费资源。

我的邻接矩阵简单代码如下:

int main()
{
    cout << "Hello world!" << endl;
    int Block[5][5] = \
    {
        0, 1, 1, 1, 0, \
        1, 0, 1, 1, 0, \
        1, 1, 0, 0, 1, \
        1, 1, 0, 0, 1, \
        0, 0, 1, 1, 0  \
    };
    Graph tmpGph(Block);
    tmpGph.DeepSearch();
    tmpGph.ResetVisit();
    cout << endl;
    tmpGph.BFS();
    //New Job!!!
//    GraphList tmpGphLst;
//    int nLineNumbers = 0;
//    int nItem, Point;
//    cout << "How Many Lines Inside?" << endl;
//    cin >> nLineNumbers;
//    while(nLineNumbers --)
//    {
//        cout << "Input Line Point A, B" << endl;
//        cin >> nItem >> Point;
//        tmpGphLst.AddToListByOrder(nItem, Point);
//    }
//    tmpGphLst.BFS();
//    cout << endl;
    return 0;
}

因为遍历的是无向图,所以我做的是一个对称邻接矩阵,其对应的图是这样的:(其中的箭头你就当他不存在吧,无向图哦)

  我发现我在写博文题同时,还能提高我的visio绘图能力~不过现在实在不怎么样。一点点练吧。

这样从1点开始进行深度优先遍历,我们很容易就能得出其遍历结果:

  1 2 3 5 4

  这个结果相信不用我多说吧,具体可以看代码及其运行结果:

int Graph::DeepSearch(int Point)
{
     p_nVisitList[Point] = 1;
     cout << Point << ends;
 
     for(int i = 0;i < 5;++ i)
     {
         if(1 == pBlock[Point][i] && 0 == p_nVisitList[i])
         {
             DeepSearch(i);
         }
     }
 }

就是这样一段简单的代码~其中在函数生命中Point的参数默认为0,其运行结果如下:

其中逐个加1,就对应上了1 2 3 5 4了。

就这么简单。深度优先遍历使用的方法是针对当前的这个点的邻接点进行查找,只要找到了一个未访问的节点,就对这个节点采用同样的方式进行遍历。所以深度优先遍历使用递归是很好的方式,我的那个代码只有13行~

而邻接矩阵的广度优先遍历则是逐层访问,比较适合邻接表来做。邻接矩阵的广度优先遍历方法如下:

void Graph::BFS()
{
    p_nVisitList[4] = 1;
    cout << 4 << ends;
    queue<int> DL;
    DL.push(4);
    while(!DL.empty())
    {
        int val = DL.front();
        DL.pop();
        for(int i = 0;i < 5;++ i)
        {
            if(1 == pBlock[val][i] && p_nVisitList[i] == 0)
            {
                cout << i << ends;
                p_nVisitList[i] = 1;
                DL.push(i);
            }
        }
    }
}

运行结果:

还是一样的图,运行结果就是第二行的结果。你可以自己算一下对不对(BFS遍历的起始点为4,注意下)。

邻接表的广度优先遍历

我觉得,因为邻接表的较为特殊的存储形式,使得其较为适合以广度优先的方式进行遍历。但是需要注意的是,邻接矩阵和邻接表这两种图的存储形式,都能够使用深度优先遍历和广度优先遍历的。

广度优先遍历的思想是逐层访问,每当当前节点的全部相邻节点都被访问完成之后,再访问下一层节点。

我在用邻接表表示的图的类中,专门制作了一个方法用于添加点和点关系的函数。通过这个函数,来实现图的创建。

看下这个类的代码:

class ListNode
{
    public:
        int val;
        int weight;
        ListNode * next;
    public:
        ListNode();
};
ListNode::ListNode():val(0), weight(0), next(NULL)
{
    ;
}
class GraphList
{
    public:
        GraphList();
        ~GraphList();
        void AddToListByOrder(int nitem, int Point);
        void BFS(int n = 0);//这个广度优先遍历的代码太好写了
    private:
        int visit[5];
        ListNode * Next[5];
};

上面的代码中包含了两个类,一个是邻接表的节点类,另外一个是邻接表本身。代码还是很简单的,而且因为邻接表的特性,使得分层遍历十分方便,看主函数代码结构:

GraphList tmpGphLst;
    int nLineNumbers = 0;
    int nItem, Point;
    cout << "How Many Lines Inside?" << endl;
    cin >> nLineNumbers;
    while(nLineNumbers --)
    {
        cout << "Input Line Point A, B" << endl;
        cin >> nItem >> Point;
        tmpGphLst.AddToListByOrder(nItem, Point);
    }
    tmpGphLst.BFS();
    cout << endl;

在看演示效果:

因为链表采用的是前插法,所以你会看到第二层的遍历结果是3 2 1,反过来的。

很容易发现,在使用邻接表来表示的时候进行广度优先遍历很方便。

图论,我就写这些啦~

最后附上本次的全部代码:

#include <iostream>
#include <queue>
using namespace std;
class Graph
{
    private:
    //访问控制
    int p_nVisitList[5];
    int (* pBlock)[5];
    public:
    Graph(int (*pParam)[5]);
    ~Graph();
    //深度优先遍历
    int DeepSearch(int Point = 0);
    void BFS();
    void ResetVisit();
};
class ListNode
{
    public:
        int val;
        int weight;
        ListNode * next;
    public:
        ListNode();
};
ListNode::ListNode():val(0), weight(0), next(NULL)
{
    ;
}
class GraphList
{
    public:
        GraphList();
        ~GraphList();
        void AddToListByOrder(int nitem, int Point);
        void BFS(int n = 0);//这个广度优先遍历的代码太好写了
    private:
        int visit[5];
        ListNode * Next[5];
};
void GraphList::AddToListByOrder(int nitem, int Point)//前插法,代码好写
{
    if(nitem >= 0 && nitem < 5 && Point >= 0 && Point < 5)
    {
        ListNode * pnewnode = new ListNode;
        if(pnewnode == NULL)
            return;
        pnewnode->val = Point;
        pnewnode->next = Next[nitem];
        Next[nitem] = pnewnode;
    }
}
void GraphList::BFS(int n)
{
    for(int i = 0;i < 5;++ i)
    {
        if(visit[i] == 0)
        {
            cout << i << ends;
            visit[i] = 1;
        }
        ListNode * pLNTmp = Next[i];
        while(pLNTmp != NULL)
        {
            if(0 == visit[pLNTmp->val])
            {
                cout << pLNTmp->val << ends;
                visit[pLNTmp->val] = 1;
            }
            pLNTmp = pLNTmp -> next;
        }
    }
}
GraphList::GraphList()
{
    for(int i = 0;i < 5;++ i)
    {
        visit[i] = 0;
        Next[i] = NULL;
    }
}
GraphList::~GraphList()
{
    for(int i = 0;i < 5;++ i)
    {
        ListNode * ptmpLN;
        while(Next[i] != NULL)
        {
            ptmpLN = Next[i]->next;
            delete Next[i];
            Next[i] = ptmpLN;
        }
    }
}
void Graph::ResetVisit()
{
    for(int i = 0;i < 5;++ i)
    {
        p_nVisitList[i] = 0;
    }
}
Graph::Graph(int (*pParam)[5])
{
    for(int i = 0;i < 5;++ i)
        p_nVisitList[i] = 0;
    pBlock = pParam;
}
Graph::~Graph()
{
    ;//nothing!
}
int Graph::DeepSearch(int Point)
{
    p_nVisitList[Point] = 1;
    cout << Point << ends;
    for(int i = 0;i < 5;++ i)
    {
        if(1 == pBlock[Point][i] && 0 == p_nVisitList[i])
        {
            DeepSearch(i);
        }
    }
    return 0;
}
void Graph::BFS()
{
    p_nVisitList[4] = 1;
    cout << 4 << ends;
    queue<int> DL;
    DL.push(4);
    while(!DL.empty())
    {
        int val = DL.front();
        DL.pop();
        for(int i = 0;i < 5;++ i)
        {
            if(1 == pBlock[val][i] && p_nVisitList[i] == 0)
            {
                cout << i << ends;
                p_nVisitList[i] = 1;
                DL.push(i);
            }
        }
    }
}
int main()
{
    cout << "Hello world!" << endl;
    int Block[5][5] = \
    {
        0, 1, 1, 1, 0, \
        1, 0, 1, 1, 0, \
        1, 1, 0, 0, 1, \
        1, 1, 0, 0, 1, \
        0, 0, 1, 1, 0  \
    };
    Graph tmpGph(Block);
    tmpGph.DeepSearch();
    tmpGph.ResetVisit();
    cout << endl;
    tmpGph.BFS();
    //New Job!!!
    GraphList tmpGphLst;
    int nLineNumbers = 0;
    int nItem, Point;
    cout << "How Many Lines Inside?" << endl;
    cin >> nLineNumbers;
    while(nLineNumbers --)
    {
        cout << "Input Line Point A, B" << endl;
        cin >> nItem >> Point;
        tmpGphLst.AddToListByOrder(nItem, Point);
    }
    tmpGphLst.BFS();
    cout << endl;
    return 0;
}    




0 0
原创粉丝点击