概念
- 图:由点以及点之间的连接关系所描述的对象
图是由点集和边集组成
图分为有向图和无向图
图(a)就是有向图,图(b)就是无向图
完全图:从图的任意一个顶点可以直接到达其余各个顶点的图
连通图:从图中任意一个顶点可以到达其余各个顶点
图的存储
- 邻接矩阵存储
邻接矩阵是用一个一维数组存储点信息,用二维数组储存连接关系
#define MaxVertaxNum 50 //顶点最大数目
typedef char VertaxType;//顶点信息类型,用字符来表示顶点
typedef bool EdgeType;//不带权值的图,只存储点的连接信息
typedef struct Mgrap1 {
VertaxType Vertax[MaxVertaxNum];
EdgeType Edge[MaxVertaxNum][MaxVertaxNum];
int vexNum, edgeNum;//点的数量、边的数量
}Mgrap1;
- 邻接链表存储
邻接链表是用线性表存储点信息,线性表中每个点信息节点尾头节点用链式存储方式存储与其有连接关系的节点
#define MaxVertaxNum 50 //顶点最大数目
//与顶点连接的信息
typedef struct ArcNode {
int adjVex;
struct ArcNode* next;//指向下一个依附顶点的指针(与表头存储结点相连接的节点)
}ArcNode;
//顶点表节点
typedef struct VNode {
VertaxType vertax;//顶点信息
ArcNode* first;//指向第一个依附的顶点(与vextax相连接的第一个节点)
}VNode , adjList[MaxVertaxNum];
//
typedef struct ALGraph {
adjList vertices;//邻接表
int vex, arc;//定点数、路径数
}ALGraph;
邻接链表存储图的遍历
- 深度优先遍历
void DFirst(Mgraph mg, VertaxType ver, visited& visited, Stack& stack)//深度优先遍历
{
visit(ver);
if (!visited.visited[ver])
{
visited.visited[ver] = true;//顶点访问,修改标记
printf("%d", mg.Vertax[ver]);
}
push(stack, ver);//定点入栈
VertaxType temVer = ver;
while (!stackEmpty(stack))
{
if (vexIsTrue(mg, temVer, visited))//与该顶点相连接的所有顶点都已经访问,顶点出栈
{
pop(stack);
if (!stackEmpty(stack))
{
temVer = getPop(stack);//读取顶点出栈后栈顶元素
}
else temVer = -1;
}//if
else
break;
}
if (temVer != -1)
{
for (int j = VertaxNum - 1; j >= 0; j--)
{
if (mg.Edge[ver][j] != 0 && visited.visited[j] != true)
{
push(stack, mg.Vertax[j]);//将与顶点相连且未被访问的顶点入栈
}
}//for
if (!stackEmpty(stack))
{
temVer = getPop(stack);
DFirst(mg, temVer, visited, stack);
}//if
}//if
}//DFirst
- 广度优先遍历
void WFirst(Mgraph mg, VertaxType ver, visited& visited, Queue& queue)//广度优先遍历
{
visit(ver);
visited.visited[ver] = true;
printf("%d\n", ver);
VertaxType temVer = ver;
if (!vexIsTrue(mg, temVer, visited))//存在与节点连接但未被访问的节点
{
for (int j = VertaxNum - 1; j >= 0; j--)
{
if (mg.Edge[ver][j] != 0 && visited.visited[j] != true)
{
enQueue(queue, mg.Vertax[j]);//将与顶点相连且未被访问的顶点入栈
}
}//for
}
if (!QueueEmpty(queue))
{
deQueue(queue , temVer);
WFirst(mg, temVer, visited, queue);
}
}
- 完整程序
//测试程序
#include <stdio.h>
#include "MGraph.h"
int main()
{
Mgraph mg;
VertaxType ver[4] = { 0 , 1 , 2 , 3};
EdgeType edge[4][4] = { {0 , 1 , 1 , 0} , {1 , 0 , 0 , 1} , {1 , 0 , 0 , 0} , {0 , 1 , 0 , 0} };
initMgraph(mg, ver, edge);
visited visited1;
initVisited(visited1);
Stack stack;
initStack(stack);
DFirst(mg, 0, visited1, stack);
printf("*******************\n");
visited visitedd;
initVisited(visitedd);
Queue queue;
initQueue(queue);
WFirst(mg, 0, visitedd, queue);
return 0;
}
#pragma once
//intQueue.h
//队列
#define max 51
//队列表最大
#define initSize 100
typedef int Elem;
typedef struct
{
Elem elem[initSize];
unsigned int front , rear; //队头、队尾
int flag;//空队列标记 flag = 0为空,flag = 1为满
}Queue;
void initQueue(Queue& que);//队列初始化
bool QueueEmpty(Queue que);//判断是否为空队列
bool QueueFull(Queue que);//判断队列是否已满
bool enQueue(Queue& que, Elem elem);//入队
bool deQueue(Queue& que ,Elem & elem);//出队
Elem getHead(Queue que);//读取对头元素
void initQueue(Queue& que)//队列初始化
{
que.flag = 0;//标记为未满
que.front = que.rear = 0;//对头队尾都指向对头,队列为空
}
bool QueueEmpty(Queue que)//判断是否为空队列
{
if ( que.front == que.rear && que.flag == 0)
return true;
return false;
}
bool QueueFull(Queue que)//判断队列是否已满
{
if (que.flag == 1)
return true;
return false;
}
bool enQueue(Queue& que, Elem elem)//入队
{
if (QueueFull(que))//队列已满
return false;
que.elem[que.front % initSize] = elem;
++que.front;
if (que.front - que.rear == initSize - 1)
que.flag = 1;
else
que.flag = 0;
return true;
}
bool deQueue(Queue& que, Elem& elem)//出队
{
elem = que.elem[que.rear % initSize];
++que.rear;
if (que.front - que.rear == initSize - 1)
que.flag = 1;
else
que.flag = 0;
return true;
}
Elem getHead(Queue que)//读取对头元素
{
Elem elem = que.elem[que.front % initSize];
return elem;
}
#pragma once
//intStack.h
#define initSize 10
typedef struct
{
int number[initSize];
int top; //线性表当前位置
}Stack;
void initStack(Stack& stack);//初始化栈
bool stackEmpty(Stack stack);//判断是否为空栈
bool stackFull(Stack stack);//判断是否为满栈
bool push(Stack& stack, int number);//入栈
bool pop(Stack& stack);//出栈
int getPop(Stack stack);//读取栈顶元素
void initStack(Stack& stack)//初始化栈
{
stack.top = 0;//指向栈的第一个空间,此时栈为空栈
}
bool stackEmpty(Stack stack)//判断是否为空栈
{
if (stack.top == 0)
return true;
else
return false;
}
bool stackFull(Stack stack)//判断是否为满栈
{
if (stack.top >= initSize)
return true;
else
return false;
}
bool push(Stack& stack, int number)//入栈
{
//栈满
if (stackFull(stack))
return false;
int top = stack.top;
stack.number[top] = number;//元素入栈
++stack.top;//栈顶向上移
return true;
}
bool pop(Stack& stack)//出栈
{
if (stackEmpty(stack))
return false;
else
{
--stack.top;//栈顶向下移
}
return true;
}
int getPop(Stack stack)//读取栈顶元素
{
if (!stackEmpty(stack))
{
int i = stack.top - 1;
return stack.number[i];
}
}
//MGraph.h
#pragma once
#include "intStack.h"
#include "intQueue.h"
#include <stdio.h>
#define MaxVertaxNum 50 //顶点最大数目
#define VertaxNum 4 //节点数量
typedef int VertaxType;//顶点信息类型,用字符来表示顶点
typedef bool EdgeType;//不带权值的图,只存储点的连接信息
typedef struct Mgraph {
VertaxType Vertax[MaxVertaxNum];
EdgeType Edge[MaxVertaxNum][MaxVertaxNum];
int vexNum, edgeNum;//点的数量、边的数量
}Mgraph;
typedef struct visited {
bool visited[VertaxNum];//标记顶点是否被访问
}visited;
/* 假设图的顶点分别为 0 , 1 , 2 , 3
邻接矩阵 0 1 0 0
1 0 1 1
0 1 0 0
0 1 0 0
*/
void initMgraph(Mgraph& mg, VertaxType Vertax[VertaxNum], EdgeType Edge[VertaxNum][VertaxNum]);//初始化
void DFirst(Mgraph mg, VertaxType ver, visited& visited, Stack& stack);//深度优先遍历
void WFirst(Mgraph mg, VertaxType ver, visited& visited, Queue& queue);//广度优先遍历
void initVisited(visited& visited);//初始化定点标记数组
void visit(VertaxType ver);//访问节点
bool vexIsTrue(Mgraph mg, VertaxType ver, visited visited);//与ver相连接的节点是否都已访问
void initMgraph(Mgraph& mg, VertaxType Vertax[VertaxNum], EdgeType Edge[VertaxNum][VertaxNum])//初始化
{
int edgeNum = 0;
for (int i = 0; i < VertaxNum; i++)//修改图的顶点信息
mg.Vertax[i] = Vertax[i];
for (int i = 0; i < VertaxNum; i++)//修改图的路径信息
{
for (int j = 0; j < VertaxNum; j++)
{
mg.Edge[i][j] = Edge[i][j];
if (Edge[i][j] != 0)
edgeNum++;
}
}
mg.vexNum = VertaxNum;
mg.edgeNum = edgeNum / 2;
}
//初始化节点标记
void initVisited(visited& visited)
{
for (int i = 0; i < VertaxNum; i++)//初始化节点标记,开始都为false
visited.visited[i] = false;
}
void visit(VertaxType ver)//访问节点
{
}
bool vexIsTrue(Mgraph mg, VertaxType ver, visited visited)//与ver相连接的节点是否都已访问
{
for (int i = 0; i < VertaxNum; i++)
{
if (mg.Edge[ver][i] != 0 && !visited.visited[i])//有相连接但是为访问顶点
{
return false;
}
}
return true;//所有相连节点都访问
}
void DFirst(Mgraph mg, VertaxType ver, visited& visited, Stack& stack)//深度优先遍历
{
visit(ver);
if (!visited.visited[ver])
{
visited.visited[ver] = true;//顶点访问,修改标记
printf("%d\n", mg.Vertax[ver]);
}
push(stack, ver);//定点入栈
VertaxType temVer = ver;
while (!stackEmpty(stack))
{
if (vexIsTrue(mg, temVer, visited))//与该顶点相连接的所有顶点都已经访问,顶点出栈
{
pop(stack);
if (!stackEmpty(stack))
{
temVer = getPop(stack);//读取顶点出栈后栈顶元素
}
else temVer = -1;
}//if
else
break;
}
if (temVer != -1)
{
for (int j = VertaxNum - 1; j >= 0; j--)
{
if (mg.Edge[ver][j] != 0 && visited.visited[j] != true)
{
push(stack, mg.Vertax[j]);//将与顶点相连且未被访问的顶点入栈
}
}//for
if (!stackEmpty(stack))
{
temVer = getPop(stack);
DFirst(mg, temVer, visited, stack);
}//if
}//if
}//DFirst
void WFirst(Mgraph mg, VertaxType ver, visited& visited, Queue& queue)//广度优先遍历
{
visit(ver);
visited.visited[ver] = true;
printf("%d\n", ver);
VertaxType temVer = ver;
if (!vexIsTrue(mg, temVer, visited))//存在与节点连接但未被访问的节点
{
for (int j = VertaxNum - 1; j >= 0; j--)
{
if (mg.Edge[ver][j] != 0 && visited.visited[j] != true)
{
enQueue(queue, mg.Vertax[j]);//将与顶点相连且未被访问的顶点入栈
}
}//for
}
if (!QueueEmpty(queue))
{
deQueue(queue , temVer);
WFirst(mg, temVer, visited, queue);
}
}
``