在面试的过程中,一般不会考到图相关的问题,因为图相关的问题难,而且描述起来很麻烦.
但是也会问道一下常见的问题,比如,最短路径,最小支撑树,拓扑排序都被问到过.
百度百科
wikipedia
int minDistance(vector dist, set sptSet) {
int min_d = INT_MAX, u;
for(int i = 0, i < dist.size(); i ++) {
if(sptSet.find(i) == sptSet.end() && dist[v] < min_d) {
min_d = dist[i], u = i;
}
}
return u;
}
// 使用vector 表示的邻接矩阵, return 起始点到所有点的最小距离
// 没有边的用0填充
vector dijstra(vector> graph, set &sptSet,int src) {
int V = graph.size();
vector dist(V, 0);
for(int i = 0;i < V; i ++) {
if(i != src) dist[i] = INT_MAX;
}
while(sptSet.size() < V-1) {
// pick mininum distance u
int u = minDistance(dist, sptSet);
sptSet.insert(u);
// 使用u更新距离
for(int v = 0; v < V; v ++) {
if(sptSet.find(v)==sptSet.end() && graph[u][v]
&& dist[u] != INT_MAX
&& dist[u]+graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
return dist;
}
百度百科
wikipedia
void floydWarshall(vector > graph, vector> &dist, vector > &path) {
int V = graph.size();
// 参数dist和path需要初始化大小, 确定是否已经初始化
vector > tmp(V, vector(V));
dist = path = tmp;
for(int i = 0; i < V; i ++) {
for(int j = 0; j < V; j ++) {
dist[i][j] = graph[i][j];
path[i][j] = j;
}
}
for(int i = 0; i < V; i++) {
for(int j = 0; j < V; j++) {
for(int k = 0; k < V; k++) {
if(dist[i][j] > dist[i][k] + dist[k][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
pre[i][j] = pre[i][k];
}
}
}
}
}
//打印最短路径 u ---> v
int pfpath(int u, int v, vector > path) {
while(u != v) {
cout << u << " ";
u = path[u][v];
}
cout << u << endl;
}
百度百科
wikipedia
int minDistance(vector dist, set mstSet) {
int min_d = INT_MAX, u;
for(int i = 0, i < dist.size(); i ++) {
if(mstSet.find(i) == mstSet.end() && dist[v] < min_d) {
min_d = dist[i], u = i;
}
}
return u;
}
// 使用vector 表示的邻接矩阵, return 起始点到所有点的最小距离
// 没有边的用0填充
vector dijstra(vector> graph, set &mstSet,int src) {
int V = graph.size();
vector dist(V, 0);
int parent[V]; // 每个顶点的相邻的点
parent[src] = -1;
for(int i = 0;i < V; i ++) {
if(i != src) dist[i] = INT_MAX;
}
while(mstSet.size() < V-1) {
// pick mininum distance u
int u = minDistance(dist, sptSet);
mstSet.insert(u);
// 使用u更新距离
for(int v = 0; v < V; v ++) {
if(mstSet.find(v)==mstSet.end() && graph[u][v]
&& graph[u][v] < dist[v]) {
dist[v] = graph[u][v];
parent[v] = u;
}
}
}
return dist;
}
百度百科
wikipedia
Code 抄写
struct Edge {
int src, dest, weight;
};
struct Graph {
int V, E;
struct Edge* edge;
};
struct Graph* createGraph(int V, int E) {
struct Graph* graph = new Graph;
graph->V = V;
graph->E = E;
graph->edge = new Edge[E];
return graph;
}
struct subset {
int parent;
int rank;
};
int find(struct subset subsets[], int i) {
if (subsets[i].parent != i)
subsets[i].parent = find(subsets, subsets[i].parent);
return subsets[i].parent;
}
void Union(struct subset subsets[], int x, int y) {
int xroot = find(subsets, x);
int yroot = find(subsets, y);
if (subsets[xroot].rank < subsets[yroot].rank)
subsets[xroot].parent = yroot;
else if (subsets[xroot].rank > subsets[yroot].rank)
subsets[yroot].parent = xroot;
else {
subsets[yroot].parent = xroot;
subsets[xroot].rank++;
}
}
int myComp(const void* a, const void* b) {
struct Edge* a1 = (struct Edge*)a;
struct Edge* b1 = (struct Edge*)b;
return a1->weight > b1->weight;
}
void KruskalMST(struct Graph* graph) {
int V = graph->V;
struct Edge result[V];
int e = 0;
int i = 0;
qsort(graph->edge, graph->E, sizeof(graph->edge[0]), myComp);
struct subset *subsets =
(struct subset*) malloc( V * sizeof(struct subset) );
for (int v = 0; v < V; ++v) {
subsets[v].parent = v;
subsets[v].rank = 0;
}
while (e < V - 1) {
struct Edge next_edge = graph->edge[i++];
int x = find(subsets, next_edge.src);
int y = find(subsets, next_edge.dest);
if (x != y) {
result[e++] = next_edge;
Union(subsets, x, y);
}
}
return;
}
定义: 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。
百度百科
wikipedia
class Graph {
int V; // 顶点的个数
list *adj; // 所有顶点的起始指针
};
void topologicalSort(int V, list *adj) {
// 计算所有入度
vector in_degree(V, 0);
for (int u=0; u::iterator itr;
for (itr = adj[u].begin(); itr != adj[u].end(); itr++) {
in_degree[*itr]++;
}
}
// 加入入度为0的点
queue q;
for (int i = 0; i < V; i++) {
if (in_degree[i] == 0) q.push(i);
}
int cnt = 0;
vector top_order;
while (!q.empty()) {
int u = q.front();
q.pop();
top_order.push_back(u);
// 所有连接点, 入度减去1
list::iterator itr;
for (itr = adj[u].begin(); itr != adj[u].end(); itr++) {
if (--in_degree[*itr] == 0) q.push(*itr);
}
cnt++;
}
if (cnt != V) {
cout << "There exists a cycle in the graph\n";
return;
}
for (int i=0; i
题目: 请你判断一个 n 个点,m 条边的有向图是否存在环。参数为两个int数组,start[i]到end[i]有一条有向边.
解析: 这是拓扑排序的一种应用.
bool isCyclicGraph(vector &start, vector &end) {
// 找到最大顶点值,构造图,
int n = 0;
for (int s : start) {
n = max(n, s);
}
for (int e : end) {
n = max(n, e);
}
// 构造图
vector> graph(n + 1);
vector d(n + 1);
int m = start.size();
// 计算所有顶点的入度
for (int i = 0; i < m; i++) {
graph[start[i]].push_back(end[i]);
d[end[i]]++;
}
queue que;
// 将所有入度为0的点,加入队列
for (int i = 1; i <= n; i++) {
if (graph[i].size() && !d[i]) {
que.push(i);
}
}
while (!que.empty()) {
int h = que.front();
que.pop();
// 将多有入度为0的点,对应的顶点 入度减去1
for (int y : graph[h]) {
d[y]--;
if (!d[y]) {
que.push(y);
}
}
}
// 判断是否所有顶点的入度都是0, 如果是,则没有环,否则就有
for (int i = 1; i <= n; i++) {
if (d[i]) {
return true;
}
}
return false;
}