71、图的定义与操作

定义:图是由顶点集合(Vertex)及顶点间的关系集合边(Edge)组成的一种数据结构:

Graph=(V,E)

V={x|x属于某个数据对象}是顶点的有穷非空集合。

E={{x,y}|x,y属于V}是顶点之间关系的有穷集合。

无向边:顶点x和y之间的边没有方向,则称该边为无向边。

(x,y)与(y,x)意义相同,表示x,y之间有连接

无向图:图中任意两个顶点之间的边均是无向边,则称该图为无向图。

有向边:顶点x和y之间的边有方向,则称该边为有向边。

<x,y>与<y,x>意义不同:<x,y>表示从x连接到y,x称为尾,y称为头。<y,x>表示从y连接到x,y称为尾,x称为头。

有向图:图中任意两个顶点之间的边均是有向边,则称该图为有向图。

无向图可以看作一种特殊的有向图!

顶点邻接(Adjacent)的定义

无向图:如果(x,y)属于E,则称顶点x和y互为邻接。

无向图:如果<x,y>属于E,则称顶点x邻接到顶点y。

度(degree)的定义:顶点v的度是和v相关联的边的数目,记为TD(v)

入度:以v为头的边的数目,记为ID(v)

出度:以v为尾的边的数目,记为OD(v)

推论:

TD(v)=ID(v)+OD(v)

count(E)=ID(v1)+ID(v2)+...+ID(v3)

count(E)=OD(v1)+OD(v2)+...+OD(vn)

count(E)=[TD(v1)+TD(v2)+...+TD(vn)]/2

权(Weight)的定义:与图相关的数据元素叫做权,权常用来表示图中顶点间的距离或者耗费。

图的一些常用操作:设置顶点的值,获取顶点的值,获取邻接顶点,设置边的值,删除边,获取顶点数,获取边数。

图在程序中表现为一种特殊的数据类型。

小结:图是顶点与边的集合,是一种非线性的数据结构,图中顶点可以与多个其它顶点产生邻接关系,图中的边有与之对应的权值,表示顶点间的距离,图在程序中表现为特殊的数据类型。

72、图的存储结构

基本思想:

用一维数组存储顶点:描述顶点相关的数据。

用二维数组存储边:描述顶点间的关系和权。

邻接矩阵法:设图A=(V,E)是一个有n个顶点的图,图的邻接矩阵为Edge[n][n],则:

Edge[i][j]=

W, W权值,i和j连接

空, i==j或i和j不连接

注:解决工程为题时,习惯于对图中的每个顶点进行编号,当不需要权值时,取W非空表示结点间有连结。

邻接矩阵法实例一:无向图的邻接矩阵是对称的。

邻接矩阵法实例二

有向图的邻接矩阵可能是不对称的。

继承自Graph.

实现方式一:直接使用数组表示顶点集和边集。

问题:构造效率低下:图对象初始化时,频繁调用顶点类型和边类型的构造函数。

空间使用率低下:图对象占用大量空间,而大多数空间处于闲置状态。

无法表示空值:无法用统一的方式表示边为空的情形。

实现方式二:使用指针数组表示顶点集和边集。

问题的解决:构造效率:初始化对象时,只需要将数组元素赋值为空,空间使用率:顶点数据元素和边数据元素在需要时动态创建。空值的表示:任意的顶点类型和边类型都使用NULL表示空值。

namespace WSlib
{
template <int N,typename V,typename E>//顶点个数N,与顶点相关的数据类型V,权值类型E
class MatrixGraph:public Graph<V,E>
{
protected:
V* m_vertexes[N]; //指针数组,指向与顶点相关联的数据元素
E* m_edges[N][N]; //邻接矩阵
int m_eCount;  //记录有多少条边
public:
MatrixGraph()
{
for(int i=0;i<vCount();i++)
{
m_vertexes[i]=NULL;
for(int j=0;j<vCount();j++)
{
m_edges[i][j]=NULL;
}
}
m_eCount=0;
}
V getVertex(int i)
{
V ret;
if(!getVertex(i,ret))
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid...");
}
return ret;
}
bool getVertex(int i, V& value)
{
bool ret=((0<=i)&&(i<vCount()));
if(ret)
{
if(m_vertexes[i]!=NULL)
{
value=*(m_vertexes[i]);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"no value assigned to this vertex...");
}
}
return ret;
}
bool setVertex(int i,const V& value)
{
bool ret=((0<=i)&&(i<vCount()));
if(ret)
{
/*if(m_vertexes[i]==NULL)
{
m_vertexes[i]=new V();
}
if(m_vertexes[i]!=NULL)
{
*(m_vertexes[i])=value; //没考虑异常安全,这行产生异常函数就会异常返回,图对象由于new,编号为i的顶点不为空,它关联的值不是合法的值,这样图对象不合法,就不能用了。用一个中间变量data
}*/
V* data=m_vertexes[i];
if(data==NULL)
{
data=new V();
}
if(data!=NULL)
{
*data=value;//这样这行出现异常,图对象内部状态不被改变
m_vertexes[i]=data;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory");
}
}
return ret;
}
SharedPointer<Array<int> >getAdjacent(int i)
{
DynamicArray<int>* ret=NULL;
if((0<=i)&&(i<vCount()))
{
int n=0;
for(int j=0;j<vCount();j++)
{
if(m_edges[i][j]!=NULL)
{
n++;
}
}
ret=new DynamicArray<int>(n);
if(ret!=NULL)
{
for(int j=0,k=0;j<vCount();j++)
{
if(m_edges[i][j]!=NULL)
{
ret->set(k++,j);
}
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory");
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid...");
}
return ret;


}
E getEdge(int i,int j)
{
E ret;
if(!getEdge(i,j,ret))
{
THROW_EXCEPTION(InvalidParameterException,"index is invalid");
}
return ret;
}
bool getEdge(int i,int j,E& value)
{
bool ret=((0<=i)&&(j<=vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
if(m_edges[i][j]!=NULL)
{
value=*(m_edges[i][j]);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No value assigned to this edge");
}
}
return ret;
}
bool setEdge(int i,int j,const E& value)
{
bool ret=((0<=i)&&(j<=vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
E* ne=m_edges[i][j];
if(ne==NULL)
{
ne=new E();
if(ne!=NULL)
{
*ne=value;
m_edges[i][j]=ne;
m_eCount++;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory");
}
}
else
{
*ne=value;
}
}
return ret;
}
bool removeEdge(int i,int j)
{
bool ret=((0<=i)&&(j<=vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
E* toDel=m_edges[i][j]; //异常安全
m_edges[i][j]=NULL;
if(toDel!=NULL)
{
m_eCount--;
delete toDel;
}
}
return ret;
}
int vCount()
{
return N;
}
int eCount()
{
return m_eCount;
}
int OD(int i)
{
int ret=0;
if((0<=i)&&(i<=vCount()))
{
for(int j=0;j<vCount();j++)
{
if(m_edges[i][j]!=NULL)
{
ret++;
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index i is invalid..");
}
return ret;
}
int ID(int i)
{
int ret=0;
if((0<=i)&&(i<=vCount()))
{
for(int j=0;j<vCount();j++)
{
if(m_edges[j][i]!=NULL)
{
ret++;
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index i is invalid..");
}
return ret;
}
~MatrixGraph()
{
for(int i=0;i<vCount();i++)
{
for(int j=0;j<vCount();j++)
{
delete m_edges[i][j];
}
delete m_vertexes[i];
}
};

int main()
{
MatrixGraph<3,int,int> g;
g.setEdge(0,1,1);
g.setEdge(1,0,2);
g.setEdge(1,2,3);
cout<<"vcount:"<<g.vCount()<<endl;
cout<<"ecount:"<<g.eCount()<<endl;
cout<<"id(1):"<<g.ID(1)<<endl;
cout<<"od(1):"<<g.OD(1)<<endl;
cout<<"TD(1):"<<g.TD(1)<<endl;
cout<<"w(0,1):"<<g.getEdge(0,1)<<endl;
cout<<"w(1,0):"<<g.getEdge(1,0)<<endl;
cout<<"w(1,2):"<<g.getEdge(1,2)<<endl;
SharedPointer<Array<int> > aj=g.getAdjacent(2);
for(int i=0;i<aj->length();i++)
{
cout<<(*aj)[i]<<" ";//(*aj)[i]:指向含有i个数的数组, *aj[4]:整形指针的数组
}
cout<<endl;
cout<<" delete edge"<<endl;
g.removeEdge(0,1);
cout<<"ecount"<<g.eCount()<<endl;
g.setVertex(0,100);//设置与顶点0相关联的数据元素为100
cout<<"v(100):"<<g.getVertex(0)<<endl;
//cout<<"w(0,1):"<<g.getEdge(0,1)<<endl;//异常,
return 0;
}

小结:邻接矩阵使用数组对图相关的数据进行存储,一维数组存储顶点相关的数据(空表示无关数据),二维数组存储边相关的数据(空表示顶点间无连接),代码实现时使用指针数组进行数据的存储。

73、存储结构下

邻接矩阵中的残留问题:MatrixGraph无法动态添加删除顶点!

N=1000,邻接矩阵体积为4*1000*1000字节,体积约4M!

基本思想:为了进一步提高空间使用率,可以考虑使用链表替换数组,将邻接矩阵变换为邻接链表。

邻接链表法:

图中的所有顶点按照编号存储于同一个链表中,每一个顶点对应一个链表,用于存储始发于改顶点的边,每一条边的信息包含:起点,终点,权值。

边数据类型的设计:

struct Edge:public Wobject

{

int b;//起始顶点

int e;//邻接顶点

E data;//权值

}

顶点数据类型的设计:

struct Vertex:public Wobject

{

V* data; //顶点数据元素值

LinkList<Edge>edge;//邻接与改顶点的边

};

动态增加/删除顶点

int addVertex(); 增加新的顶点,返回顶点编号,末尾添加

int addVertex(const V& value); 增加新顶点的同时附加数据元素

void removeVertex() 删除最近增加的顶点,末尾删除

namespace WSlib
{
template <typename V,typename E>
class ListGraph:public Graph<V,E>
{
protected:
struct Vertex:public Wobject //顶点中包含一个链表用来存储边
{
V* data;   //每个顶点附加的元素
LinkList<Edge<E>>edge;
Vertex()
{
data=NULL;
}
};
LinkList<Vertex*>m_list;//邻接链表
public:
ListGraph(unsigned int n=0)
{
for(unsigned int i=0;i<n;i++ )
{
addVertex();
}
}
int addVertex()//增加顶点就是在链表末尾增加元素 //o(n)
{
int ret=-1;
Vertex* v=new Vertex();
if(v!=NULL)
{
m_list.insert(v);
ret=m_list.length()-1;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory");
}
return ret;
}
int addVertex(const V& value) //o(n)
{
int ret=addVertex();
if(ret>=0)
{
setVertex(ret,value);
}
return ret;
}
bool setVertex(int i,const V& value) //o(n)
{
bool ret=((0<=i)&&(i<vCount()));
if(ret)
{
Vertex* vertex=m_list.get(i);
V* data=vertex->data;
if(data==NULL)
{
data=new V();
}
if(data!=NULL)
{
*data=value;
vertex->data=data;
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"No memory");
}
}
return ret;
}
V getVertex(int i) //o(n)
{
V ret;
if(!getVertex(i,ret))
{
THROW_EXCEPTION(InvalidParameterException,"Index i is valid");
}
return ret;
}
bool getVertex(int i,V& value) //o(n)
{
bool ret=((0<=i)&&(i<vCount()));
if(ret)
{
Vertex* v=m_list.get(i); //o(n)
if(v->data !=NULL)
{
value=*(v->data);
}
else
{
THROW_EXCEPTION(InvalidOperationException,"no value assigned to..");
}
}
return ret;
}
void removeVertex() //o(n^2)
{
if(m_list.length()>0)
{
int index=m_list.length()-1;//只能从后边开始删除
Vertex* v=m_list.get(index); //o(n)
if(m_list.remove(index))
{
//int i=0;//炫技
for(int i=(m_list.move(0),0);!m_list.end();i++,m_list.next()) //o(n)
{
int pos=m_list.current()->edge.find(Edge<E>(i,index));//每个结点找一下,从index出发的边直接删除index结点就可以
//m_list.current()->edge,当前结点的邻接链表。i为起点,index为终点的边是否存在当前邻接链表中,存在pos>=0,此时需要重载相等操作符
if(pos>=0)
{
m_list.current()->edge.remove(pos); //当前顶点的邻接链表删掉
}
//i++;
}
delete v->data; //释放顶点相关联的数据元素值的空间
delete v;       //顶点自身占用的空间释放掉
}
}
else
{
THROW_EXCEPTION(InvalidOperationException,"no vertex");
}
}
SharedPointer<Array<int>>getAdjacent(int i) //o(n)
{
DynamicArray<int>* ret=NULL;
if((0<=i)&&(i<vCount()))
{
Vertex* vertex=m_list.get(i);
ret=new DynamicArray<int>(vertex->edge.length());
if(ret!=NULL)
{
for(int k=(vertex->edge.move(0),0); !vertex->edge.end();k++,vertex->edge.next())
{
ret->set(k,vertex->edge.current().e);//第二个参数e设置为ret的第k个元素
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory to create ret object...");
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index i is invalid...");
}
return ret;
}
E getEdge(int i,int j) //o(n)
{
E ret;
if(!getEdge(i,j,ret))
{
THROW_EXCEPTION(InvalidOperationException,"edge<i,j>is invalid");
}
return ret;
}
bool getEdge(int i,int j,E& value)//o(n)
{
bool ret=((0<=i)&&(i<vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
Vertex* vertex=m_list.get(i);
int pos=vertex->edge.find(Edge<E>(i,j));
if(pos>=0)
{
value=vertex->edge.get(pos).data;
}
else
{
THROW_EXCEPTION(InvalidOperationException,"No value assigned to this edge...");
}
}
return ret;
}
bool setEdge(int i,int j,const E& value)//o(n)
{
bool ret=((0<=i)&&(i<vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
Vertex* vertex=m_list.get(i);
int pos=vertex->edge.find(Edge<E>(i,j));
if(pos>=0)
{
ret=vertex->edge.set(pos,Edge<E>(i,j,value));//把邻接链表对应位置处的边相关的数据元素值重新设置
}
else
{
ret=vertex->edge.insert(0,Edge<E>(i,j,value));
}
}
return ret;
}
bool removeEdge(int i,int j) //o(n)
{
bool ret=((0<=i)&&(i<vCount())&&(0<=j)&&(j<vCount()));
if(ret)
{
Vertex* vertex=m_list.get(i);
int pos=vertex->edge.find(Edge<E>(i,j));
if(pos>=0)
{
ret=vertex->edge.remove(pos);
}
}
return ret;
}
int vCount()//顶点数目 //o(1)
{
return m_list.length();
}
int eCount() //o(n)
{
int ret=0;
for(m_list.move(0);!m_list.end();m_list.next())
{
ret +=m_list.current()->edge.length();
}
return ret;
}
int ID(int i)//o(n^2)
{
int ret=0;
if((0<=i)&&(i<vCount()))
{
for(m_list.move(0);!m_list.end();m_list.next())
{
LinkList<Edge<E>>& edge=m_list.current()->edge;
         for(edge.move(0);!edge.end();edge.next())
{
if(edge.current().e==i)
{
ret++;
break; //不执行当前for循环
}
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index is invalid");
}
return ret;
}
int OD(int i)//o(n)
{
int ret=0;
if((0<=i)&&(i<vCount()))
{
ret=m_list.get(i)->edge.length();
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid..");
}
return ret;
}
~ListGraph()
{
while(m_list.length()>0)
{
Vertex* toDel=m_list.get(0);
m_list.remove(0);
delete toDel->data; //删除附加到顶点的数据元素
delete toDel;    //删除链表里边的顶点对象
}
}
};

#endif

int main()
{
ListGraph<char,int> g;
//g.setVertex(0,'A');
g.addVertex('A');
g.addVertex('B');
g.addVertex('C');
g.addVertex('D');
//g.removeVertex();
for(int i=0;i<g.vCount();i++)
{
cout<<i<<":"<<g.getVertex(i)<<endl;
}
g.setEdge(0,1,5);
g.setEdge(0,3,5);
g.setEdge(1,2,8);
g.setEdge(2,3,2);
g.setEdge(3,1,9);
cout<<"W(0,1):"<<g.getEdge(0,1)<<endl;
cout<<"W(0,3):"<<g.getEdge(0,3)<<endl;
cout<<"W(1,2):"<<g.getEdge(1,2)<<endl;
cout<<"W(2,3):"<<g.getEdge(2,3)<<endl;
cout<<"W(3,1):"<<g.getEdge(3,1)<<endl;
cout<<"ecount;"<<g.eCount()<<endl;
//g.removeEdge(3,1);
//cout<<"W(3,1):"<<g.getEdge(3,1)<<endl;//非法
cout<<"ecount;"<<g.eCount()<<endl;
SharedPointer<Array<int> >aj=g.getAdjacent(0);
for(int i=0;i<aj->length();i++)
{
cout<<(*aj)[i]<<endl;
}
cout<<"ID(1):"<<g.ID(1)<<endl;
cout<<"OD(1):"<<g.OD(1)<<endl;
cout<<"TD(1):"<<g.TD(1)<<endl;
g.removeVertex();
cout<<"ecount;"<<g.eCount()<<endl;
cout<<"W(0,1):"<<g.getEdge(0,1)<<endl;
cout<<"W(1,2):"<<g.getEdge(1,2)<<endl;
//cout<<"W(2,3):"<<g.getEdge(2,3)<<endl;
//cout<<"W(3,1):"<<g.getEdge(3,1)<<endl;
return 0;
}

小结:邻接链表法使用链表对图相关的数据进行存储,每一个顶点关联一个链表,用于存储边相关的数据,所有顶点按编号被组织在同一个链表中,邻接链表法实现的图能够支持动态添加删除顶点。

74、图的遍历(BFS)

时间复杂度对比分析:

                    MatrixGraph        ListGraph

addVertex         -                        o(n)

removeVertex    -                        o(n^2)

getVertex        o(1)                       o(n)

setVertex        o(1)                        o(n)

getAdjacent    o(n)                        o(n)

getEdge          o(1)                        o(n)

setEdge            o(1)                      o(n)

removeEdge    o(1)                        o(n)

vCount            o(1)                        o(1)

eCount            o(1)                        o(n)

ID                    o(n)                        o(n^2)

OD                  o(n)                        o(n)

小结论:MatrixGraph适用于内存资源丰富的场合(性能较好)

ListGraph适用于内存资源受限的场合(节省空间)

图的遍历(BFS):从图中的某一顶点出发,沿着一些边访问图中的其他顶点,使得每个顶点最多被访问一次。

注意:从某个顶点出发进行遍历,不一定能够访问到图中的所有顶点。

图的遍历方式:

广度优先(Breadth First Search):以二叉树层次遍历的思想对图进行遍历。一层一层的圆弧。

深度优先(Depth First Search):以二叉树先序遍历的思想对图进行遍历。

广度优先算法:

原料:class LinkQueue<T>;

步骤:1、将起始顶点压入队列中。2、队头顶点v弹出,判断是否已经标记(标记:转2,未标记:转3)。3、标记顶点v,并将顶点v的邻接顶点压入队列中。4、判断队列是否为空(非空:转2,空:结束)。

template <typename T>
DynamicArray<T>* toArray(LinkQueue<T>& queue)//队列转换为数组
{
DynamicArray<T>* ret=new DynamicArray<T>(queue.length());
if(ret!=NULL)
{
for(int i=0;i<ret->length();i++,queue.remove())
{
ret->set(i,queue.front());
}
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException,"no memory");
}
return ret;

}

SharedPointer<Array<int>>BFS(int i)//广度优先遍历
{
DynamicArray<int>* ret=NULL;
if((0<=i)&&(i<vCount()))
{
LinkQueue<int> q;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for(int j=0;j<visited.length();j++)
{
visited[j]=false;
}
q.add(i); //把初始顶点放入队列中
while(q.length()>0)
{
int v=q.front();
q.remove();
if(!visited[v])
{
SharedPointer<Array<int> >aj=getAdjacent(v);
for(int j=0;j<aj->length();j++)
{
q.add((*aj)[j]);
}
r.add(v);
visited[v]=true;
}
}
ret=toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index i is invalid");
}
return ret;

}

小结:MatrixGraph适用于资源富足的场合,ListGraph适用于资源受限的场合,广度优先按照“层次的方式”对顶点进行访问,广度优先算法的核心是队列的使用。

75、图的遍历(DFS)

深度优先(DFS):算法

原料:class LinkStack<T>//广度是队列

步骤:1、将起始顶点压入栈中。2、弹出栈顶顶点,判断是否已经标记(标记:转2,未标记:转3)。3、标记顶点v,并将顶点v的邻接顶点压入栈中。4、判断栈是否为空(非空:转2,空;结束)。

SharedPointer<Array<int> >DFS(int i)
{
DynamicArray<int>* ret=NULL;
if((0<=i)&&(i<vCount()))
{
LinkStack<int> s;
LinkQueue<int> r;
DynamicArray<bool> visited(vCount());
for(int j=0;j<visited.length();j++)
{
visited[j]=false;
}
s.push(i);
while(s.size()>0)
{
int v=s.top();
s.pop();
if(!visited[v])
{
SharedPointer<Array<int> >aj=getAdjacent(v);
for(int j=aj->length()-1;j>=0;j--)
{
s.push((*aj)[j]);
}
r.add(v);
visited[v]=true;
}
}
ret=toArray(r);
}
else
{
THROW_EXCEPTION(InvalidParameterException,"Index i is invalid ...");
}
return ret;

}

问题:如何使用二叉树先序遍历的思想遍历图?

递归版深度优先:

G=v0+G' //起始顶点v0

DFS(G)=visited(v0)+DFS(G') -->G'不为空,且v0到G'有连结

定义功能:DFS(graph,vex)//graph表示图,vex表示起始顶点

以顶点vex为起始顶点深度优先遍历graph

DFS(graph,vex)=

visit(vex);return;  adjacent(vex)==NULL

visit(vex);aj=getAdjacent(vex);DFS(graph,{aj}); adjacent(vex)!=NULL

#include <iostream>
//递归版深度优先
template <typename V,typename E>
void DFS(Graph<V,E>& g,int v, Array<bool>& visited)
{
if((0<=v)&&(v<g.vCount()))
{
cout<<v<<endl;
visited[v]=true;
SharedPointer<Array<int> >aj=g.getAdjacent(v);
for(int i=0;i<aj->length();i++)
{
if(!visited[(*aj)[i]])
{
DFS(g,(*aj)[i],visited);
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterException,"index v is invalid...");
}
}
template <typename V,typename E>
void DFS(Graph<V,E>& g, int v)
{
DynamicArray<bool> visited(g.vCount());
for(int i=0;i<visited.length();i++)
{
visited[i]=false;
}
DFS(g,v,visited);
}
int main()
{
MatrixGraph<9,char,int> g;
const char* VD="AVEDCGFHI";
for(int i=0;i<9;i++)
{
g.setVertex(i,VD[i]);//设置顶点相关的数据元素值
}
g.setEdge(0,1,0);
g.setEdge(1,0,0);
g.setEdge(0,3,0);
g.setEdge(3,0,0);
g.setEdge(0,4,0);
g.setEdge(4,0,0);
g.setEdge(1,2,0);
g.setEdge(2,1,0);
g.setEdge(1,4,0);
g.setEdge(4,1,0);
g.setEdge(2,5,0);
g.setEdge(5,2,0);
g.setEdge(3,6,0);
g.setEdge(6,3,0);
g.setEdge(4,6,0);
g.setEdge(6,4,0);
g.setEdge(6,7,0);
g.setEdge(7,6,0);
g.setEdge(7,8,0);
g.setEdge(8,7,0);
SharedPointer<Array<int>>sa=g.DFS(0);
for(int i=0;i<sa->length();i++)
{
cout<<(*sa)[i]<<" ";
}
cout<<endl;
DFS(g,0);
return 0;
}

小结:深度优先按照先序遍历的方式对顶点进行访问,深度优先算法的核心是栈的使用,深度优先和广度优先的唯一不同在于栈或队列的使用,深度优先算法可以使用递归的方式实现。

猜你喜欢

转载自blog.csdn.net/ws857707645/article/details/80664271
71
71A