这里
图可以看成有n个结点的树。
DFS,BFS
都是看这个结点的问题
两个指针:左孩子和右孩子
这里用指针数组的形式存
*child[2]
表示有两个指针,每一个指针指向一个结点。
DFS=====前序遍历
这里看邻接表图
DFS(p->dest)
表示到相邻的结点访问,
递归找相邻结点的相邻结点访问。
直到为空
用int v 的原因是找数组下标比较容易,且数组的类型可能改变,顶点的值类型会变,这里提高代码的重用性。
P=p->link 是指向后找结点,找到下一个相邻结点。
先找完一串(从头连到尾,不分支),再找另外的相邻结点
邻接矩阵实现方式
还不完整
#include<iostream>
#include<queue>
using namespace std;
//图的邻接矩阵模式
extern const int maxWeight=9999;
const int maxSize = 100;
//邻接矩阵存储的图的类定义(无向图)
template <class T, class E>
class Graphmtx //图的邻接矩阵类定义
{
public:
Graphmtx(int sz); //构造函数
~Graphmtx() //析构函数
{
delete[]VertexList;
delete[]Edge;
}
T getValue(int i) //取顶点i的值, i不合理返回0
{
return i >= 0 && i < numVertices ? VertexList[i] : 0;
}
void DFS(Graphmtx<T, E> &G, int v);
void BFS(Graphmtx<T, E>& G, int k);
void locata( T& vex1, T& vex2, int& m, int& n);
void getGraphmtx();
private:
int maxVertices; //图中最大顶点数
int numEdges;
int numVertices;
int getVertexPos(T vertex) //找到顶点的位置。可以优化成散列的方式找该顶点,效率更高
{
for (int i = 0; i < numVertices; i++)
{
if (VertexList[i] == vertex) return i;
}
return -1;
}
T* VertexList; //顶点表
E** Edge; //邻接矩阵, 数组的元素值为两个顶点之间的权值。
bool *visited; //遍历标记
};
//构造函数
template <class T, class E>
Graphmtx<T, E>::Graphmtx(int sz)
{
int i = 0, j = 0;
maxVertices = sz;
numVertices = sz; //初始化顶点数为0
numEdges =0;
VertexList = new T[maxVertices]; //顶点只需要一维的矩阵存就可以。
cout << "输入顶点的值: " << endl;
for (i = 0; i <numVertices; i++)
{
cin >> VertexList[i];
}
cout << "输入边的数量" << endl;
cin >> numEdges;
Edge = (int**) new int* [maxVertices]; //创建邻接矩阵数组
visited = new bool[maxVertices];
for (i=0;i< maxVertices;i++)
{
visited[i] = false;
}
for (i = 0; i < maxVertices; i++)
{
Edge[i] = new int[maxVertices];
}
for (i = 0; i < maxVertices; i++)//浪费空间的做法,需要一开始就开很大的空间。
{
for (j = 0; j < maxVertices; j++)
{
Edge[i][j] = (i == j) ? 0 : maxWeight; //除了对角线为0,其余都是无穷大(权值)
}
}
getGraphmtx();
}
//创建图(以邻接矩阵的方式)
//通过结点信息(A,B,C,D之类)来查找对应矩阵下标
/*********************确定边在矩阵的位置*********************/
template <class T, class E>
void Graphmtx<T, E>::locata( T& vex1, T& vex2, int& m, int& n)
{
for (int i = 0; i < maxVertices; i++)
{
if (vex1 == VertexList[i])
m = i;
if (vex2 == VertexList[i])
n = i;
}
}
/*********************创建图对应的邻接矩阵************************/
template <class T, class E>
void Graphmtx<T, E>::getGraphmtx()
{
//根据输入的两个顶点,来更新矩阵的值(如输入A,B表示从A到B有一条边,就更新矩阵相应位置的值为1)
for (int i = 1; i <= numEdges; i++)
{
T vex1, vex2; //接受输入的两个顶点,来表示从vex1到vex2这条边
cout << "请输入边的信息(形如A B,表示从A到B的一条边):";
cin >> vex1 >> vex2;
int m=0, n=0; //m和n是用来接受vex1和vex2所在的下标值,好据此更新矩阵相应位置的值
locata( vex1, vex2, m, n);
Edge[m][n] = 1;
Edge[n][m] = 1;//无向图邻接矩阵对称,少掉这句代码就是有向图的邻接矩阵了
}
}
template <class T, class E>
void Graphmtx<T, E>::DFS(Graphmtx<T, E> &G, int v) //输入图,和当前顶点的位置
{
int j = 0;
G.visited[v] = true;
cout << G.VertexList[v]<<"-> ";
for (j = 0; j < G.numVertices; j++)
if (G.Edge[v][j]==1 && !visited[j])
DFS(G, j);
}
//BFS用队列
//图可以看成n叉树,每一层都可以有n个子结点
//每次调用函数前都要设置visited矩阵为0
template <class T, class E>
void Graphmtx<T, E>::BFS(Graphmtx<T, E>& G, int k) //输入图,和当前顶点的位置
{
int i = 0;
for (i = 0; i < maxVertices; i++)
{
visited[i] = false;
}
queue <int> q;
q.push(k);
G.visited[k]= 1;
i = 0;
while (!q.empty())
{
i = q.front();
q.pop();
cout << G.VertexList[i] << "-> ";
for (int j = 0; j < G.numVertices; j++) {
if (G.Edge[i][j] == 1 && G.visited[j] == 0)//把所有子结点入队(或者理解为把所有相邻结点且未访问过的入队)
{
G.visited[j] = 1;
q.push(j);
}
}
}
}
邻接表的方式
const int DefaultVertices = 30;//默认最大顶点数
//边结点,下一个顶点的位置
template<class T,class E>//T为顶点名字
struct Edge {
int dest; //边的另一个顶点的位置
E cost; //边上的权值
Edge<T, E>* link; //这个点的下一条边
Edge() { dest = -1; cost = 0; link = NULL; }
Edge(int num, E weight) { dest = num; cost = weight; link = NULL; }
};
//顶点
template<class T,class E>//T为数据
struct Vertex {
T data; //顶点名字
Edge<T,E>* adj; //边链表的头指针
Vertex() {};
};
//图
template<class T, class E> //T为顶点名字
class Graph
{
public:
int maxVertices; //图中最大顶点数
int numEdges; //当前边数
int numVertices; //当前顶点数
bool* visited; // 成员属性 辅助数组
Vertex<T,E>* NodeTable; //顶点表(各边链表的头指针)
Graph(int sz);
~Graph();
int getVertexPos(T vetrex) {//给出顶点vetrex在图中的位置,可以改成散列的方式
for (int i = 0; i < numVertices; i++) {
if (NodeTable[i].data == Vertex)return i;
}
return -1;
}
void CreateNodeTable();
void DFS(int v);
void BFS();
};
template<class T, class E>
Graph<T,E>::Graph(int sz ) {//初始化
maxVertices = sz; numVertices = 0; numEdges = 0;
NodeTable = new Vertex<T,E>[maxVertices];//创建顶点表数组
visited = new bool[sz];
int i;
cout << " 请输入结点数 :" << endl;
cin >> numVertices;
if (NodeTable == NULL||visited == NULL)
{
cerr << "存储分配错误!" << endl;
exit(0);
}
for (i = 0; i < maxVertices; i++) {
NodeTable[i].adj = NULL;//边链表头指针赋空
}
for (i = 0; i < numVertices; i++)
{
visited[i] = false;
}
CreateNodeTable();
}
template<class T, class E>
Graph<T, E>::~Graph() {
for (int i = 0; i < numVertices; i++)
{
Edge<T, E>* p = NodeTable[i].adj; //作为工作指针,记头结点
//每一个顶点都要删除后面连的链表
while (p != NULL)
{
NodeTable[i].adj = p->link;
delete p;
p = NodeTable[i].adj;
}
}
delete[] NodeTable;
}
template<class T, class E>
void Graph<T, E>::CreateNodeTable()
{
int n=0, j=0, i=0, m=0;
Edge<T, E>* p;
cout << "输入结点个数: " << endl;
cin >> n;
for (i = 0; i < n; i++)
{
NodeTable[i].adj = 0;
cout << "输入该结点的值" << endl ;
cin >> NodeTable[i].data;
cout << "输入相邻的结点个数 : " << endl;
cin >> m; //建立的链表的长度
for (j = 0; j < m; j++)
{
p = new Edge<T, E>;
cout << "输入连接点的 数组下标的位置: " << endl;
cin >> p->dest; //输入连接点的位置
p->link = NodeTable[i].adj;
NodeTable[i].adj = p;
}
}
}
//遍历
//DFSk=====类似前序遍历,
template<class T, class E>
void Graph<T, E>::DFS(int v) //v表示起点
{
Edge<T, E> *p;
visited[v] = true;
cout << NodeTable[v].data<<" -> ";
p = NodeTable[v].adj;
while (p != 0)
{
if (!visited[p->dest])
DFS(p->dest);
p = p->link;
}
}
//BFS====层次遍历
//不需要初始值
template<class T, class E>
void Graph<T, E>::BFS()
{
int v=0; //根结点的下标
Edge<T, E>* p;
queue<int> qu;//定义一个队列
cout << "输入一个出发点的位置:" << endl;
cin >> v; //
qu.push(v);
visited[v] = true; //这里表示入列
while (!qu.empty())
{
v = qu.front(); //取队头元素
qu.pop(); //弹出队头元素
cout << NodeTable[v].data<<" -> ";
p = NodeTable[v].adj;
//找邻接点
while (p != 0)
{
qu.push(p->dest);
p = p->link;
}
}
}