重温数据结构——图的遍历

重温数据结构——图的遍历

      首先,我很想说的是,最近这两天寝室里的蚊子,有点多,有点犀利~每天早上起来都要被叮上几个包,有点苦逼。

       另外今天还玩了几把dota2,感觉画面质量是很不错的,但是,手感和dota不一样,而且我的笔记本配置很一般~

       接下来讲今天看的数据结构——图~

       我上个学期在上海泰瑞达的春季招聘中曾被考过这类问题。前面有一题是多态和另外一个名词的解释,有点记不清了。然后还有一道题考的是括号解析,这个很简单的,用栈就能直接处理。然后后面就是连续的两个图的问题。之前好像只是简单的看了看源代码,对于什么是深度优先遍历和广度优先遍历稍微有点认识吧。结果自然是可想而知,比较惨的。当时我在卷子上是这么写的:“今天不会,明天就会了”。当天回去就开始看图论,但是确实是搞的差不多了,不过现在嘛,呵呵~

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

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

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

 1 int main()
 2 {
 3     cout << "Hello world!" << endl;
 4     int Block[5][5] = \
 5     {
 6         0, 1, 1, 1, 0, \
 7         1, 0, 1, 1, 0, \
 8         1, 1, 0, 0, 1, \
 9         1, 1, 0, 0, 1, \
10         0, 0, 1, 1, 0  \
11     };
12     Graph tmpGph(Block);
13     tmpGph.DeepSearch();
14     tmpGph.ResetVisit();
15     cout << endl;
16     tmpGph.BFS();
17     //New Job!!!
18 //    GraphList tmpGphLst;
19 //    int nLineNumbers = 0;
20 //    int nItem, Point;
21 //    cout << "How Many Lines Inside?" << endl;
22 //    cin >> nLineNumbers;
23 //    while(nLineNumbers --)
24 //    {
25 //        cout << "Input Line Point A, B" << endl;
26 //        cin >> nItem >> Point;
27 //        tmpGphLst.AddToListByOrder(nItem, Point);
28 //    }
29 //    tmpGphLst.BFS();
30 //    cout << endl;
31     return 0;
32 }

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

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

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

  1 2 3 5 4

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

1 int Graph::DeepSearch(int Point)
 2 {
 3     p_nVisitList[Point] = 1;
 4     cout << Point << ends;
 5 
 6     for(int i = 0;i < 5;++ i)
 7     {
 8         if(1 == pBlock[Point][i] && 0 == p_nVisitList[i])
 9         {
10             DeepSearch(i);
11         }
12     }
13 }

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

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

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

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

 1 void Graph::BFS()
 2 {
 3     p_nVisitList[4] = 1;
 4     cout << 4 << ends;
 5     queue<int> DL;
 6     DL.push(4);
 7     while(!DL.empty())
 8     {
 9         int val = DL.front();
10         DL.pop();
11         for(int i = 0;i < 5;++ i)
12         {
13             if(1 == pBlock[val][i] && p_nVisitList[i] == 0)
14             {
15                 cout << i << ends;
16                 p_nVisitList[i] = 1;
17                 DL.push(i);
18             }
19         }
20     }
21 }

运行结果:

      

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

       邻接表的广度优先遍历

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

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

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

       看下这个类的代码:

 1 class ListNode
 2 {
 3     public:
 4         int val;
 5         int weight;
 6         ListNode * next;
 7     public:
 8         ListNode();
 9 };
10 ListNode::ListNode():val(0), weight(0), next(NULL)
11 {
12     ;
13 }
14 class GraphList
15 {
16     public:
17         GraphList();
18         ~GraphList();
19         void AddToListByOrder(int nitem, int Point);
20         void BFS(int n = 0);//这个广度优先遍历的代码太好写了
21     private:
22         int visit[5];
23         ListNode * Next[5];
24 };

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


 1     GraphList tmpGphLst;
 2     int nLineNumbers = 0;
 3     int nItem, Point;
 4     cout << "How Many Lines Inside?" << endl;
 5     cin >> nLineNumbers;
 6     while(nLineNumbers --)
 7     {
 8         cout << "Input Line Point A, B" << endl;
 9         cin >> nItem >> Point;
10         tmpGphLst.AddToListByOrder(nItem, Point);
11     }
12     tmpGphLst.BFS();
13     cout << endl;

在看演示效果:

 

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

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

图论,我就写这些啦~

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

  1 #include <iostream>
  2 #include <queue>
  3 
  4 using namespace std;
  5 
  6 class Graph
  7 {
  8     private:
  9     //访问控制
 10     int p_nVisitList[5];
 11     int (* pBlock)[5];
 12 
 13     public:
 14     Graph(int (*pParam)[5]);
 15     ~Graph();
 16     //深度优先遍历
 17     int DeepSearch(int Point = 0);
 18     void BFS();
 19     void ResetVisit();
 20 };
 21 
 22 class ListNode
 23 {
 24     public:
 25         int val;
 26         int weight;
 27         ListNode * next;
 28     public:
 29         ListNode();
 30 };
 31 ListNode::ListNode():val(0), weight(0), next(NULL)
 32 {
 33     ;
 34 }
 35 class GraphList
 36 {
 37     public:
 38         GraphList();
 39         ~GraphList();
 40         void AddToListByOrder(int nitem, int Point);
 41         void BFS(int n = 0);//这个广度优先遍历的代码太好写了
 42     private:
 43         int visit[5];
 44         ListNode * Next[5];
 45 };
 46 void GraphList::AddToListByOrder(int nitem, int Point)//前插法,代码好写
 47 {
 48     if(nitem >= 0 && nitem < 5 && Point >= 0 && Point < 5)
 49     {
 50         ListNode * pnewnode = new ListNode;
 51         if(pnewnode == NULL)
 52             return;
 53         pnewnode->val = Point;
 54         pnewnode->next = Next[nitem];
 55         Next[nitem] = pnewnode;
 56     }
 57 }
 58 
 59 void GraphList::BFS(int n)
 60 {
 61     for(int i = 0;i < 5;++ i)
 62     {
 63         if(visit[i] == 0)
 64         {
 65             cout << i << ends;
 66             visit[i] = 1;
 67         }
 68         ListNode * pLNTmp = Next[i];
 69         while(pLNTmp != NULL)
 70         {
 71             if(0 == visit[pLNTmp->val])
 72             {
 73                 cout << pLNTmp->val << ends;
 74                 visit[pLNTmp->val] = 1;
 75             }
 76             pLNTmp = pLNTmp -> next;
 77         }
 78     }
 79 }
 80 
 81 GraphList::GraphList()
 82 {
 83     for(int i = 0;i < 5;++ i)
 84     {
 85         visit[i] = 0;
 86         Next[i] = NULL;
 87     }
 88 }
 89 
 90 GraphList::~GraphList()
 91 {
 92     for(int i = 0;i < 5;++ i)
 93     {
 94         ListNode * ptmpLN;
 95         while(Next[i] != NULL)
 96         {
 97             ptmpLN = Next[i]->next;
 98             delete Next[i];
 99             Next[i] = ptmpLN;
100         }
101     }
102 }
103 
104 void Graph::ResetVisit()
105 {
106     for(int i = 0;i < 5;++ i)
107     {
108         p_nVisitList[i] = 0;
109     }
110 }
111 Graph::Graph(int (*pParam)[5])
112 {
113     for(int i = 0;i < 5;++ i)
114         p_nVisitList[i] = 0;
115     pBlock = pParam;
116 }
117 
118 Graph::~Graph()
119 {
120     ;//nothing!
121 }
122 
123 int Graph::DeepSearch(int Point)
124 {
125     p_nVisitList[Point] = 1;
126     cout << Point << ends;
127 
128     for(int i = 0;i < 5;++ i)
129     {
130         if(1 == pBlock[Point][i] && 0 == p_nVisitList[i])
131         {
132             DeepSearch(i);
133         }
134     }
135     return 0;
136 }
137 
138 void Graph::BFS()
139 {
140     p_nVisitList[4] = 1;
141     cout << 4 << ends;
142     queue<int> DL;
143     DL.push(4);
144     while(!DL.empty())
145     {
146         int val = DL.front();
147         DL.pop();
148         for(int i = 0;i < 5;++ i)
149         {
150             if(1 == pBlock[val][i] && p_nVisitList[i] == 0)
151             {
152                 cout << i << ends;
153                 p_nVisitList[i] = 1;
154                 DL.push(i);
155             }
156         }
157     }
158 }
159 
160 int main()
161 {
162     cout << "Hello world!" << endl;
163     int Block[5][5] = \
164     {
165         0, 1, 1, 1, 0, \
166         1, 0, 1, 1, 0, \
167         1, 1, 0, 0, 1, \
168         1, 1, 0, 0, 1, \
169         0, 0, 1, 1, 0  \
170     };
171     Graph tmpGph(Block);
172     tmpGph.DeepSearch();
173     tmpGph.ResetVisit();
174     cout << endl;
175     tmpGph.BFS();
176     //New Job!!!
177     GraphList tmpGphLst;
178     int nLineNumbers = 0;
179     int nItem, Point;
180     cout << "How Many Lines Inside?" << endl;
181     cin >> nLineNumbers;
182     while(nLineNumbers --)
183     {
184         cout << "Input Line Point A, B" << endl;
185         cin >> nItem >> Point;
186         tmpGphLst.AddToListByOrder(nItem, Point);
187     }
188     tmpGphLst.BFS();
189     cout << endl;
190     return 0;
191 }

 

posted @ 2013-08-24 20:00  Matrix_R  阅读(3568)  评论(2编辑  收藏  举报