图的表达方式
邻接表:
邻接矩阵:
数组:
二维数组:
自己的图表示方式:
class Edge;
class Node{
public:
int val;
int in; //入度
int out; // 出度
vector<Node*> nexts; // 指向的节点
vector<Edge*> edges; // 出边
Node(int val) : val(val) {}
};
class Edge{
public:
int weight;
Node *from;
Node *to;
Edge(int weight, Node *from, Node *to){
this -> weight = weight;
this -> from = from;
this -> to = to;
}
};
class Graph{
public:
// 点集 点的编号到点的映射
unordered_map<int, Node*> nodes;
// 边集 是一个集合
unordered_set<Edge*> edges;
};
二维数组 -> 自己熟悉的图表示方式
Graph* createGraph(vector<vector<int> >& matrix){
Graph *graph = new Graph();
for(int i = 0; i < matrix.size(); i++){
int weight = matrix[i][0];
int from = matrix[i][1];
int to = matrix[i][2];
if(graph -> nodes.find(from) == graph -> nodes.end()){
graph -> nodes.insert(make_pair(from, new Node(from)));
}
if(graph -> nodes.find(to) == graph -> nodes.end()){
graph -> nodes.insert(make_pair(to, new Node(to)));
}
Node* fromNode = graph -> nodes[from];
Node* toNode = graph -> nodes[to];
Edge *newEdge = new Edge(weight, fromNode, toNode);
graph -> edges.insert(newEdge);
fromNode -> out++;
toNode -> in++;
fromNode -> edges.push_back(newEdge);
fromNode -> nexts.push_back(toNode);
}
return graph;
}
图的宽度优先遍历bfs
void bfs(Node *node){
if(node == nullptr){
return;
}
queue<Node*> q;
unordered_set<Node*> set;
q.push(node);
set.insert(node);
while(!q.empty()){
Node *temp = q.front(); q.pop();
cout << temp -> val << " ";
for(Node *next : temp -> nexts){
if(set.find(next) == set.end()){
set.insert(next);
q.push(next);
}
}
}
}
图的拓扑排序
根据节点依赖关系先后排序
先输出入度为0的点,消除该点的影响,继续输出入度为0的点
vector<Node*> sortTopology(Graph *graph){
queue<Node*> zeroInQueue;
int i = 0;
while(graph -> nodes.find(i) != graph -> nodes.end()){
if(graph -> nodes[i] -> in == 0){
zeroInQueue.push(graph -> nodes[i]);
}
i++;
}
vector<Node*> result;
while(!zeroInQueue.empty()){
Node *cur = zeroInQueue.front(); zeroInQueue.pop();
result.push_back(cur);
for(Node *next : cur -> nexts){
next -> in --;
if(next -> in ==0){
zeroInQueue.push(next);
}
}
}
return result;
}
图的最小生成树(MST)算法
K算法(Kruskal)
所有边排序,从最小边开始加,如果加上该边形成环,则不加
需要使用并查集
struct cmp{
// 小根堆
bool operator()(Edge *a, Edge *b){
return a -> weight > b -> weight;
}
};
vector<Edge*> kruskal(Graph *graph){
vector<Node*> mynodes;
int i = 0;
while(graph -> nodes.find(i) != graph -> nodes.end()){
mynodes.push_back(graph -> nodes[i]);
i++;
}
mySet my(mynodes);
priority_queue<Edge*, vector<Edge*>, cmp> q;
for(auto it = graph -> edges.begin(); it != graph -> edges.end(); it++){
q.push(*it);
}
vector<Edge*> res;
while(!q.empty()){
Edge *cur = q.top(); q.pop();
if(!my.isSameSet(cur -> from, cur -> to)){
res.push_back(cur);
my.unionSet(cur -> from, cur -> to);
}
}
return res;
}
P算法(Prim)
适用范围:要求无向图
把任意点加入集合,该点的边中另一点未加入集合的边解锁,在所有解锁的边中找最小边,将边的另一点加入集合,以此类推
struct cmp{
bool operator()(Edge *a, Edge *b){
return a -> weight > b -> weight;
}
};
unordered_set<Edge*> prim(Graph *graph){
priority_queue<Edge*, vector<Edge*>, cmp> q;
unordered_set<Node*> nodes;
unordered_set<Edge*> ans;
Node *begin = graph -> nodes[0];
nodes.insert(begin);
for(Edge *edge : begin -> edges){
q.push(edge);
}
while(!q.empty()){
Edge *cur = q.top(); q.pop();
Node *toNode = cur -> to;
if(nodes.find(toNode) == nodes.end()){
nodes.insert(toNode);
ans.insert(cur);
for(Edge *temp : toNode -> edges){
q.push(temp);
}
}
}
return ans;
}
单源最短路径算法(Dijkstra算法)
规定出发点,求该点到其他所有节点的最短路径
适用范围:不能有累加和为负数的环
distanceMap开始时为 0 无穷 无穷 无穷 无穷 。。。
根据head点相连的边调整distanceMap
head点选定(其distanceMap值不再变化)
在distanceMap未选定点中选择value值最小的点node
根据node点相连的边调整distanceMap
node点选定(其distanceMap值不再变化)
在distanceMap未选定点中选择value值最小的点 以此类推
Node* getMinDistanceAndUnselectedNode(unordered_map<Node*, int>& distanceMap, unordered_set<Node*>& selectedNodes){
Node* minNode = nullptr;
int minDistance = INT_MAX;
for(auto it = distanceMap.begin(); it != distanceMap.end(); it++){
if(selectedNodes.find((*it).first) == selectedNodes.end()){
Node *node = (*it).first;
int distance = (*it).second;
if(distance < minDistance){
minDistance = distance;
minNode = node;
}
}
}
return minNode;
}
unordered_map<Node*, int> dijkstra(Node *head){
unordered_map<Node*, int> distanceMap;
distanceMap.insert(make_pair(head, 0));
unordered_set<Node*> selectedNodes;
Node *minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);
while(minNode != nullptr){
int distance = distanceMap[minNode];
for(Edge *edge : minNode -> edges){
Node *toNode = edge -> to;
if(distanceMap.find(toNode) == distanceMap.end()){
distanceMap.insert(make_pair(toNode, distance + edge -> weight));
}
if(distance + edge -> weight < distanceMap[toNode]){
distanceMap[toNode] = distance + edge -> weight;
}
}
selectedNodes.insert(minNode);
minNode = getMinDistanceAndUnselectedNode(distanceMap, selectedNodes);
}
return distanceMap;
}
使用堆优化Dijkstra算法
class NodeRecord{
public:
Node *node;
int distance;
NodeRecord(Node *node, int distance){
this -> node = node;
this -> distance = distance;
}
};
class NodeHeap{
public:
vector<Node*> nodes;
unordered_map<Node*, int> heapIndexMap;
unordered_map<Node*, int> distanceMap;
int size;
NodeHeap(int size){
for(int i = 0; i < size; i++){
nodes.push_back(nullptr);
}
size = 0;
}
bool isEmpty(){
return size == 0;
}
bool isEntered(Node *head){
return heapIndexMap.find(head) != heapIndexMap.end();
}
bool inHead(Node *head){
return isEntered(head) && heapIndexMap.find(head) -> second != -1;
}
void swap(int index1, int index2){
heapIndexMap[nodes[index1]] = index2;
heapIndexMap[nodes[index2]] = index1;
Node *temp = nodes[index1];
nodes[index1] = nodes[index2];
nodes[index2] = temp;
}
void heapify(int index, int size){
int left = index * 2 + 1;
while(left < size){
int smallest = left + 1 < size && distanceMap[nodes[left + 1]] < distanceMap[nodes[left]] ? left + 1 : left;
smallest = distanceMap[nodes[smallest]] < distanceMap[nodes[index]] ? smallest : index;
if(smallest == index){
break;
}
swap(smallest, index);
index = smallest;
left = index * 2 + 1;
}
}
void insertHeapify(Node *node, int index){
while(distanceMap[nodes[index]] < distanceMap[nodes[(index - 1) / 2]]){
swap(index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
void addOrUpdateOrIgnore(Node *node, int distance){
if(inHead(node)){
distanceMap[node] = distance < distanceMap[node] ? distance : distanceMap[node];
insertHeapify(node, heapIndexMap[node]);
}
if(!isEntered(node)){
nodes[size] = node;
heapIndexMap[node] = size;
distanceMap[node] = distance;
insertHeapify(node, size++);
}
}
NodeRecord* pop(){
NodeRecord *record = new NodeRecord(nodes[0], distanceMap[nodes[0]]);
swap(0, size - 1);
heapIndexMap[nodes[size - 1]] = -1;
distanceMap.erase(nodes[size - 1]);
nodes[size - 1] = nullptr;
heapify(0, --size);
return record;
}
};
unordered_map<Node*, int> dijkstra(Node *head, int size){
NodeHeap *heap = new NodeHeap(size);
heap -> addOrUpdateOrIgnore(head, 0);
unordered_map<Node*, int> ans;
while(!heap -> isEmpty()){
NodeRecord *record = heap -> pop();
Node *cur = record -> node;
int distance = record -> distance;
for(Edge *edge : cur -> edges){
heap -> addOrUpdateOrIgnore(edge -> to, edge -> weight + distance);
}
ans.insert(make_pair(cur, distance));
}
return ans;
}