圖的廣度遍歷和深度遍歷思想不一樣。后者是用遞歸的方法來(lái)實(shí)現(xiàn)的,這個(gè)是要借助隊(duì)列來(lái)實(shí)現(xiàn)的。
實(shí)現(xiàn)的基本思想如下:
1、從圖中某個(gè)頂點(diǎn)V0出發(fā),并訪(fǎng)問(wèn)此頂點(diǎn);
2、從V0出發(fā),訪(fǎng)問(wèn)V0的各個(gè)未曾訪(fǎng)問(wèn)的鄰接點(diǎn)W1,W2,…,Wk;然后,依次從W1,W2,…,Wk出發(fā)訪(fǎng)問(wèn)各自未被訪(fǎng)問(wèn)的鄰接點(diǎn);
3、重復(fù)步驟2,直到全部頂點(diǎn)都被訪(fǎng)問(wèn)為止。</br>
廣度優(yōu)先遍歷是以層為順序,和樹(shù)的層次遍歷差不多,是將某一層上的所有節(jié)點(diǎn)都搜索到了之后才向下一層搜索;而深度優(yōu)先遍歷是將某一條枝椏上的所有節(jié)點(diǎn)都搜索到了之后,才轉(zhuǎn)向搜索另一條枝椏上的所有節(jié)點(diǎn)。
深度優(yōu)先遍歷從某個(gè)頂點(diǎn)出發(fā),首先訪(fǎng)問(wèn)這個(gè)頂點(diǎn),然后找出剛訪(fǎng)問(wèn)這個(gè)結(jié)點(diǎn)的第一個(gè)未被訪(fǎng)問(wèn)的鄰結(jié)點(diǎn),然后再以此鄰結(jié)點(diǎn)為頂點(diǎn),繼續(xù)找它的下一個(gè)新的頂點(diǎn)進(jìn)行訪(fǎng)問(wèn),重復(fù)此步驟,直到所有結(jié)點(diǎn)都被訪(fǎng)問(wèn)完為止。
廣度優(yōu)先遍歷從某個(gè)頂點(diǎn)出發(fā),首先訪(fǎng)問(wèn)這個(gè)頂點(diǎn),然后找出這個(gè)結(jié)點(diǎn)的所有未被訪(fǎng)問(wèn)的鄰接點(diǎn),訪(fǎng)問(wèn)完后再訪(fǎng)問(wèn)這些結(jié)點(diǎn)中第一個(gè)鄰接點(diǎn)的所有結(jié)點(diǎn),重復(fù)此方法,直到所有結(jié)點(diǎn)都被訪(fǎng)問(wèn)完為止。
可以看到兩種方法最大的區(qū)別在于前者從頂點(diǎn)的第一個(gè)鄰接點(diǎn)一直訪(fǎng)問(wèn)下去再訪(fǎng)問(wèn)頂點(diǎn)的第二個(gè)鄰接點(diǎn);后者從頂點(diǎn)開(kāi)始訪(fǎng)問(wèn)該頂點(diǎn)的所有鄰接點(diǎn)再依次向下,一層一層的訪(fǎng)問(wèn)。
在這里我是用對(duì)圖的存儲(chǔ)方式是用鄰接矩陣來(lái)實(shí)現(xiàn)的。
這種方法是用一個(gè)一維數(shù)組來(lái)表示頂點(diǎn),用一個(gè)二緯數(shù)組來(lái)實(shí)現(xiàn)對(duì)邊的存儲(chǔ),若a和b之間有邊,那就讓二位數(shù)組中的這兩個(gè)數(shù)據(jù)對(duì)應(yīng)的數(shù)據(jù)中填入1;沒(méi)有回路用一個(gè)很大的樹(shù)來(lái)表示就好了
具體可參考圖的鄰接矩陣百度百科
對(duì)于圖的廣度遍歷的具體的演示過(guò)程請(qǐng)看廣度優(yōu)先優(yōu)酷
在這里給出C++的代碼
在這里寫(xiě)的是無(wú)向圖,測(cè)試用的是無(wú)向圖,其實(shí)有向圖和這個(gè)基本一樣,只是加了一個(gè)邊的方向,想要修改也就是在搜索下一條邊的時(shí)候要搜兩次,一次是a到b,一個(gè)是b到a;
這是隊(duì)列的實(shí)現(xiàn)代碼
//
// Graph.hpp
// 圖的廣度優(yōu)先
//
// Created by 橘子和香蕉 on 2018/11/26.
// Copyright ? 2018 橘子和香蕉. All rights reserved.
//
/*
這這里用鏈表的形式來(lái)實(shí)現(xiàn)隊(duì)列;
隊(duì)列的實(shí)現(xiàn)有兩種,一種是數(shù)組,循環(huán)隊(duì)列。一種是鏈表
兩個(gè)指針,一個(gè)指向頭,一個(gè)指向尾。數(shù)據(jù)是在尾指針添加,在頭指針刪除。
*/
#include <iostream>
using namespace std;
typedef struct qnode{
int position;
qnode *next;
}qnode;
class Cqueue{
private:
qnode *front;//頭指針
qnode *rear;//尾指針
int length;//隊(duì)列的長(zhǎng)度
public:
Cqueue();
~Cqueue();
void inQueue(int data);//data入隊(duì)
int outQueue();//出隊(duì)列
void printCqueue();//輸出隊(duì)列
bool isEmpty();//判斷隊(duì)列是不是空
};
Cqueue::Cqueue(){
front = new qnode;
front->next = NULL;
rear = front;
length = 0;
}
Cqueue::~Cqueue(){
qnode *p;
while (front != NULL ) {
p = front;
front = front->next;
delete p;
}
}
void Cqueue::inQueue(int data){
// qnode *n = new qnode;
// n->position = data;
// n->next = rear->next;
// rear->next = n;
// rear = n;
// if(front ->next == NULL ){
// front->next = n;
// }
// length ++;
qnode *p = new qnode;
p->position = data;
p->next = NULL;
rear->next = p;
rear = p;
length++;
}
int Cqueue::outQueue(){
if(front == rear){
cout<<"error\n";
return -1;
}
// qnode *p = front ->next;
// int data = p->position;
// front->next = p->next;
// if(p->next == NULL){
// rear = front;
// }
// delete p;
// length--;
// return data;
qnode *p = front->next;
int data = p->position;
front->next = p->next;
if(p->next ==NULL){
rear = front;
}
delete p;
length--;
return data;
}
void Cqueue::printCqueue(){
qnode *p = front->next;
while (p != NULL) {
cout<<p->position<<"\t";
p = p->next;
}
cout<<"length"<<length<<endl;
cout<<endl;
}
bool Cqueue::isEmpty(){
return front == rear?true:false;
}
下面是圖的實(shí)現(xiàn)代碼:
//
// Graph.hpp
// 圖的廣度優(yōu)先
//
// Created by 橘子和香蕉 on 2018/11/26.
// Copyright ? 2018 橘子和香蕉. All rights reserved.
//
#include <iostream>
using namespace std;
#define VERTEXNUM 100
#define dataType char
typedef struct node{
dataType data;
bool isAccess;
}node;
class Graph{
private:
node vertex[VERTEXNUM];//頂點(diǎn)表
int edge[VERTEXNUM][VERTEXNUM];//邊表
int vertexNum;//頂點(diǎn)個(gè)數(shù)
int edgeNum;//邊的個(gè)數(shù)
int locate(dataType data);//在頂點(diǎn)表中找data的位置
bool isHaveNevEdge(dataType data);//data是不是還有鄰接點(diǎn)
void move(dataType data);//若一個(gè)頂點(diǎn)被刪除后,沒(méi)有鄰接點(diǎn),那就從頂點(diǎn)表中刪除這個(gè)元素,然后在頂點(diǎn)表和邊表中都要移動(dòng)數(shù)據(jù)元素。
int getFirstVertex(dataType data);//得到元素的第一個(gè)鄰接點(diǎn)位置。
int getNextNevVertex(dataType data,dataType FrontData);//得到data頂點(diǎn)從Frontdata之后的第一個(gè)頂點(diǎn)位置。
public:
void init(int vertex ,int edgeNum);//初始化邊數(shù)和頂點(diǎn)數(shù)。并且初始化邊表的數(shù)組。
void create();//創(chuàng)建圖
void printGraph();//輸出
void addEdge(dataType start,dataType end);//添加一條邊
void deleteEdege(dataType start,dataType end);//刪除一條邊
void breadthFirstSearch(dataType data);//廣度優(yōu)先遍歷
};
int Graph::locate(dataType data){
for (int i = 0; i<vertexNum;i++) {
if(vertex[i].data == data){
return I;
}
}
return -1;
}
void Graph::create(){
cout<<"input Graph data\n";
for (int i = 0; i<vertexNum; i++) {
cin>>vertex[i].data;
vertex[i].isAccess = false;
}
for (int j = 0; j<edgeNum; j++) {
cout<<"input start and end of edge:\n";
char start ,end;
cin>>start>>end;
int startPosition = locate(start);
int endPosition = locate(end);
edge[startPosition][endPosition] = 1;
edge[endPosition][startPosition] = 1;
}
}
void Graph::init(int vertex, int edgeNum){
this->vertexNum = vertex;
this->edgeNum = edgeNum;
for (int i = 0; i<VERTEXNUM; i++) {
for (int j = 0; j<VERTEXNUM; j++) {
edge[i][j] = INT_MAX;
}
}
}
void Graph::printGraph(){
cout<<endl;
cout<<endl;
cout<<"頂點(diǎn)邊:\n";
cout<<"vertexNum:"<<vertexNum<<" edgeNum:"<<edgeNum<<endl;
for (int i = 0; i<vertexNum; i++) {
cout<<vertex[i].data<<"\t";
}
cout<<"邊表如下:\n";
for (int j = 0; j<edgeNum; j++) {
for (int k = 0; k<edgeNum ; k++) {
cout<<edge[j][k]<<"\t";
}
cout<<endl;
}
}
bool Graph::isHaveNevEdge( dataType data ){
int position = locate(data);
for (int i = 0; i<vertexNum; i++) {
if(edge[position][i] != INT_MAX){
return true;
}
}
return false;
}
void Graph::move(dataType data){
int positon = locate(data);
for (int i = positon; i<vertexNum; i++) {
vertex[i].data = vertex[i+1].data;
vertex[i].isAccess = vertex[i+1].isAccess;
}
vertexNum --;
for (int i = positon; i<vertexNum; i++) {
for (int j = 0; j<vertexNum; j++) {
edge[i][j] = edge[i+1][j];
}
}
edgeNum--;
}
void Graph::addEdge(char start, char end){
int startPositon = locate(start);
int endPosition = locate(end);
if(startPositon == -1 && endPosition != -1){
vertex[vertexNum].data = start;
vertex[vertexNum].isAccess = false;
this->vertexNum+=1;
this->edgeNum+=1;
startPositon = vertexNum-1;
}
if(startPositon != -1 && endPosition == -1){
vertex[vertexNum].data = end;
vertex[vertexNum].isAccess = false;
this->vertexNum+=1;
this->edgeNum+=1;
endPosition = vertexNum-1;
}
if(startPositon == -1 && endPosition == -1){
vertex[vertexNum].data = start;
vertex[vertexNum].isAccess = false;
this->vertexNum+=1;
this->edgeNum+=0;
startPositon = vertexNum-1;
vertex[vertexNum].data = end;
vertex[vertexNum].isAccess = false;
this->vertexNum+=1;
this->edgeNum+=1;
endPosition = vertexNum-1;
}
edge[startPositon][endPosition] = 1;
edge[endPosition][startPositon] = 1;
cout<<startPositon<<endPosition;
cout<< edge[startPositon][endPosition]<<";"<<edge[endPosition][startPositon] <<endl;
}
void Graph::deleteEdege(dataType start, dataType end){
int startPosition = locate(start);
int endPosition = locate(end);
if(startPosition == -1 || endPosition == -1){
cout<<"error\n";
return;
}
edge[startPosition][endPosition] = INT_MAX;
edge[endPosition][startPosition] = INT_MAX;
if(! isHaveNevEdge(start)){
move(start);
}
if(! isHaveNevEdge(end)){
move(end);
}
}
int Graph::getFirstVertex(dataType data){
int position = locate(data);
for (int i = 0; i<vertexNum; i++) {
if( edge[position][i] == 1 ){
return I;
}
}
return -1;
}
int Graph::getNextNevVertex(dataType data ,dataType frontData){
int position = locate(data);
int frontPosition = locate(frontData);
for (int i = frontPosition+1 ; i<vertexNum; i++) {
if(edge[position][i] == 1){
return I;
}
}
return -1;
}
void Graph::breadthFirstSearch(dataType data){
cout<<"DFS:\n";
Cqueue queue;
int position = locate(data);
int queueHeadPosition = -1;
if(position == -1){
cout<<"the vettex is not exist\n";
return;
}
vertex[position].isAccess = true;
queue.inQueue(position);// 入隊(duì)列
cout<<position<<endl;
while(queue.isEmpty() == false){
queueHeadPosition = queue.outQueue();//獲得隊(duì)列的頭元素
cout<<vertex[queueHeadPosition].data<<"\t";
for (
int i = getFirstVertex(vertex[queueHeadPosition].data);//獲得隊(duì)列頭元素的第一個(gè)鄰接點(diǎn)
i>=0;
i = getNextNevVertex(vertex[queueHeadPosition].data, vertex[i].data)//獲得從i之后下一個(gè)鄰接點(diǎn)
) {
if(vertex[i].isAccess == false){
queue.inQueue(i);
vertex[i].isAccess = true;
// cout<<vertex[i].data<<"\t";
}
}
}
cout<<endl;
}
下面給出main函數(shù):
//
// main.cpp
// 圖的廣度優(yōu)先
//
// Created by 橘子和香蕉 on 2018/11/26.
// Copyright ? 2018 橘子和香蕉. All rights reserved.
//
#include <iostream>
using namespace std;
int main(){
// Cqueue a;
// a.inQueue(3);
// a.inQueue(4);
// a.inQueue(5);
// a.printCqueue();
// a.outQueue();
// a.printCqueue();
// a.outQueue();
// a.printCqueue();
// for (int i = 23; i<40; i++) {
// a.inQueue(i);
// }
// a.printCqueue();
Graph s;
s.init(4, 4);
s.create();
s.printGraph();
// s.addEdge('b', 'e');
// s.printGraph();
// s.deleteEdege('b', 'e');
// s.printGraph();
// s.breadthFirstSearch('d');
// s.breadthFirstSearch('b');
s.breadthFirstSearch('a');
return 1;
}
注意:在測(cè)試的時(shí)候不能在一次運(yùn)行的時(shí)候連續(xù)從一個(gè)頂點(diǎn)開(kāi)始廣度優(yōu)先遍歷,因?yàn)樵诘谝淮伪闅v的時(shí)候就將其設(shè)置為訪(fǎng)問(wèn)過(guò),第二次遍歷的時(shí)候就不能繼續(xù)訪(fǎng)問(wèn)了,這個(gè)問(wèn)題也是很好解決的,就是在添加一個(gè)函數(shù)用來(lái)沒(méi)次訪(fǎng)問(wèn)完了后將所有的結(jié)點(diǎn)設(shè)置為沒(méi)有訪(fǎng)問(wèn)過(guò)就好了,這樣就可以在一次運(yùn)行中連續(xù)運(yùn)行。而不是下面這樣,需要注釋幾個(gè),每次只能從一個(gè)結(jié)點(diǎn)出發(fā)。