Kylin/DataStructure/Graph.h
2023-12-27 10:29:16 +08:00

350 lines
12 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef GRAPH_H
#define GRAPH_H
#include "Array.h"
#include "DynamicArray.h"
#include "DynamicArrayList.h"
#include "LinkedQueue.h"
#include "LinkedStack.h"
#include "Object.h"
#include "SharedPointer.h"
#include "Sort.h"
#include <optional>
namespace Kylin {
/*ListGraph用*/
template <typename EdgeType>
struct Edge : public Object {
static constexpr size_t npos = static_cast<size_t>(-1);
Edge(size_t begin = npos, size_t end = npos) : begin(begin), end(end) {}
Edge(size_t begin, size_t end, const EdgeType &value) : begin(begin), end(end), value(value) {}
bool operator==(const Edge &obj) { return (begin == obj.begin) && (end == obj.end); }
bool operator!=(const Edge &obj) { return !(*this == obj); }
bool operator<(const Edge &obj) { return (value < obj.value); }
bool operator>(const Edge &obj) { return (value > obj.value); }
bool operator<=(const Edge &obj) { return !(*this > obj); }
size_t begin;
size_t end;
EdgeType value;
};
template <typename VertexType, typename EdgeType>
class Graph : public Object {
public:
virtual VertexType vertex(size_t index) const = 0;
virtual bool setVertex(size_t index, const VertexType &value) = 0;
virtual DynamicArray<size_t> adjacent(size_t index) const = 0;
virtual std::optional<EdgeType> edge(size_t start, size_t end) const = 0;
virtual bool setEdge(size_t start, size_t end, const EdgeType &value) = 0;
virtual bool removeEdge(size_t start, size_t end) = 0;
virtual size_t vertexCount() const = 0;
virtual size_t edgeCount() const = 0;
virtual size_t outDegree(size_t index) const = 0;
virtual size_t inDegree(size_t index) const = 0;
size_t degree(size_t index) const { return outDegree(index) + inDegree(index); }
bool asUndirected() {
bool ret = true;
auto vertexes = vertexCount();
for (size_t i = 0; (i < vertexes) && ret; i++) {
for (size_t j = 0; (j < vertexes) && ret; j++) {
auto edge1 = edge(i, j);
if (edge1) {
auto edge2 = edge(j, i);
ret = ret && edge2 && (edge1 == edge2);
}
}
}
return ret;
}
DynamicArrayList<Edge<EdgeType>> prim(const EdgeType &LIMIT) {
if (!asUndirected()) THROW_EXCEPTION(InvalidOperationException, "Graph must be undirectedgraph.");
auto vertexSize = vertexCount();
DynamicArrayList<Edge<EdgeType>> result(vertexSize - 1);
DynamicArray<size_t> edges(vertexSize);
DynamicArray<EdgeType> costs(vertexSize, LIMIT);
DynamicArray<bool> mark(vertexSize, false);
//以start为起点查找邻边获取权值。如果有最小的则更新cost数组和edges邻边记录表。
auto updateCosts = [this, &mark, &costs, &edges](size_t start) {
auto adjacent = this->adjacent(start);
for (size_t j = 0; j < adjacent.size(); j++) {
auto end = adjacent[j];
auto newCost = *edge(start, end);
if (mark[end] == false && costs[end] > newCost) {
costs[end] = newCost;
edges[end] = start;
}
}
};
updateCosts(0);
mark[0] = true;
for (size_t i = 1; i < vertexSize; i++) {
//选取最小边,记录其终点
auto miniCost = LIMIT;
size_t end = static_cast<size_t>(-1);
for (size_t j = 0; j < vertexSize; j++) {
if (mark[j] == false && costs[j] < miniCost) {
miniCost = costs[j];
end = j;
}
}
if (end == static_cast<size_t>(-1)) break;
result.append(Edge(edges[end], end, miniCost));
mark[end] = true;
updateCosts(end); //已上次的end为start,更新cost数组
}
if (result.size() != (vertexSize - 1))
THROW_EXCEPTION(InvalidOperationException, "No enough edge for prim operation...");
return result;
}
DynamicArrayList<Edge<EdgeType>> kruskal() {
DynamicArrayList<Edge<EdgeType>> result(1);
auto edges = getUndirectedEdges();
if (edges.empty()) return result;
auto vertexSize = vertexCount();
DynamicArray<size_t> set(vertexSize);
for (size_t i = 0; i < vertexSize; i++) {
set[i] = i;
}
auto find = [&set](size_t index) {
while (index != set[index]) {
index = set[index];
}
return index;
};
Sort::quick(&edges[0], edges.size());
for (size_t i = 0; i < edges.size(); i++) {
auto beginRoot = find(edges[i].begin);
auto endRoot = find(edges[i].end);
if (beginRoot != endRoot) {
result.append(edges[i]);
set[endRoot] = beginRoot;
}
if (result.size() >= (vertexSize - 1)) break;
}
if (result.size() != vertexSize - 1)
THROW_EXCEPTION(InvalidOperationException, "No enough edge for kruskal operation...");
return result;
}
DynamicArray<size_t> breadthFirstSearch(size_t index) {
if (index < 0 || index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid...");
LinkedQueue<size_t> queue;
LinkedQueue<size_t> ret;
DynamicArray<bool> visited(vertexCount(), false);
queue.enqueue(index);
while (queue.length() > 0) {
auto v = queue.dequeue();
if (visited[v]) continue;
auto aj = adjacent(v);
for (size_t j = 0; j < aj.length(); j++) {
queue.enqueue(aj.at(j));
}
ret.enqueue(v);
visited[v] = true;
}
return toArray(ret);
}
DynamicArray<size_t> depthFirstSearch(size_t index) {
if (index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid...");
LinkedStack<size_t> stack;
LinkedQueue<size_t> ret;
DynamicArray<bool> visited(vertexCount(), false);
stack.push(index);
while (stack.size() > 0) {
auto v = stack.top();
stack.pop();
if (visited[v]) continue;
auto aj = adjacent(v);
for (auto value : aj) {
stack.push(value);
}
ret.enqueue(v);
visited[v] = true;
}
return toArray(ret);
}
DynamicArray<size_t> dijkstra(size_t begin, size_t end, const EdgeType &LIMIT) {
size_t vertexSize = vertexCount();
if (begin >= vertexSize || end >= vertexSize)
THROW_EXCEPTION(InvalidParameterException, "Parameter begin or end is invalid.");
LinkedStack<size_t> result;
DynamicArray<EdgeType> distance(vertexSize, LIMIT);
DynamicArray<bool> mark(vertexSize, false);
DynamicArray<size_t> path(vertexSize, static_cast<size_t>(-1));
for (size_t i = 0; i < vertexSize; i++) {
auto edge = this->edge(begin, i);
if (edge) {
distance[i] = *edge;
path[i] = begin;
}
}
mark[begin] = true;
for (size_t i = 1; i < vertexSize; i++) {
EdgeType mini = LIMIT;
size_t endIndex = static_cast<size_t>(-1);
for (size_t j = 0; j < vertexSize; j++) {
if (mark[j] == false && distance[j] < mini) {
endIndex = j;
mini = distance[j];
}
}
if (endIndex == static_cast<size_t>(-1)) break;
mark[endIndex] = true;
for (size_t j = 0; j < vertexSize; j++) {
if (mark[j] == false) {
auto edge = this->edge(endIndex, j);
if (edge && (*edge + distance[endIndex] < distance[j])) {
distance[j] = *edge + distance[endIndex];
path[j] = endIndex;
}
}
}
}
result.push(end);
size_t pos = end;
while (path[pos] != begin) {
pos = path[pos];
result.push(pos);
}
result.push(begin);
return toArray(result);
}
DynamicArray<int> floyd(int x, int y, const EdgeType &LIMIT) {
LinkedQueue<int> ret;
if ((x >= 0) && (x < vertexCount()) && (y >= 0) && (y < vertexCount())) {
DynamicArray<DynamicArray<EdgeType>> dist(vertexCount());
DynamicArray<DynamicArray<int>> path(vertexCount());
for (int k = 0; k < vertexCount(); k++) {
dist[k].resize(vertexCount());
path[k].resize(vertexCount());
}
for (int i = 0; i < vertexCount(); i++) { // A -1
for (int j = 0; j < vertexCount(); j++) {
auto edge = this->edge(i, j);
dist[i][j] = edge ? *edge : LIMIT;
path[i][j] = edge ? j : -1;
}
}
for (int k = 0; k < vertexCount(); k++) {
for (int i = 0; i < vertexCount(); i++) {
for (int j = 0; j < vertexCount(); j++) {
if (dist[i][k] + dist[k][j] < dist[i][j]) {
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k];
}
}
}
}
while ((x != -1) && (x != y)) {
ret.enqueue(x);
x = path[x][y];
}
if (x != -1) {
ret.enqueue(x);
}
if (ret.size() < 2) {
THROW_EXCEPTION(InvalidOperationException, "There is no path form x to y.");
}
} else {
THROW_EXCEPTION(InvalidParameterException, "Index<x,y> is invalid .");
}
return toArray(ret);
}
/* DFS递归版实现
static void DFS(Graph *graph,size_t index,Kylin::Array<bool> &visited,LinkedQueue<size_t> &ret) {
if((index>=0)&&(index<graph->vertexCount())) {
ret.add(index);
visited[index] = true;
auto aj = graph->adjacent(index);
for(size_t i=0;i<aj->length();i++){
if(visited[aj->at(i)]) continue;
DFS(graph,aj->at(i),visited,ret);
}
} else {
THROW_EXCEPTION(Kylin::InvalidParameterException,"Index is invalid...");
}
}
SharedPointer<Array<size_t>> DFS(size_t index) {
Kylin::DynamicArray<bool> visited(vertexCount(),false);
LinkedQueue<size_t> ret;
DFS(this,index,visited,ret);
return toArray(ret);
}
*/
protected:
template <typename T>
static DynamicArray<T> toArray(LinkedQueue<T> &queue) {
DynamicArray<T> ret(queue.length());
for (size_t i = 0; i < ret.length(); i++) {
ret[i] = queue.dequeue();
}
return ret;
}
template <typename T>
static DynamicArray<T> toArray(LinkedStack<T> &stack) {
DynamicArray<T> ret(stack.size());
for (size_t i = 0; i < ret.size(); i++) {
ret[i] = stack.pop();
}
return ret;
}
DynamicArrayList<Edge<EdgeType>> getUndirectedEdges() {
DynamicArrayList<Edge<EdgeType>> result(1);
if (!asUndirected()) return result;
auto vertexes = vertexCount();
for (size_t i = 0; i < vertexes; i++) {
for (size_t j = i + 1; j < vertexes; j++) {
auto e = edge(i, j);
if (e) {
result.append(Edge<EdgeType>(i, j, *e));
}
}
}
return result;
}
size_t findTerminalVertex(Array<size_t> &p, size_t v) {
while (p[v] != static_cast<size_t>(-1)) {
v = p[v];
}
return v;
}
}; // namespace Kylin
} // namespace Kylin
#endif // GRAPH_H