图:
1 数据:顶点
2 关系:边
3 根据边是否有方向:有向图,无向图
4 图的描述:
邻接矩阵:一个一维数组保存顶点,二维数组保存边
邻接表:一个一维数组保存顶点(链表头结点),链表保存顶点能到达的边
5 网图:
边不仅仅描述顶点之间的关联,还表达(代价,权重)等;
1 源文件
//邻接矩阵描述图
#include<stdio.h>
#include<iostream>
#include<queue>
using namespace std;
#define Vertexs 6
#define Edges 7
struct Graph
{
int vertexs;//顶点个数
int edges;//边数
char* pVertex;//指向保存所有顶点的一维数组的指针
int** pEdge;//指向保存所有边的二维数组的指针
};
//创建图对象
struct Graph* createGraph();
//初始化图对象
void initGraph(struct Graph* g, int vertexs, int edges,
char* v, int map[Vertexs][Vertexs]);
//显示
void show(struct Graph* g);
//获取下标
int getIdx(char* v, int vertexs, char c);
//遍历
void travel(struct Graph* g, char beg);
//深度优先遍历
void DFS(struct Graph* g, char beg, bool isFind[Vertexs]);
//广度优先遍历
void BFS(struct Graph* g, char beg, bool isFind[Vertexs]);
//找途中某个地点的第一个相邻顶点,找到返回下标,没找到返回-1
int findFirstVertex(struct Graph*g,int beg, bool isFind[Vertexs]);
//找途中某个地点的下一个相邻顶点,找到返回下标,没找到返回-1
int findNextVertex(struct Graph* g, int beg, bool isFind[Vertexs]);
int main()
{
char buff[7] = "ABCDEF";
int map[Vertexs][Vertexs] =
{
{0,1,1,0,0,0},
{1,0,0,1,0,0},
{1,0,0,1,1,1},
{0,1,1,0,0,0},
{0,0,1,0,0,1},
{0,0,1,0,1,0}
};
struct Graph* g = createGraph();
initGraph(g, 6, 7, buff, map);
show(g);
travel(g, 'A');
return 0;
}
Graph* createGraph()
{
struct Graph* g = new Graph;
if (nullptr == g)
{
return nullptr;
}
memset(g, 0, sizeof(Graph));
return g;
}
void initGraph(Graph* g, int vertexs, int edges, char* v, int map[Vertexs][Vertexs])
{
//顶点个数,边数赋值
g->vertexs = vertexs;
g->edges = edges;
//开内存
g->pVertex = new char[g->vertexs];
memcpy(g->pVertex, v, sizeof(char) * g->vertexs);
//开内存保存指针变量
g->pEdge = new int* [g->vertexs];
//给每个指针变量开内存
for (int i = 0; i < g->vertexs; i++)
{
g->pEdge[i] = new int[g->vertexs];
memcpy(g->pEdge[i], map[i], sizeof(int) * g->vertexs);
}
}
void show(struct Graph* g)
{
for (int i = 0; i <= g->vertexs; i++)
{
for (int j = 0; j <= g->vertexs; j++)
{
if (0 == i && 0 == j)//左上角
{
printf(" ");
}
else if (0 == i)//最上面一行
{
printf("%c ", g->pVertex[j-1]);
}
else if (0 == j)//最左边一列
{
printf("%c ", g->pVertex[i-1]);
}
else//边
{
printf("%d ", g->pEdge[i - 1][j - 1]);
}
}
printf("\n");
}
}
int getIdx(char* v, int vertexs, char c)
{
for (int i = 0; i < vertexs; i++)
{
if (v[i] == c)
{
return i;
}
}
return -1;
}
void travel(struct Graph* g, char beg)
{
bool* isFind = new bool[g->vertexs];
memset(isFind, 0, sizeof(bool) * g->vertexs);
printf("BFS:%c ",beg);
DFS(g, beg, isFind);
memset(isFind, 0, sizeof(bool) * g->vertexs);
printf("\nDFS:%c ", beg);
BFS(g, beg, isFind);
delete[] isFind;
}
void DFS(Graph* g, char beg, bool isFind[Vertexs])
{
int curIdx = getIdx(g->pVertex, g->vertexs, beg);
isFind[curIdx] = true;
int nextIdx = findFirstVertex(g, curIdx, isFind);
while (1)
{
if (-1 == nextIdx)
break;
if (!isFind[nextIdx])
{
printf("%c ", g->pVertex[nextIdx]);
DFS(g, g->pVertex[nextIdx], isFind);
}
nextIdx=findNextVertex(g, curIdx, isFind);
}
}
void BFS(Graph* g, char beg, bool isFind[Vertexs])
{
queue<int> q;//队列
//把第一个放到队列中
q.push(getIdx(g->pVertex, g->vertexs, beg));
isFind[getIdx(g->pVertex, g->vertexs, beg)] = true;
int headIdx;
int idx;
while (!q.empty())
{
headIdx = q.front();
//删掉队列头
q.pop();
idx = findFirstVertex(g, headIdx, isFind);
//循环找当前队列头的声音相邻顶点并放到队列中,放完了就结束
while (1)
{
if (idx == -1)break;
if (!isFind[idx])
{
isFind[idx] = true;
printf("%c ", g->pVertex[idx]);
q.push(idx);
}
idx = findNextVertex(g, headIdx, isFind);
}
}
}
int findFirstVertex(Graph* g, int beg, bool isFind[Vertexs])
{
for (int i = 0; i < g->vertexs; i++)
{
if (isFind[i])
continue;
if (1 == g->pEdge[beg][i])
return i;
}
return -1;
}
int findNextVertex(Graph* g, int beg, bool isFind[Vertexs])
{
for (int i = beg+1; i < g->vertexs; i++)
{
if (isFind[i])
continue;
if (1 == g->pEdge[beg][i])
return i;
}
return -1;
}
2,两种遍历思想
深度优先遍历:Deep First Search DFS
思想:
找第一个,
循环找下一个一直到找不到下一个,
循环结束.
广度优先遍历:Breadth First Search BFS
思想:
先把起点放到队列中,
循环找起点的所有相邻顶点都放到队列中,
所有相邻顶点都放完了,
就删掉队列头,
然后循环找当前队列头的所有相邻顶点,
并放到队列中去;