#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 namespace Kylin { /*ListGraph用*/ template struct Edge : public Object { static constexpr size_t npos = static_cast(-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 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 adjacent(size_t index) const = 0; virtual std::optional 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> prim(const EdgeType &LIMIT) { if (!asUndirected()) THROW_EXCEPTION(InvalidOperationException, "Graph must be undirectedgraph."); auto vertexSize = vertexCount(); DynamicArrayList> result(vertexSize - 1); DynamicArray edges(vertexSize); DynamicArray costs(vertexSize, LIMIT); DynamicArray 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(-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(-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> kruskal() { DynamicArrayList> result(1); auto edges = getUndirectedEdges(); if (edges.empty()) return result; auto vertexSize = vertexCount(); DynamicArray 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 breadthFirstSearch(size_t index) { if (index < 0 || index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); LinkedQueue queue; LinkedQueue ret; DynamicArray 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 depthFirstSearch(size_t index) { if (index >= vertexCount()) THROW_EXCEPTION(InvalidParameterException, "Index is invalid..."); LinkedStack stack; LinkedQueue ret; DynamicArray 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 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 result; DynamicArray distance(vertexSize, LIMIT); DynamicArray mark(vertexSize, false); DynamicArray path(vertexSize, static_cast(-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(-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(-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 floyd(int x, int y, const EdgeType &LIMIT) { LinkedQueue ret; if ((x >= 0) && (x < vertexCount()) && (y >= 0) && (y < vertexCount())) { DynamicArray> dist(vertexCount()); DynamicArray> 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 is invalid ."); } return toArray(ret); } /* DFS递归版实现 static void DFS(Graph *graph,size_t index,Kylin::Array &visited,LinkedQueue &ret) { if((index>=0)&&(indexvertexCount())) { ret.add(index); visited[index] = true; auto aj = graph->adjacent(index); for(size_t i=0;ilength();i++){ if(visited[aj->at(i)]) continue; DFS(graph,aj->at(i),visited,ret); } } else { THROW_EXCEPTION(Kylin::InvalidParameterException,"Index is invalid..."); } } SharedPointer> DFS(size_t index) { Kylin::DynamicArray visited(vertexCount(),false); LinkedQueue ret; DFS(this,index,visited,ret); return toArray(ret); } */ protected: template static DynamicArray toArray(LinkedQueue &queue) { DynamicArray ret(queue.length()); for (size_t i = 0; i < ret.length(); i++) { ret[i] = queue.dequeue(); } return ret; } template static DynamicArray toArray(LinkedStack &stack) { DynamicArray ret(stack.size()); for (size_t i = 0; i < ret.size(); i++) { ret[i] = stack.pop(); } return ret; } DynamicArrayList> getUndirectedEdges() { DynamicArrayList> 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(i, j, *e)); } } } return result; } size_t findTerminalVertex(Array &p, size_t v) { while (p[v] != static_cast(-1)) { v = p[v]; } return v; } }; // namespace Kylin } // namespace Kylin #endif // GRAPH_H