根据分类,图的搜索分类能够分为html
先看BFS和DFS,由于这是最基础的搜索策略了,BFS是按照深度进行搜索,DFS则是按照广度进行搜索;数组
其实只要你理解了树的DFS和BFS,那么图的话,只是在其基础上加了判断结点是否访问过,是否联通而已;.net
先看一幅有向图指针
能够发现,其遍历的顺序为code
0->3->1->2->4htm
其的概念就是一条路走到黑blog
图的表示方法包括邻接表,邻接矩阵等,邻接矩阵表示的是用一个二维数组表示图的联通,其中i行j列表示了i结点和j结点的联通状况,若是其为1,说明是联通的,若是其为0,反之;邻接表表示的是一个一维数组,可是数组中每一个列表包含着是链表;递归
看个图加深理解:
队列
其中a是有向图/原图,b是邻接表表示图,c是邻接矩阵表示图;ip
1. 访问数组初始化:visited[n] = 0 2. 访问顶点:visited[v] = 1 3. 取v的第一个邻接点w; 4. 循环递归: while(w存在) if(w未被访问过) 从顶点w出发递归执行; w = v的下一个邻接点;
1. 栈初始化:visited[n] = 0 2. 访问顶点:visited[v] = 1 3. 入栈 4. while(栈不为空) x = 栈的顶元素,而且出栈; if (存在并找到未被访问的x的邻接点w) 访问w:visited[w] = 1 w进栈
上面的寻找下一个邻接点,须要根据图是邻接表仍是邻接矩阵进行循环判断;
因为图的表示有几种,因此实现的代码包括了用邻接矩阵的图和邻接表的图;
.h文件
typedef struct edge { int vertex; struct edge* next; }Edge; class DFS { public: DFS(); ~DFS(); void Test_M(); void Test_L(); private: // 邻接矩阵 void createGraph_M(int (*edge)[VERTEXNUM], int start, int end); void displayGraph_M(int (*edge)[VERTEXNUM]); void DFT_M(int (*edge)[VERTEXNUM], int* vertexStatusArr); void DFTCore_M(int (*edge)[VERTEXNUM], int i, int* vertexStatusArr); // 邻接表 void createGraph_L(Edge** edge, int start, int end); void displayGraph_L(Edge** edge); void delGraph_L(Edge** edge); void DFT_L(Edge** edge, int* vertextStatusArr); void DFTCore_L(Edge** edge, int i, int* vertexStatusArr); }; void DFSTest_M(); void DFSTest_L();
.cpp文件
DFS::DFS() { } DFS::~DFS() { } /*----------------------------邻接矩阵--------------------------*/ /** * 建立图 * * @param edge <#edge description#> */ void DFS::createGraph_M(int (*edge)[VERTEXNUM], int start, int end) { edge[start][end] = 1; } /** * 打印存储的图 * * @param edge <#edge description#> */ void DFS::displayGraph_M(int (*edge)[VERTEXNUM]) { for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { std::cout << edge[i][j]; } std::cout << std::endl; } } /** * 深度优先遍历 * * @param edge <#edge description#> */ void DFS::DFT_M(int (*edge)[VERTEXNUM], int* vertexStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { DFTCore_M(edge, i, vertexStatusArr); } std::cout << std::endl; } void DFS::DFTCore_M(int (*edge)[VERTEXNUM], int i, int* vertexStatusArr) { if (vertexStatusArr[i] == 1) return; // 顶点访问过则再也不访问 std::cout << i << "->"; vertexStatusArr[i] = 1; // 存在边的对应关系,才递归 for (int j = 0; j < VERTEXNUM; j++) { if (edge[i][j] == 1) { DFTCore_M(edge, j, vertexStatusArr); } } } void DFS::Test_M() { std::cout << "--------------邻接矩阵表示-----------------" << std::endl; //动态建立存放边的二维数组 int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int) * VERTEXNUM * VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { edge[i][j] = 0; } } // 存放顶点的遍历状态;0:未遍历,1:已遍历 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_M(edge); //建立图 createGraph_M(edge, 0, 3); createGraph_M(edge, 0, 4); createGraph_M(edge, 3, 1); createGraph_M(edge, 3, 2); createGraph_M(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_M(edge); // 遍历 std::cout << "traversal.." << std::endl; DFT_M(edge, vertexStatusArr); free(edge); } /*----------------------------邻接表--------------------------*/ void DFS::createGraph_L(Edge** edge, int start, int end) { Edge* nedge = (Edge*)malloc(sizeof(Edge)); nedge->vertex = end; nedge->next = nullptr; edge = edge + start; while (*edge != nullptr) { edge = &((*edge)->next); } *edge = nedge; } void DFS::displayGraph_L(Edge** edge) { Edge* nedge; int edgeCount = 0; for (int i = 0; i < VERTEXNUM; i++) { nedge = *(edge + i); std::cout << i << ":"; while (nedge != nullptr) { std::cout << nedge->vertex << ","; nedge = nedge->next; edgeCount++; } std::cout << std::endl; } std::cout <<"edge count is " << edgeCount << std::endl; } void DFS::delGraph_L(Edge** edge) { Edge *p, *del; for (int i = 0; i < VERTEXNUM; i++) { p = *(edge + i); while (p != nullptr) { del = p; p = p->next; free(del); } edge[i] = nullptr; } free(edge); } void DFS::DFT_L(Edge** edge, int* vertextStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { DFTCore_L(edge, i, vertextStatusArr); } std::cout << std::endl; } void DFS::DFTCore_L(Edge** edge, int i, int* vertexStatusArr) { if (vertexStatusArr[i] == 1) { return; } std::cout << i << "->"; vertexStatusArr[i] = 1; Edge *p = *(edge + i); while (p != nullptr) { DFTCore_L(edge, p->vertex, vertexStatusArr); p = p->next; } } void DFS::Test_L() { std::cout << "--------------邻接表表示-----------------" << std::endl; // 动态建立存放边的指针数组 Edge **edge = (Edge**)malloc(sizeof(Edge*)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { edge[i] = nullptr; } // 存放顶点的遍历状态:0:未遍历,1:已遍历 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_L(edge); //建立图 createGraph_L(edge, 0, 3); createGraph_L(edge, 0, 4); createGraph_L(edge, 3, 1); createGraph_L(edge, 3, 2); createGraph_L(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_L(edge); // 深度优先遍历 DFT_L(edge, vertexStatusArr); // 释放邻接表占用的内存 delGraph_L(edge); edge = nullptr; free(vertexStatusArr); vertexStatusArr = nullptr; }
总结:代码有很强的C的风格,抱歉;这里面主要看遍历过程;
先看一幅有向图
能够发现,其遍历的顺序为
0->3->4->1->2
其的概念就是左看看右看看,雨露均沾
1. 初始化队列:visited[n] = 0 2. 访问顶点:visited[v] = 1 3. 顶点v加入队列 4. 循环: while(队列是否为空) v = 队列头元素 w = v的第一个邻接点 while(w存在) if(若是w未访问) visited[w] = 1; 顶点w加入队列 w = 顶点v的下一个邻接点
上面的寻找下一个邻接点,是寻找以前结点的下一个邻接点,而不是当前的,不然就变成DFS了;
.h文件
typedef struct bedge { int vertex; struct bedge* pre; struct bedge* next; }BEdge; template <class T> class Queue { private: T *arr; int front; int rear; int size; int length; public: Queue(); ~Queue(); void Push(T value); T Pop(); int Size(); int Length(); bool Empty(); bool Full(); }; class BFS { private: BEdge *front; BEdge *rear; public: BFS(); ~BFS(); void Test_M(); void Test_L(); void createGraph_M(int (*edge)[VERTEXNUM], int start, int end); void displayGraph_M(int (*edge)[VERTEXNUM]); void BFT_M(int (*edge)[VERTEXNUM], int *vertexStatusArr); void BFTCore_M(int (*edge)[VERTEXNUM], int i, int *vertexStatusArr); void createGraph_L(BEdge** edge, int start, int end); void displayGraph_L(BEdge** edge); void delGraph_L(BEdge** edge); void BFT_L(BEdge** edge, int* vertextStatusArr); void BFTCore_L(BEdge** edge, int i, int* vertexStatusArr); }; void BFSTest_M(); void BFSTest_L();
.cpp文件
template <class T> Queue<T>::Queue() { size = 10; arr = new T[size]; front = rear = length = 0; } template <class T> Queue<T>::~Queue() { delete [] arr; } template <class T> void Queue<T>::Push(T value) { // 大于原数组长度,建立新数组,赋值给新数组 if (length == size) { int nsize = size * 2; int * narr = new T(nsize); int i = 0; for (; i < length; i++) { narr[(front + i) % nsize] = arr[(front + i) % size]; } rear = (front + i) % nsize; arr = narr; size = nsize; } arr[rear] = value; rear = (rear + 1) % size; ++length; } template <class T> T Queue<T>::Pop() { T temp = arr[front]; front = (front + 1) % size; // 原来的内存块没有作到真正的删除 --length; return temp; } template <class T> int Queue<T>::Size() { return size; } template <class T> int Queue<T>::Length() { return length; } template <class T> bool Queue<T>::Empty() { return length == 0; } template <class T> bool Queue<T>::Full() { return length == size; } BFS::BFS() { } BFS::~BFS() { } void BFS::createGraph_M(int (*edge)[VERTEXNUM], int start, int end) { edge[start][end] = 1; } void BFS::displayGraph_M(int (*edge)[VERTEXNUM]) { for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { std::cout << edge[i][j]; } std::cout << std::endl; } } void BFS::BFT_M(int (*edge)[VERTEXNUM], int *vertexStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { BFTCore_M(edge, i, vertexStatusArr); } std::cout << std::endl; } void BFS::BFTCore_M(int (*edge)[VERTEXNUM], int i, int *vertexStatusArr) { Queue<int> queue; queue.Push(i); while (!queue.Empty()) { int t = queue.Pop(); if (vertexStatusArr[t] == 0) { std::cout << t << "->"; vertexStatusArr[t] = 1; for (int i = 0; i < VERTEXNUM; i++) { if (edge[t][i] == 1) { queue.Push(i); } } } } } void BFS::Test_M() { std::cout << "--------------邻接矩阵表示-----------------" << std::endl; //动态建立存放边的二维数组 int (*edge)[VERTEXNUM] = (int (*)[VERTEXNUM])malloc(sizeof(int) * VERTEXNUM * VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { for (int j = 0; j < VERTEXNUM; j++) { edge[i][j] = 0; } } // 存放顶点的遍历状态;0:未遍历,1:已遍历 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_M(edge); //建立图 createGraph_M(edge, 0, 3); createGraph_M(edge, 0, 4); createGraph_M(edge, 3, 1); createGraph_M(edge, 3, 2); createGraph_M(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_M(edge); // 遍历 std::cout << "traversal.." << std::endl; BFT_M(edge, vertexStatusArr); free(edge); } void BFS::createGraph_L(BEdge** edge, int start, int end) { BEdge* nedge = (BEdge*)malloc(sizeof(BEdge)); nedge->vertex = end; nedge->next = nullptr; edge = edge + start; while (*edge != nullptr) { edge = &((*edge)->next); } *edge = nedge; } void BFS::displayGraph_L(BEdge** edge) { BEdge* nedge; int edgeCount = 0; for (int i = 0; i < VERTEXNUM; i++) { nedge = *(edge + i); std::cout << i << ":"; while (nedge != nullptr) { std::cout << nedge->vertex << ","; nedge = nedge->next; edgeCount++; } std::cout << std::endl; } std::cout <<"edge count is " << edgeCount << std::endl; } void BFS::delGraph_L(BEdge** edge) { BEdge *p, *del; for (int i = 0; i < VERTEXNUM; i++) { p = *(edge + i); while (p != nullptr) { del = p; p = p->next; free(del); } edge[i] = nullptr; } free(edge); } void BFS::BFT_L(BEdge** edge, int* vertextStatusArr) { for (int i = 0; i < VERTEXNUM; i++) { BFTCore_L(edge, i, vertextStatusArr); } std::cout << std::endl; } void BFS::BFTCore_L(BEdge** edge, int i, int* vertexStatusArr) { Queue<int> queue; queue.Push(i); while (!queue.Empty()) { int t = queue.Pop(); if (vertexStatusArr[t] == 0) { std::cout << t << "->"; vertexStatusArr[t] = 1; BEdge* p = *(edge + t); while (p != nullptr) { queue.Push(p->vertex); p = p->next; } } } } void BFS::Test_L() { std::cout << "--------------邻接表表示-----------------" << std::endl; // 动态建立存放边的指针数组 BEdge **edge = (BEdge**)malloc(sizeof(BEdge*)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { edge[i] = nullptr; } // 存放顶点的遍历状态:0:未遍历,1:已遍历 int *vertexStatusArr = (int*)malloc(sizeof(int)*VERTEXNUM); for (int i = 0; i < VERTEXNUM; i++) { vertexStatusArr[i] = 0; } std::cout << "after init.." << std::endl; displayGraph_L(edge); //建立图 createGraph_L(edge, 0, 3); createGraph_L(edge, 0, 4); createGraph_L(edge, 3, 1); createGraph_L(edge, 3, 2); createGraph_L(edge, 4, 1); std::cout << "after create.." << std::endl; displayGraph_L(edge); // 深度优先遍历 BFT_L(edge, vertexStatusArr); // 释放邻接表占用的内存 delGraph_L(edge); edge = nullptr; free(vertexStatusArr); vertexStatusArr = nullptr; }
参考: