遍历的定义:
从已给的联通图中某顶点出发,沿着一些边访遍图中的所有顶点,并且每个顶点仅仅被访问一次,叫做图的遍历,是图的基本运算。
图的特点:
图中可能存在回路,且图的任一顶点都有可能与其他顶点联通,在访问完某点之后可能会沿边回到曾经访问过的节点。
避免重复访问的思路:
设置辅助数组visited【n】,用来标记已经访问过的节点
*默认visited状态为0
*顶点被访问后置为1,避免重复访问
深度优先搜索(DFS):
从某个起始节点开始遍历,首先访问该节点,并标记该节点已被访问。接着找到与该节点相邻的未被访问的节点中的一个,继续以该节点为起始节点进行深度优先搜索。
联通图的深度优先遍历类似于树的先根遍历。
设置对应顶点的数组值初始化为0
int visited[顶点个数];
//图G为领接矩阵类型
void DFS(Graph G , int v)
{
visited[v]=true;
for(int i=0;i<G.vexnum;i++)
{
if(G.bian[v][i] != 0 && ( !visited[i]) )
//检查到相领节点且未访问过就递归执行搜查
DFS(G,i);
}
}
BFS(Breadth-First Search)又称广度优先搜索,是一种基于图的遍历算法,它从指定的起始节点开始遍历图,依次访问其相邻的节点,直到遍历完整个图为止。
使用邻接表表示图的优点包括:
- 空间复杂度低:对于稀疏图,邻接表中只存储非零元素,空间复杂度较低;
- 可快速获取节点的邻居节点:由于邻居节点存储在同一链表中,因此可以快速获取某个节点的邻居节点;
- 遍历效率高:对于从某个节点出发的遍历操作,由于只需要访问该节点的邻居节点,因此遍历的效率较高。
邻接表也有一些缺点,例如:
- 无法快速判断两个节点之间是否存在边;
- 在查找两个节点之间的边时,需要遍历链表,时间复杂度较高;
- 对于稠密图,邻接表的空间复杂度可能不如邻接矩阵。
和树的层次遍历类似。
//树的层次遍历
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100 // 队列的最大容量
/* 树结构体定义 */
typedef struct TreeNode
{
int data;
struct TreeNode *left_child; // 指向左子树根节点的指针
struct TreeNode *right_child; // 指向右子树根节点的指针
} TreeNode;
/* 队列结构体定义 */
typedef struct
{
TreeNode *data[MAX_SIZE]; // 存储节点指针的数组
int front; // 队首指针
int rear; // 队尾指针
} Queue;
/* 初始化队列 */
void init_queue(Queue *queue)
{
queue->front = 0;
queue->rear = 0;
}
/* 判断队列是否为空 */
int is_empty(Queue *queue)
{
return queue->front == queue->rear;
}
/* 入队 */
void enqueue(Queue *queue, TreeNode *node)
{
queue->data[queue->rear++] = node;
}
/* 出队 */
TreeNode *dequeue(Queue *queue)
{
return queue->data[queue->front++];
}
/* 层次遍历 */
void level_order_traversal(TreeNode *root)
{
if (root == NULL) { // 空树,直接返回
return;
}
Queue queue;
init_queue(&queue); // 初始化队列
enqueue(&queue, root); // 将根节点入队
while (!is_empty(&queue)) {
TreeNode *node = dequeue(&queue); // 取出队首节点
printf("%d ", node->data); // 访问该节点
if (node->left_child != NULL) { // 将左子树的根节点入队
enqueue(&queue, node->left_child);
}
if (node->right_child != NULL) { // 将右子树的根节点入队
enqueue(&queue, node->right_child);
}
}
}
/* 创建新节点 */
TreeNode *new_node(int data) {
TreeNode *node = (TreeNode *) malloc(sizeof(TreeNode));
node->data = data;
node->left_child = NULL;
node->right_child = NULL;
return node;
}
//邻接表的层序遍历
#include <stdio.h>
#include <stdlib.h>
/* 边结构体定义 */
typedef struct EdgeNode
{
int adjvex; // 相邻顶点在数组中的下标
struct EdgeNode *next_edge; // 指向下一条边的指针
} EdgeNode;
/* 顶点结构体定义 */
typedef struct VertexNode
{
int data; // 顶点存储的数据
EdgeNode *first_edge; // 指向第一条边的指针
} VertexNode;
/* 图结构体定义 */
typedef struct
{
VertexNode vertices[100]; // 存储顶点的数组
int vertex_count; // 顶点数
int edge_count; // 边数
} Graph;
/* 添加边 */
void add_edge(Graph *graph, int from, int to)
{
EdgeNode *edge = (EdgeNode *) malloc(sizeof(EdgeNode));
edge->adjvex = to;
edge->next_edge = graph->vertices[from].first_edge;
graph->vertices[from].first_edge = edge; // 将该边插入到头部
}
/* 创建图 */
Graph *create_graph(int vertex_count, int edge_count)
{
Graph *graph = (Graph *) malloc(sizeof(Graph));
graph->vertex_count = vertex_count;
graph->edge_count = edge_count;
for (int i = 0; i < vertex_count; i++)
{
graph->vertices[i].data = i; // 顶点的数据初始化为下标值
graph->vertices[i].first_edge = NULL;
}
int from, to;
for (int i = 0; i < edge_count; i++)
{
scanf("%d %d", &from, &to);
add_edge(graph, from, to); // 添加边
}
return graph;
}