Algorithms and Data Structures (6)

1. Figure

1. Contact table

The representation method is as follows:
insert image description here
Construction of an undirected graph with weights:

#define MaxInt 32767     // 极大值
#define MVNum 100        // 最大定点数
typedef int ArcType;     // 边的权值类型
typedef char VerTexType; // 顶点数据类型

//弧(边)的结点结构
struct ArcNode
{
    
    
    int adjvex;              // 该边指向顶点的下标
    struct ArcNode *nextarc; // 下一条边指针
    ArcType info;            // 边的权值
};

// 顶点的结点结构
typedef struct VNode
{
    
    
    VerTexType data;          // 顶点信息
    struct ArcNode *firstarc; // 指向第一条边关联该点的边
} VNode, AdjList[MVNum];

// 图的结构定义
typedef struct
{
    
    
    AdjList vertices;
    int vexnum, arcnum; // 图的顶点数和边数
} ALGraph;

Create a graph:

// 采用邻接表表示法创建无向网
Status CreateUDG(ALGraph &G)
{
    
    
    cin >> G.vexnum >> G.arcnum; // 输入总顶点数与总边数
    for (int i = 0; i < G.vexnum; ++i)
    {
    
    
        cin >> G.vertices[i].data;
        G.vertices[i].firstarc = NULL;
    }

    for (int k = 0; k < G.arcnum; ++k)
    {
    
    
        char v1, v2;
        cin >> v1 >> v2;
        int i = LocateVex(G, v1);
        int j = LocateVex(G, v2);

        ArcNode *p1 = new ArcNode;
        p1->adjvex = j;
        p1->nextarc = G.vertices[i].firstarc;
        G.vertices[i].firstarc = p1;

        ArcNode *p2 = new ArcNode;
        p2->adjvex = i;
        p2->nextarc = G.vertices[j].firstarc;
        G.vertices[j].firstarc = p2;
    }
    return 0;
}

//顶点在顶点表中的下标
int LocateVex(ALGraph G, VerTexType u)
{
    
    
    int i;
    for (int i = 0; i < G.vexnum; ++i)
       if (u == G.vertices[i].data) return i;
    return -1;
}

2. Adjacency matrix

Expressed as follows:
insert image description here
Construction of directed graph with weights:

#include <bits/stdc++.h>
using namespace std;
#define MaxVertices 100	//假设包含的最大结点数
#define MaxWeight -1	//假设两点不邻接的正无穷值

//定义结点
struct AdjMarix {
    
    
	int Vertices[MaxVertices];	//存储结点信息
	int Edge[MaxVertices][MaxVertices] = {
    
     0 };	//存储每条边的权值
	int numV;	//当前顶点的个数
	int numE;	//当前边的个数
};

void CreatGraph(AdjMarix *G) {
    
    
	int vi, vj, w;
	cout << "请输入顶点数量:" << endl;
	cin >> G->numV;
	cout << "请输入顶点信息:" << endl;
	//输入结点的编号并初始化
	for (int i = 0; i < G->numV; i++) {
    
    
		cin >> vi;
		G->Vertices[i] = vi;
		G->Edge[i][i] = MaxWeight; //初始化过程先默认权值为无穷大
	}
	cout << "请输入边的数量:" << endl;
	cin >> G->numE;
	cout << "请输入边的信息:" << endl;
	for (int i = 0; i < G->numE; i++) {
    
    
		cin >> vi >> vj >> w; //vi、vj为邻接矩阵对应点的坐标,w为边的权值
		G->Edge[vi - 1][vj - 1] = w;
		//G->Edge[vj-1][vi-1]=w; 无向图需要再加上这一句
	}
}

//遍历图,展示邻接表矩阵
void ShowGraph(AdjMarix *G) {
    
    
	for (int i = 0; i < G->numV; i++) {
    
    
		for (int j = 0; j < G->numV; j++) {
    
    
			cout << G->Edge[i][j] << " ";
		}
		cout << endl;
	}
}

int main() {
    
    
	AdjMarix AM;
	CreatGraph(&AM);
	ShowGraph(&AM);
}

The result of the input and output is:
insert image description here

3. Width-first traversal of the graph

1. Use the queue to implement
2. Start from the source node and enter the queue according to the width, and then pop up
3. Every time a point pops up, put all the adjacent points of the node that have not entered the queue into the queue
4 until the queue becomes empty
. Adjacency matrix version:

#include <iostream>
#include <queue>

using namespace std;

#define MaxVertexNum 100 //顶点数目的最大值

// VertexType,顶点的数据类型
template<typename VertexType>
class MGraph {
    
    
private:
    VertexType Vex[MaxVertexNum];   //顶点表
    int Edge[MaxVertexNum][MaxVertexNum];  //邻接矩阵,边表
    int vexnum, arcnum;  //图的当前顶点数和弧数
    bool inq[MaxVertexNum]; //如果顶点i已入过,inq[i]==true。初值为false

    void BFS(int u) {
    
       //遍历u所在的连通块
        queue<int> q;   //定义队列q
        q.push(u);   //初始顶点u入队
        inq[u] = true;  //设置u已入过队
        while (!q.empty()) {
    
        //只要队列非空
            u = q.front();  //取出队首元素并访问
            cout << Vex[u] << "\t";
            q.pop();    //队首元素出队
            for (int v = 0; v < vexnum; v++)
                //如果u的邻接点v未曾加入过队列
                if (Edge[u][v] == 1 && inq[v] == false) {
    
    
                    //将v入队并标记已入队
                    q.push(v);
                    inq[v] = true;
                }
        }
    }

public:
    MGraph() {
    
    
        for (int i = 0; i < MaxVertexNum; i++) {
    
    
            inq[i] = false;
            for (int k = 0; k < MaxVertexNum; k++)
                Edge[i][k] = 0;
        }
    }

    void create() {
    
    
        int row, col;
        cin >> vexnum >> arcnum;    //输入实际图的顶点数和边数
        for (int i = 0; i < vexnum; i++)   //输入顶点信息
            cin >> Vex[i];

        for (int i = 0; i < arcnum; i++) {
    
      //输入边信息
            cin >> row >> col;
            Edge[row][col] = 1;
        }
    }

    void BFSTrave() {
    
      //遍历图G
        for (int u = 0; u < vexnum; u++) //枚举所有顶点
            if (inq[u] == false)
                BFS(u); //遍历u所在的连通块
    }
};

int main() {
    
    
    MGraph<string> G;
    G.create();
    G.BFSTrave();
    return 0;
}

Adjacency table version:

#include <iostream>
#include <queue>

using namespace std;

#define MaxVertexNum 100 //顶点数目的最大值

struct ArcNode {
    
        //边表结点
    int adjvex;     //该弧所指向的顶点的位置
    ArcNode *next;  //指向下一条弧的指针
};

template<typename VertexType>
struct VNode {
    
            //顶点表结点
    VertexType data;  //顶点信息
    ArcNode *first;   //指向第一条依附该顶点的弧的指针
};

template<typename VertexType>
class ALGraph {
    
     //ALGraph是以邻接表存储的图类型
private:
    VNode<VertexType> vertices[MaxVertexNum]; //邻接表
    int vexnum, arcnum; //图的顶点数和弧数
    bool inq[MaxVertexNum]; //如果顶点i已入过,inq[i]==true。初值为false

    void BFS(int u) {
    
       //遍历u所在的连通块
        queue<int> q;   //定义队列q
        q.push(u);   	//初始顶点u入队
        inq[u] = true;  //设置u已入过队
        while (!q.empty()) {
    
    
            u = q.front();  //取出队首元素并访问
            cout << vertices[u].data << "\t";
            q.pop();    //队首元素出队
            ArcNode *p = vertices[u].first;
            while (p) {
    
    
                if (inq[p->adjvex] == false) {
    
    
                    q.push(p->adjvex);
                    inq[p->adjvex] = true;
                }
                p = p->next;
            }
        }
    }

public:
    ALGraph() {
    
    
        for (int i = 0; i < MaxVertexNum; i++) {
    
    
            inq[i] = false;
            vertices[i].first = NULL;
        }
    }

    void create() {
    
    
        int row, col;
        cin >> vexnum >> arcnum;    //输入实际图的顶点数和边数
        for (int i = 0; i < vexnum; i++)   //输入顶点信息
            cin >> vertices[i].data;

        for (int i = 0; i < arcnum; i++) {
    
      //输入边信息
            cin >> row >> col;
            ArcNode *p = new ArcNode;
            p->adjvex = col;
            p->next = vertices[row].first;
            vertices[row].first = p;
        }
    }

    void BFSTrave() {
    
      //遍历图G
        for (int u = 0; u < vexnum; u++) //枚举所有顶点
            if (inq[u] == false)
                BFS(u); //遍历u所在的连通块
    }
};

int main() {
    
    
    ALGraph<string> G;
    G.create();
    G.BFSTrave();
    return 0;
}

Fourth, breadth-first traversal

Depth-first search uses "depth" as the first keyword, and returns to the nearest fork every time it cannot move forward along the path. Take a directed graph (see the figure below) for DFS traversal as an example (traversing from V0, black indicates that the node has not been visited, white indicates that the node has been visited, and the dotted line indicates the current traversal path):
insert image description here

If you want to traverse the entire graph, you need to traverse all connected blocks (connected components and strongly connected components) separately. Therefore, the basic idea of ​​DFS traversing the graph is to set the passed vertex as visited, and not to process it the next time the vertex is encountered recursively, until the vertices of the entire graph are marked as visited.

#include <iostream>

using namespace std;

#define MaxVertexNum 100 //顶点数目的最大值

struct ArcNode {
    
        //边表结点
    int adjvex;     //该弧所指向的顶点的位置
    ArcNode *next;  //指向下一条弧的指针
};

template<typename VertexType>
struct VNode {
    
            //顶点表结点
    VertexType data;  //顶点信息
    ArcNode *first;   //指向第一条依附该顶点的弧的指针
};

template<typename VertexType>
class ALGraph {
    
     //ALGraph是以邻接表存储的图类型
private:
    VNode<VertexType> vertices[MaxVertexNum]; //邻接表
    int vexnum, arcnum; //图的顶点数和弧数
    bool visited[MaxVertexNum]; //如果顶点i已被访问,则visited[i]==true。初值为false

    void DFS(int u) {
    
       //u为当前访问的顶点索引
        cout << vertices[u].data << "\t";
        visited[u] = true;   //设置u已被访问
        ArcNode *p = vertices[u].first;

        while (p) {
    
    
            if (visited[p->adjvex] == false)
                DFS(p->adjvex);
            p = p->next;
        }
    }

public:
    ALGraph() {
    
    
        for (int i = 0; i < MaxVertexNum; i++) {
    
    
            visited[i] = false;
            vertices[i].first = NULL;
        }
    }

    void create() {
    
    
        int row, col;
        cin >> vexnum >> arcnum;    //输入实际图的顶点数和边数
        for (int i = 0; i < vexnum; i++)   //输入顶点信息
            cin >> vertices[i].data;

        for (int i = 0; i < arcnum; i++) {
    
      //输入边信息
            cin >> row >> col;
            ArcNode *p = new ArcNode;
            p->adjvex = col;
            p->next = vertices[row].first;
            vertices[row].first = p;
        }
    }

    void DFSTrave() {
    
      //遍历图G
        for (int u = 0; u < vexnum; u++)  //对每个顶点u
            if (visited[u] == false)  //如果u未被访问
                DFS(u); //访问u和u所在的连通块
    }
};

int main() {
    
    
    ALGraph<string> G;
    G.create();
    G.DFSTrave();
    return 0;
}

Adjacency matrix version:

#include <iostream>

using namespace std;

#define MaxVertexNum 100 //顶点数目的最大值

// VertexType,顶点的数据类型
template<typename VertexType>
class MGraph {
    
    
private:
    VertexType Vex[MaxVertexNum];   //顶点表
    int Edge[MaxVertexNum][MaxVertexNum];  //邻接矩阵,边表
    int vexnum, arcnum;  //图的当前顶点数和弧数
    bool visited[MaxVertexNum]; //如果顶点i已被访问,则visited[i]==true。初值为false

    void DFS(int u) {
    
       //u为当前访问的顶点索引
        cout << Vex[u] << "\t";
        visited[u] = true;   //设置u已被访问
        for (int i = 0; i < vexnum; i++)
            if (Edge[u][i] == 1 && visited[i] == false)
                DFS(i);
    }

public:
    MGraph() {
    
    
        for (int i = 0; i < MaxVertexNum; i++) {
    
    
            visited[i] = false;
            for (int k = 0; k < MaxVertexNum; k++)
                Edge[i][k] = 0;
        }
    }

    void create() {
    
    
        int row, col;
        cin >> vexnum >> arcnum;    //输入实际图的顶点数和边数
        for (int i = 0; i < vexnum; i++)   //输入顶点信息
            cin >> Vex[i];

        for (int i = 0; i < arcnum; i++) {
    
      //输入边信息
            cin >> row >> col;
            Edge[row][col] = 1;
        }
    }

    void DFSTrave() {
    
      //遍历图G
        for (int u = 0; u < vexnum; u++)  //对每个顶点u
            if (visited[u] == false)  //如果u未被访问
                DFS(u); //访问u和u所在的连通块
    }
};

int main() {
    
    
    MGraph<string> G;
    G.create();
    G.DFSTrave();
    return 0;
}

2. Topological sorting

Topological sorting is the process of constructing a topological sequence for a directed acyclic graph:
1. Select a vertex without a predecessor in the directed graph and output it.
2. Delete the vertex and all arcs ending with it from the graph.
code show as below:

#include <bits/stdc++.h>
using namespace std;
#define MAXVERTIES 20
#define OK 1
#define ERROR 0

int indegree[MAXVERTIES] = {
    
     0 };	//用于存储入度信息

/*
5
1 2 3 4 5
6
1 2
1 4
1 3
2 4
3 5
4 5
*/

//定义结点
struct VexNode {
    
    
	int data;
	VexNode *next;
};

//定义弧
struct ArcNode {
    
    
	int data;
	VexNode *firstacr = NULL;
};

//定义邻接表
struct GraphList {
    
    
	ArcNode arclist[MAXVERTIES];
	int vexnum, arcnum;
};

//定义栈
struct Stack {
    
    
	int Sacklist[MAXVERTIES] = {
    
     0 };
	int top = -1;
};

//入栈操作
void Push(Stack &S, int key) {
    
    
	if (S.top == MAXVERTIES) {
    
    
		cout << "栈已满!" << endl;
		return;
	}
	S.top++;
	S.Sacklist[S.top] = key;
}

//出栈操作
int Pop(Stack &S) {
    
    
	if (S.top == -1) {
    
    
		cout << "栈为空!" << endl;
		return -1;
	}
	int temp = S.Sacklist[S.top];
	S.top--;
	return temp;
}

//返回结点在结点数组中的下标
int Location(GraphList &G, int key) {
    
    
	for (int i = 0; i < G.vexnum; i++) {
    
    
		if (G.arclist[i].data == key) {
    
    
			return i;
		}
	}
	return -1;
}

//创建图
void CreatGraph(GraphList &G) {
    
    
	cout << "请输入顶点数:" << endl;
	cin >> G.vexnum;
	cout << "请输入顶点信息:" << endl;
	for (int i = 0; i < G.vexnum; i++) {
    
    
		cin >> G.arclist[i].data;
	}
	cout << "请输入弧数:" << endl;
	cin >> G.arcnum;
	cout << "请输入弧端点信息:" << endl;
	for (int i = 0; i < G.arcnum; i++) {
    
    
		int v1, v2;
		cin >> v1 >> v2;
		int Location1 = Location(G, v1);
		int Location2 = Location(G, v2);
		VexNode *new_node = new VexNode;
		new_node->data = Location2;
		new_node->next = G.arclist[Location1].firstacr;
		G.arclist[Location1].firstacr = new_node;
		indegree[Location2]++;
	}
}

//拓扑排序
int TopoSort(GraphList &G, int *topolist) {
    
    
	Stack S;
	int topo = 0;
	//先将所有入度为0的结点入栈
	for (int i = 0; i < G.vexnum; i++) {
    
    
		if (indegree[i] == 0) {
    
    
			Push(S, i);
		}
	}
	//依次出栈入度为0的结点
	while (S.top != -1) {
    
    
		int vx = Pop(S);
		topolist[topo++] = G.arclist[vx].data;	//输出结点
		VexNode *temp = G.arclist[vx].firstacr;
		//删除以该结点为尾的弧
		while (temp != NULL) {
    
    
			int index = temp->data;
			indegree[index]--;	//将该弧的弧头结点入度减1
			//如果入度为0,则入栈
			if (indegree[index] == 0) {
    
    
				Push(S, index);
			}
			temp = temp->next;
		}
	}
	topolist[topo] = -1;
	//如果拓扑序列中的元素个数等于所有元素个数,则该图无环,否则该图有环
	if (topo == G.vexnum) {
    
    
		return OK;
	} else {
    
    
		return ERROR;
	}
}

int main() {
    
    
	GraphList GL;
	CreatGraph(GL);
	int topolist[MAXVERTIES] = {
    
     0 };
	int vx = TopoSort(GL, topolist);
	if (!vx) {
    
    
		cout << "有环!" << endl;
	} else {
    
    
		cout << "有向无环!" << endl;
		cout << "拓扑序列如下:" << endl;
		for (int i = 0; topolist[i] != -1; i++) {
    
    
			cout << topolist[i] << " ";
		}
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/qq_52302919/article/details/131494237