图的概念 |
|
有向边
有向图
无向边
无向图
点的次数: 点连接的边的数量
闭路: 起点和重点一样
连接图: 任意两点之间都可到达
无闭路有向图: 没有闭路的有向图
森林: 互素的树的集合
生成树: 含有图里所有点的树
生成树林: 所有生成树的并集
|
|
|
|
|
图论算法的应用 |
|
● 电路的元件关系
● 交通网
● 电脑网络(本地网络, 互联网, web等)
● 数据库(实体关系图(ER图))
|
|
|
图的数据结构 |
邻接矩阵 |
适用于数据多的
//------------------------------------------------
// 邻接矩阵
//------------------------------------------------
struct Graph {
int v;
int e;
int **adj;
};
// 创建图
struct Graph *adjMatrixOfGraph() {
int i, u, v;
struct Graph *G = (struct Graph *)malloc(sizeof(struct Graph));
if (G == NULL) {
printf("memory error\n");
return NULL;
}
printf("Number of Verticees: ");
scanf("%d", &G->v);
printf("Number of Edges: ");
scanf("%d", &G->e);
G->adj = (int **)malloc(sizeof(int *) * G->v);
if (G->adj == NULL) {
printf("Memory Error\n");
return NULL;
}
for (i = ; i < G->v; i++) {
G->adj[i] = (int *)malloc(sizeof(int) * G->v);
if (G->adj[i] == NULL) {
printf("Memory Error\n");
return NULL;
}
}
printf("v: %d, e: %d\n", G->v, G->e);
for (u=; u<G->v; u++) { // 初始化点
for (v=; v<G->v; v++) {
if (u==v) {
G->adj[u][v] = ;
} else {
G->adj[u][v] = ; // 以0初始化矩阵
}
}
}
for (i=; i<G->e; i++) { // 初始化边
printf("Reading Edge: ");
scanf("%d %d", &u, &v);
G->adj[u][v] = G->adj[v][u] = ;
}
return G;
}
|
邻接链表 |
适用于数据小的
//------------------------------------------------
// 邻接链表
//------------------------------------------------
struct S9ListNode {
int vertexNumber;
struct S9ListNode *next;
};
struct ListGraph {
int v;
int e;
struct S9ListNode *adj;
};
struct ListGraph *adjListOfGraph() { // 无向图
int i, x, y;
struct S9ListNode *temp;
struct ListGraph *G = (struct ListGraph *)malloc(sizeof(struct ListGraph));
if (G == NULL) {
printf("Memory Error\n");
return NULL;
}
printf("Number of Vertices: ");
scanf("%d", &G->v);
printf("Number of Edges: ");
scanf("%d", &G->e);
G->adj = (struct S9ListNode *)malloc(sizeof(struct S9ListNode)*G->v);
if (G->adj == NULL) {
printf("Memory Error\n");
return NULL;
}
for (i=; i<G->v; i++) { // 先初始化所有链表
G->adj[i] = *(struct S9ListNode *)malloc(sizeof(struct S9ListNode));
G->adj[i].vertexNumber = i;
G->adj[i].next = &G->adj[i];
}
for (i=; i<G->e; i++) {
printf("Reading Edge: ");
scanf("%d %d", &x, &y);
struct S9ListNode *node;
temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode));
// 把y添加到x的链表上
temp->vertexNumber = y;
temp->next = &G->adj[x];
node = &G->adj[x];
while (node != NULL && node->next != &G->adj[x]) {
node = node->next;
}
node->next = temp;
// 把x添加到y的链表山
temp = (struct S9ListNode *)malloc(sizeof(struct S9ListNode));
temp->vertexNumber = x;
temp->next = &G->adj[y];
node = &G->adj[y];
while (node != NULL && node->next != &G->adj[y]) {
node = node->next;
}
node->next = temp;
}
return G;
}
|
|
|
图的遍历 |
DFS
深度优先搜索
|
Depth First Search
//------------------------------------------------
// 深度优先搜索 DFS
//------------------------------------------------
int visited[]; // 实际只需要点的数量的长度
// 状态: 1: 已访问 0: 未访问
// 邻接矩阵的DFS
void depthFirstSearch(struct Graph *g, int u) {
int v;
visited[u] = ;
printf("%d visited\n", u); // 访问中的处理
for (v = ; v <g->v; v++) {
// 对点u连接的未访问的节点进行访问
if (visited[v] == && g->adj[u][v] != ) { // 节点并未访问且u和v连接
depthFirstSearch(g, v); // 从v出发
}
}
}
void depthFirstSearchTraversal(struct Graph *g) {
int i;
for (i = ; i < g->v; i++) { // 初始化访问表
visited[i] = ;
}
// 有不通的子连接图时需要
for (i = ; i < g->v; i++) {
if (visited[i] == ) {
depthFirstSearch(g, i); // 一次呼出直接遍历完i可到的所有点
}
}
}
// 邻接链表的DFS
void depthFirstSearch_List(struct ListGraph *g, int u) {
struct S9ListNode *temp = g->adj[u].next;
visited[u] = ;
printf("%d visited\n", u); // 访问中的处理
while (temp != &g->adj[u]) {
if (visited[temp->vertexNumber] == ) {
depthFirstSearch_List(g, temp->vertexNumber);
}
temp = temp->next;
}
}
void depthFirstSearchTraversal_List(struct ListGraph *g) {
int i;
for (i = ; i < g->v; i++) { // 初始化访问表
visited[i] = ;
}
// 有不通的子连接图时需要
for (i = ; i < g->v; i++) {
if (visited[i] == ) {
depthFirstSearch_List(g, i); // 一次呼出直接遍历完i可到的所有点
}
}
}
|
BFS
宽度优先搜索
|
Breadth First Search
//------------------------------------------------
// 宽度优先搜索 BFS
//------------------------------------------------
struct S9QueueNode {
int data;
struct S9QueueNode *next;
};
struct S9Queue {
struct S9QueueNode *front;
};
struct S9Queue *S9CreateQueue() {
struct S9Queue *q = (struct S9Queue *)malloc(sizeof(struct S9Queue));
if (q == NULL) {
return NULL;
}
q->front = NULL;
return q;
}
int S9DeQueue(struct S9Queue *queue) {
if (queue==NULL) {
return -;
}
if (queue->front == NULL) {
return -;
}
struct S9QueueNode *temp = queue->front;
if (queue->front == NULL) {
return -;
}
int data = temp->data;
queue->front = queue->front->next;
free(temp);
return data;
}
void S9EnQueue(struct S9Queue *queue, int data) {
if (queue == NULL) {
queue = (struct S9Queue *)malloc(sizeof(struct S9Queue));
}
struct S9QueueNode *newNode = (struct S9QueueNode *)malloc(sizeof(struct S9QueueNode));
struct S9QueueNode *temp = queue->front;
newNode->next = NULL;
newNode->data = data;
if (temp == NULL) {
queue->front = newNode;
} else {
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
void S9FreeQueue(struct S9Queue *q) {
if (q == NULL) {
return;
}
if (q->front != NULL) {
struct S9QueueNode *temp = q->front, *temp2;
while (temp != NULL) {
temp2 = temp;
temp = temp->next;
free(temp2);
}
}
free(q);
}
int S9IsEmptyQueue(struct S9Queue *queue) { // true: 1, false: 0
if (queue == NULL) {
return ;
}
int result = queue->front == NULL ? : ;
return result;
}
void S9ShowQueue(struct S9Queue *q) {
if (q == NULL) {
printf("queue is null\n");
return;
}
if (q->front == NULL) {
printf("queue has no data\n");
return;
}
struct S9QueueNode *temp = q->front;
int count = ;
while (temp) {
printf("[%d]: %d ", count, temp->data);
temp = temp->next;
count++;
}
puts("");
}
int visited_bfs[];
void breadthFirstSearch(struct Graph *g, int u) { // 矩阵
int count = , i;
struct S9Queue *queue = S9CreateQueue();
S9EnQueue(queue, u);
while (!S9IsEmptyQueue(queue)) {
int u = S9DeQueue(queue);
printf("顶点[%d]: %d\n", count, u);
count++;
visited_bfs[u] = ;
for (i=; i<g->v; i++) {
if (g->adj[u][i] == && visited_bfs[i] == ) {
S9EnQueue(queue, i);
}
}
}
S9FreeQueue(queue);
}
void breadthFirstSearchTravsal(struct Graph *g) {
for (int i=; i<; i++) {
visited_bfs[i] = ;
}
for (int i = ; i<g->v; i++) {
if (visited_bfs[i] == ) {
breadthFirstSearch(g, i);
}
}
}
|
|
|
最短路径算法 |
种类 |
● 不带加权的图
● 带加权的图
● 有负加权的图
|
应用 |
● 两地间最近的路
● 从A到B发送数据最便宜的方法
|
不加权的图最短路径 |
//------------------------------------------------
// 不带加权的图
//------------------------------------------------
int distant[];
int path[];
void unweightedShortestPath(struct Graph *g, int s) { // 邻接矩阵版
struct S9Queue *queue = S9CreateQueue();
int v, w;
S9EnQueue(queue, s);
for (int i = ; i<g->v; i++) {
distant[i] = -;
path[i] = -; // 起点为-1
}
distant[s] = ;
while(!S9IsEmptyQueue(queue)) {
v = S9DeQueue(queue);
for (w = ; w<g->v; w++) {
if (g->adj[v][w] != && distant[w] == -) {
S9EnQueue(queue, w);
distant[w] = distant[v] + ;
path[w] = v;
}
}
}
S9FreeQueue(queue);
}
|
迪杰斯特拉算法
加权图最短路径算法
|
//------------------------------------------------
// 不带负加权的图 迪杰斯特拉算法
//------------------------------------------------
void dijkstra(struct Graph *g, int s) {
struct S9Queue *queue = S9CreateQueue(); // 优先队列
int v, w;
S9EnQueue(queue, s);
for (int i = ; i<g->v; i++) {
distant[i] = -; // -1 表示还没处理
}
distant[s] = ; // 自己到自己的距离为0
while (!S9IsEmptyQueue(queue)) {
// v = S9DeQueue(queue); // TODO-PRO: fix here [这里要改成以距离为排序的DeleteMin]
v = S9DeleteMin(queue);
for (w = ; w<g->v; w++) {
if (g->adj[v][w] != ) { // v -> w 直接相同
int newDistant = distant[v] + g->adj[v][w]; // 新距离
printf("distant[v]: %d\n", distant[v]);
if (distant[w] == -) {
distant[w] = newDistant;
S9EnQueue(queue, w);
path[w] = v;
} else if (newDistant < distant[w]) {
distant[w] = newDistant;
path[w] = v;
// 更新w
S9EnQueue(queue, w);
}
}
}
}
}
|
贝尔曼-福特算法 |
可以有负加权边 |
|
|