图的实现、无向图的最小生成树、有向图的最短路径

graph.h

#ifndef __GRAPH__
#define __GRAPH__

#include <iostream>
#include <queue>
using namespace std;

class DisjointSet;

template <class TypeOfEdge>
class Graph {
public:
  virtual bool insert(int u, int v, TypeOfEdge weight) = 0;
  virtual bool remove(int u, int v) = 0;
  virtual bool modify(int u, int v, TypeOfEdge weight) = 0;
  virtual bool exist(int u, int v) const = 0;
  virtual int numOfVer() const {return vers;}
  virtual int numOfEdge() const {return edges;}

protected:
  int vers;
  int edges;
};

//有向加权图的邻接表实现
//作为无权图使用时,可将weight置1,权值一样
//作为无向图使用时,插入和删除时需将两个方向的边均插入或删除,修改weight时同样
template <class TypeOfVer, class TypeOfEdge>
class AdjListGraph : public Graph<TypeOfEdge>{
public:
  //这里为了方便,所有成员函数写成内联函数的形式

  //构造一个只有结点没有边的图
  AdjListGraph(int v, const TypeOfVer *d, bool isWeightedFlag, bool isDirectedFlag){
    vers = v;
    edges = 0;
    isWeighted = isWeightedFlag;
    isDirected = isDirectedFlag;

    verList = new VerNode[vers];
    for (int i = 0; i < vers; ++i) {
      verList[i].ver = d[i];
    }
  }

  ~AdjListGraph(){
    for (int i = 0; i < vers; ++i) {
      EdgeNode *p, *pre;
      p = verList[i].head;
      while (p != NULL){
        pre = p;
        p = p->next;
        delete pre;
      }
    }

    delete [] verList;
  }

  bool insert(int u, int v, TypeOfEdge weight = 0) {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;

    if (exist(u, v))
      return false;

    verList[u].head = new EdgeNode(v, weight, verList[u].head);
    if (!isDirected)
      verList[v].head = new EdgeNode(u, weight, verList[v].head);
    ++edges;

    return true;
  }

  bool remove(int u, int v) {
    bool flag = removeCore(u, v);
    if (!isDirected)
      flag &= removeCore(v, u);
    return flag;
  }

  bool removeCore(int u, int v) {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;

    EdgeNode *p = verList[u].head;
    if (p == NULL){
      return false;
    }
    //删除结点为头结点
    if (p->end == v){
      verList[u].head = p->next;
      delete p;
      --edges;
      return true;
    }

    //找到删除结点或找不到
    EdgeNode *pre = p;
    p = p->next;
    while (p != NULL && p->end != v) {
      pre = p;
      p = p->next;
    }
    //找不到
    if (p == NULL){
      return false;
    }
    //找到
    pre->next = p->next;
    delete p;
    --edges;

    return true;
  }

  bool modify(int u, int v, TypeOfEdge weight) {
    bool flag = modifyCore(u, v, weight);
    if (!isDirected)
      flag &= modifyCore(v, u, weight);
    return flag;
  }

  bool modifyCore(int u, int v, TypeOfEdge weight) {
    EdgeNode *p = verList[u].head;
    while (p != NULL && p->end != v) {
      p = p->next;
    }
    if (p == NULL) {
      return false;
    }
    p->weight = weight;
    return true;
  }

  bool exist(int u, int v) const {
    EdgeNode *p = verList[u].head;
    while (p != NULL && p->end != v) {
      p = p->next;
    }
    if (p == NULL) {
      return false;
    }
    return true;
  }

  //深度优先遍历
  void dfs(int startVer = 0) const {
    bool *visited = new bool[vers];
    for (int i = 0; i < vers; ++i)
      visited[i] = false;

    int j = 0;
    for (int i = startVer; i < vers + startVer; ++i){
      j = i % vers;
      if (visited[j])
        continue;
      dfsCore(j, visited);
      cout << endl; //每一行为一棵深度优先生成树
    }
  }

  //广度优先遍历
  void bfs(int startVer = 0) const {
    bool *visited = new bool[vers];
    for (int i = 0; i < vers; ++i)
      visited[i] = false;

    queue<int> q;
    int j = 0;
    for (int i = startVer; i < vers + startVer; ++i){
      j = i % vers;
      if (visited[j])
        continue;
      q.push(j);
      while (!q.empty()) {
        //访问当前结点
        int v = q.front();
        q.pop();
        if (visited[v])
          continue;
        cout << verList[v].ver << '\t';
        visited[v] = true;

        //当前结点的后继结点放入队列
        EdgeNode *p = verList[v].head;
        while (p != NULL) {
          if (!visited[p->end]) {
            q.push(p->end);
          }
          p = p->next;
        }
      }
      cout << endl; //每一行为一棵广度优先生成树
    }
  }

  //欧拉回路
  void eulerCircuit(TypeOfVer start) {
    if (edges == 0)
      return;

    for (int i = 0; i < vers; ++i) {
      int degree = 0;
      EdgeNode *p = verList[i].head;
      while (p != NULL) {
        ++degree;
        p = p->next;
      }
      //度数为0或奇数,不存在欧拉回路
      if ((degree == 0) || (degree & 0x1))
        return;
    }

    //找到起始点序号
    int iStart = 0;
    for (iStart = 0; iStart < vers; ++iStart){
      if (verList[iStart].ver == start)
        break;
    }
    if (iStart == vers)
      return;

    //保存一个备份
    VerNode *tmp = clone();

    //找到第一条路径(起点所有的边已被访问)
    EulerNode *beg, *end;
    eulerCircuitCore(iStart, beg, end);

    EulerNode *p, *pre;
    while (true) {
      pre = beg;
      p = beg->next;
      while (p != NULL) {
        if (verList[p->nodeNum].head != NULL)
          break;
        pre = p;
        p = p->next;
      }
      if (p == NULL)
        break;

      //从某一个未访问的边开始找一条路径
      EulerNode *begTmp, *endTmp;
      eulerCircuitCore(p->nodeNum, begTmp, endTmp);
      pre->next = begTmp;
      endTmp->next = p->next;
      delete p;
    }

    //恢复原图
    delete [] verList;
    verList = tmp;

    p = beg;
    while (p != NULL) {
      cout << verList[p->nodeNum].ver << '\t';
      pre = p;
      p = p->next;
      delete pre;
    }
    cout << endl;
  }

  //拓扑排序
  void topologySort() const {
    //计算入度
    int *inDegree = new int[vers];
    memset(inDegree, 0, vers * sizeof(int));
    for (int i = 0; i < vers; ++i){
      EdgeNode *p = verList[i].head;
      while (p != NULL) {
        ++inDegree[p->end];
        p = p->next;
      }
    }

    //入度为0的放入队列
    queue<int> q;
    for (int i = 0; i < vers; ++i){
      if (inDegree[i] == 0)
        q.push(i);
    }

    while (!q.empty()) {
      int v = q.front();
      q.pop();
      cout << verList[v].ver << '\t';

      //入度减1, 为0的放入队列
      EdgeNode *p = verList[v].head;
      while (p != NULL) {
        --inDegree[p->end];
        if (inDegree[p->end] == 0) {
          q.push(p->end);
        }
        p = p->next;
      }
    }
    cout << endl;
  }

  //kruskal算法求最小生成树( 时间复杂度O(|E|log|E|) )
  void kruskal() const {
    priority_queue<Edge, deque<Edge>, greater<Edge>> pq;  //最小堆
    //priority_queue<Edge, deque<Edge>, compEdgeGreater> pq;  //最小堆
    //priority_queue<Edge> pq;  //默认最大堆
    DisjointSet ds(vers);

    //所有边放入优先级队列
    for (int i = 0; i < vers; ++i) {
      EdgeNode *p = verList[i].head;
      while (p != NULL) {
        if (i < p->end) { //只添加一次
          Edge edge(i, p->end, p->weight);
          pq.push(edge);
        }
        p = p->next;
      }
    }

    //合并生成最小生成树
    int count = 0;
    while (count < vers - 1) {
      Edge edge = pq.top();
      pq.pop();
      int u = ds.find(edge.beg);
      int v = ds.find(edge.end);
      if (u != v) {
        ++count;
        ds.unionTwoSet(u, v);
        cout << "(" << verList[edge.beg].ver << "," << verList[edge.end].ver << ")\t";
      }
    }
    cout << endl;
  }

  //prim算法求最小生成树( 时间复杂度O(|V^2|) )
  void prim(TypeOfEdge noEdge) const {
    //顶点集合V, 最小生成树结点集合U, 剩余结点V-U
    bool *flag = new bool[vers];                //结点在U中为true
    TypeOfEdge *lowCost = new TypeOfEdge[vers]; //U中结点到结点i的最小权值, 当i在U中时lowCost为noEdge, 当i在V-U中时lowCost为有限值
    int *startNode = new int[vers];             //U中结点startNode[i]到结点i的权值是lowCost[i]

    for (int i = 0; i < vers; ++i) {
      flag[i] = false;
      lowCost[i] = noEdge;
    }

    int start = 0;  //起始点
    int current = start;  //current是即将加入到U中的结点
    for (int i = 1; i < vers; ++i) {
      EdgeNode *p = verList[current].head;
      while (p != NULL) {
        if (!flag[p->end] && p->weight < lowCost[p->end]) { //结点p->end不在U中, 并且结点p->end到结点current的距离小于结点p->end到U中已有点的最小距离
          lowCost[p->end] = p->weight;
          startNode[p->end] = current;
        }
        p = p->next;
      }

      //current加入U
      flag[current] = true;

      //寻找V-U中到V-U的最小距离点
      TypeOfEdge min = noEdge;
      bool tflag = false;
      for (int j = 0; j < vers; ++j) {
        if (lowCost[j] < min) {
          min = lowCost[j];
#if 1
          current = j;  //取V-U中到U的最小距离点作为下一个计算点
#else
          if (!tflag) {
            tflag = true;
            current = j;  //在V-U中随意取一个点,与上面的方法结果一致
          }
#endif
        }
      }
      cout << "(" << verList[startNode[current]].ver << "," << verList[current].ver << ")\t";

      lowCost[current] = noEdge;
    }
    cout << endl;

    delete [] flag;
    delete [] lowCost;
    delete [] startNode;
  }

  //非加权图的单源最短路径( bfs算法, 时间复杂度为|V|和|E|中的较小者, 即O(|V| + |E|) )
  void unweightedShortDistance(TypeOfVer start, TypeOfEdge noEdge) const {
    //找到起始点序号
    int iStart = 0;
    for (iStart = 0; iStart < vers; ++iStart) {
      if (verList[iStart].ver == start)
        break;
    }
    if (iStart == vers)
      return;

    TypeOfEdge *distance = new TypeOfEdge[vers];
    int *prev = new int[vers];
    for (int i = 0; i < vers; ++i) {
      distance[i] = noEdge;
    }

    distance[iStart] = 0;
    prev[iStart] = iStart;
    queue<int> q;
    q.push(iStart);
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      EdgeNode *p = verList[u].head;
      while (p != NULL) {
        if (distance[p->end] == noEdge) {
          distance[p->end] = distance[u] + 1;
          prev[p->end] = u;
          q.push(p->end);
        }
        p = p->next;
      }
    }

    for (int i = 0; i < vers; ++i) {
      cout << "the path from " << start << " to "  << verList[i].ver << ": ";
      printPath(iStart, i, prev);
      cout << endl;
    }
    cout << endl;

    delete [] distance;
    delete [] prev;
  }

  //加权图的单源最短路径(dijkstra算法与prim算法有些类似, 时间复杂度O(|V^2|) )
  void dijkstra(TypeOfVer start, TypeOfEdge noEdge) const {
    //找到起始点序号
    int iStart = 0;
    for (iStart = 0; iStart < vers; ++iStart) {
      if (verList[iStart].ver == start)
        break;
    }
    if (iStart == vers)
      return;

    //顶点集合V, 已经找到最短路径的顶点集合U, 剩余结点V-U
    TypeOfEdge *distance = new TypeOfEdge[vers];  //结点i到起始点的最短距离
    bool *konwn = new bool[vers];                 //结点在U中为true
    int *prev = new int[vers];                    //结点i的前继结点
    for (int i = 0; i < vers; ++i) {
      distance[i] = noEdge;
      konwn[i] = false;
    }

    distance[iStart] = 0;
    prev[iStart] = iStart;
    int current = iStart;
    for (int i = 1; i < vers; ++i) {
      //寻找V-U中到U中的最小距离点
      TypeOfEdge min = noEdge;
      for (int j = 0; j < vers; ++j) {
        if (!konwn[j] && distance[j] < min) {
          min = distance[j];
          current = j;
        }
      }

      konwn[current] = true;
      EdgeNode *p = verList[current].head;
      while (p != NULL) {
        if (!konwn[p->end] && min + p->weight < distance[p->end]) {
          distance[p->end] = min + p->weight;
          prev[p->end] = current;
        }
        p = p->next;
      }
    }

    for (int i = 0; i < vers; ++i) {
      cout << "the path from " << start << " to "  << verList[i].ver << ": ";
      printPath(iStart, i, prev);
      cout << "\twith length: " << distance[i] << endl;
    }
    cout << endl;

    delete [] distance;
    delete [] prev;
    delete [] konwn;
  }

  //带负权值图的单源最短路径(可以有环, 但不能有负环, 时间复杂度O(|V||E|) )
  void weightedNegative(TypeOfVer start, TypeOfEdge noEdge) const {
    //找到起始点序号
    int iStart = 0;
    for (iStart = 0; iStart < vers; ++iStart) {
      if (verList[iStart].ver == start)
        break;
    }
    if (iStart == vers)
      return;

    TypeOfEdge *distance = new TypeOfEdge[vers];
    int *prev = new int[vers];
    for (int i = 0; i < vers; ++i) {
      distance[i] = noEdge;
    }

    distance[iStart] = 0;
    prev[iStart] = iStart;
    queue<int> q;
    q.push(iStart);
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      EdgeNode *p = verList[u].head;
      while (p != NULL) {
        if (distance[u] + p->weight < distance[p->end]) {
          distance[p->end] = distance[u] + p->weight;
          prev[p->end] = u;
          q.push(p->end);
        }
        p = p->next;
      }
    }

    for (int i = 0; i < vers; ++i) {
      cout << "the path from " << start << " to "  << verList[i].ver << ": ";
      printPath(iStart, i, prev);
      cout << "\twith length: " << distance[i] << endl;
    }
    cout << endl;

    delete [] distance;
    delete [] prev;
  }

private:
  struct EdgeNode {
    int end;
    TypeOfEdge weight;
    EdgeNode *next;

    EdgeNode(int e, TypeOfEdge w, EdgeNode *n = NULL):end(e), weight(w), next(n) {}
  };

  struct VerNode {
    TypeOfVer ver;
    EdgeNode *head;

    VerNode(EdgeNode *h = NULL):head(h){}
    VerNode(TypeOfVer v, EdgeNode *h = NULL):ver(v), head(h){}
  };

  VerNode *verList;
  bool isWeighted;
  bool isDirected;

  void dfsCore(int start, bool *visited) const {
    cout << verList[start].ver << '\t';
    visited[start] = true;

    EdgeNode *p = verList[start].head;
    while (p != NULL) {
      if (!visited[p->end])
        dfsCore(p->end, visited);
      p = p->next;
    }
  }

  struct EulerNode {
    int nodeNum;
    EulerNode *next;

    EulerNode(int num, EulerNode *n = NULL):nodeNum(num), next(n) {}
  };

  VerNode *clone() const {
    VerNode *tmp = new VerNode[vers];
    for (int i = 0; i < vers; ++i){
      tmp[i].ver = verList[i].ver;
      EdgeNode *p = verList[i].head;
      while (p != NULL) {
        tmp[i].head = new EdgeNode(p->end, p->weight, tmp[i].head);
        p = p->next;
      }
    }
    return tmp;
  }

  void eulerCircuitCore(int start, EulerNode *&beg, EulerNode *&end) {
    beg = end = new EulerNode(start);
    while (verList[start].head != NULL) {
      int nextNodeNum = verList[start].head->end;
      remove(start, nextNodeNum);
      //remove(nextNodeNum, start);

      end->next = new EulerNode(nextNodeNum);
      end = end->next;

      start = nextNodeNum;
    }
  }

  struct Edge {
    int beg, end;
    TypeOfEdge weight;

    Edge(int b, int e, TypeOfEdge w):beg(b), end(e),weight(w) {}
    bool operator>(const Edge &right) const {
      return weight > right.weight;
    }
  };

  struct compEdgeGreater {
    bool operator()(Edge first, Edge second) {
      return first.weight > second.weight;
    }
  };

  void printPath(int start, int end, int *prev) const {
    if (start == end) {
      cout << verList[start].ver;
      return;
    }
    printPath(start, prev[end], prev);
    cout << "-" << verList[end].ver;
  }
};

//有向加权图的邻接矩阵实现
//作为无权图使用时,可将weight置1,权值一样
//作为无向图使用时,插入和删除时需将两个方向的边均插入或删除,修改weight时同样
template <class TypeOfVer, class TypeOfEdge>
class AdjMatrixGraph : public Graph<TypeOfEdge>{
public:
  //这里为了方便,所有成员函数写成内联函数的形式
  AdjMatrixGraph(int v, const TypeOfVer *d, TypeOfEdge noEdgeFlag, bool isWeightedFlag, bool isDirectedFlag) {
    vers = v;
    edges = 0;
    noEdge = noEdgeFlag;
    isWeighted = isWeightedFlag;
    isDirected = isDirectedFlag;

    ver = new TypeOfVer[vers];
    for (int i = 0; i < vers; ++i) {
      ver[i] = d[i];
    }

    edge = new TypeOfEdge *[vers];
    for (int i = 0; i < vers; ++i) {
      edge[i] = new TypeOfEdge[vers];
      for (int j = 0; j < vers; ++j) {
        edge[i][j] = noEdge;
      }
      edge[i][i] = 0;
    }
  }

  ~AdjMatrixGraph() {
    delete [] ver;
    for (int i = 0; i < vers; ++i) {
      delete [] edge[i];
    }
    delete [] edge;
  }

  bool insert(int u, int v, TypeOfEdge w) {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;
    if (exist(u, v))
      return false;
    edge[u][v] = w;
    if (!isDirected)
      edge[v][u] = w;
    ++edges;
    return true;
  }

  bool remove(int u, int v) {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;
    if (!exist(u, v))
      return false;
    edge[u][v] = noEdge;
    if (!isDirected)
      edge[v][u] = noEdge;
    --edges;
    return true;
  }

  bool modify(int u, int v, TypeOfEdge w) {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;
    if (!exist(u, v))
      return false;
    edge[u][v] = w;
    if (!isDirected)
      edge[v][u] = w;
    return true;
  }

  bool exist(int u, int v) const {
    if (u < 0 || u > vers - 1 || v < 0 || v > vers - 1)
      return false;
    if (edge[u][v] == noEdge)
      return false;
    return true;
  }

  //所有顶点对的最短路径( 时间复杂度O(|V^3|) )
  void floyd() const {
    TypeOfEdge **d = new TypeOfEdge *[vers];
    int **prev = new int *[vers];
    for (int i = 0; i < vers; ++i) {
      d[i] = new TypeOfEdge[vers];
      prev[i] = new int[vers];
      for (int j = 0; j < vers; ++j) {
        d[i][j] = edge[i][j];
        prev[i][j] = (edge[i][j] != noEdge) ? i : -1;
      }
    }

    for (int k = 0; k < vers; ++k) {
      for (int i = 0; i < vers; ++i) {
        for (int j = 0; j < vers; ++j) {
          if (d[i][k] + d[k][j] < d[i][j]) {
            d[i][j] = d[i][k] + d[k][j];
            prev[i][j] = prev[k][j];
          }
        }
      }
    }

    for (int i = 0; i < vers; ++i) {
      for (int j = 0; j < vers; ++j) {
        cout << "the path from " << ver[i] << " to " << ver[j] << ": ";
        printPath(i, j, prev);
        cout << "\twith length: " << d[i][j]<< endl;
      }
    }
    //cout << "最短路径" << endl;
    //for (int i = 0; i < vers; ++i) {
    //  for (int j = 0; j < vers; ++j) {
    //    cout << prev[i][j] << "\t";
    //  }
    //  cout << endl;
    //}
    //cout << "长度" << endl;
    //for (int i = 0; i < vers; ++i) {
    //  for (int j = 0; j < vers; ++j) {
    //    cout << d[i][j] << "\t";
    //  }
    //  cout << endl;
    //}
    cout << endl;

    delete [] d;
    delete [] prev;
  }

private:
  TypeOfEdge **edge;
  TypeOfVer *ver;
  TypeOfEdge noEdge;
  bool isWeighted;
  bool isDirected;

  void printPath(int start, int end, int **prev) const {
    if (start == end) {
      cout << ver[start];
      return;
    }
    printPath(start, prev[start][end], prev);
    cout << "-" << ver[end];
  }
};

//不相交集(并查集)
class DisjointSet {
public:
  DisjointSet(int n) {
    size = n;
    parent = new int[n];
    for (int i = 0; i < n; ++i) {
      parent[i] = -1;
    }
  }

  ~DisjointSet(){
    delete [] parent;
  }

  int find(int x) {
    if (parent[x] < 0)
      return x;
    return parent[x] = find(parent[x]);
  }

  void unionTwoSet(int root1, int root2){
    if (root1 == root2)
      return;
    if (parent[root1] > parent[root2]) {  //root1规模小
      parent[root2] += parent[root1];
      parent[root1] = root2;
    }
    else{
      parent[root1] += parent[root2];
      parent[root2] = root1;
    }
  }

private:
  int size;
  int *parent;
};

#endif

main.cpp

#include "graph.h"
#include <iostream>
using namespace std;

int main() {
  //有向图的遍历
  cout << "有向图的遍历:" << endl;
  AdjListGraph<char, int> g(7, "0123456", true, true);
  //adjListGraph<char, int> g(7, "1234567", true, true);
  //adjListGraph<char, int> g(7, "abcdefg", true, true);
  g.insert(4, 5, 1);
  g.insert(4, 6, 1);
  g.insert(6, 5, 1);
  g.insert(5, 1, 1);
  g.insert(6, 3, 1);
  g.insert(1, 3, 1);
  g.insert(0, 1, 1);
  g.insert(3, 2, 1);
  g.insert(1, 2, 1);
  g.insert(3, 0, 1);
  g.insert(2, 0, 1);
  g.dfs();
  cout << endl;
  g.dfs(4);
  cout << endl;
  g.bfs();
  cout << endl;
  g.bfs(4);
  cout << endl;

  //无向图的欧拉回路
  cout << "无向图的欧拉回路:" << endl;
  AdjListGraph<char, int> eulerGraph(6, "012345", true, false);
  eulerGraph.insert(0, 1, 1);
  eulerGraph.insert(0, 2, 1);
  eulerGraph.insert(1, 2, 1);
  eulerGraph.insert(2, 3, 1);
  eulerGraph.insert(1, 4, 1);
  eulerGraph.insert(1, 3, 1);
  eulerGraph.insert(2, 4, 1);
  eulerGraph.insert(3, 4, 1);
  eulerGraph.insert(3, 5, 1);
  eulerGraph.insert(4, 5, 1);
  eulerGraph.eulerCircuit('5');

  //有向无环图的拓扑排序
  cout << "有向无环图的拓扑排序:" << endl;
  AdjListGraph<char, int> topologyGraph(7, "0123456", true, true);
  topologyGraph.insert(0, 1, 1);
  topologyGraph.insert(0, 2, 1);
  topologyGraph.insert(1, 3, 1);
  topologyGraph.insert(1, 4, 1);
  topologyGraph.insert(1, 5, 1);
  topologyGraph.insert(2, 4, 1);
  topologyGraph.insert(2, 6, 1);
  topologyGraph.insert(4, 5, 1);
  topologyGraph.insert(4, 6, 1);
  topologyGraph.insert(5, 3, 1);
  topologyGraph.topologySort();

  //无向图的最小生成树
  cout << "最小生成树:" << endl;
  //AdjListGraph<char, int> minimumSpanningTree(6, "012345", true, false);
  AdjListGraph<char, int> minimumSpanningTree(6, "123456", true, false);
  minimumSpanningTree.insert(0, 3, 5);
  minimumSpanningTree.insert(3, 5, 2);
  minimumSpanningTree.insert(4, 5, 6);
  minimumSpanningTree.insert(1, 4, 3);
  minimumSpanningTree.insert(0, 1, 6);
  minimumSpanningTree.insert(0, 2, 1);
  minimumSpanningTree.insert(1, 2, 5);
  minimumSpanningTree.insert(2, 3, 5);
  minimumSpanningTree.insert(2, 4, 6);
  minimumSpanningTree.insert(2, 5, 4);
  minimumSpanningTree.kruskal();
  minimumSpanningTree.prim(INT_MAX);

  //有向图的单源最短路径
  cout << "单源最短路径:" << endl;
  AdjListGraph<char, int> singleSourceShortestPath(7, "0123456", true, true);
  singleSourceShortestPath.insert(0, 1, 2);
  singleSourceShortestPath.insert(1, 4, 10);
  singleSourceShortestPath.insert(4, 6, 6);
  singleSourceShortestPath.insert(6, 5, 1);
  singleSourceShortestPath.insert(2, 0, 4);
  singleSourceShortestPath.insert(2, 5, 5);
  singleSourceShortestPath.insert(0, 3, 1);
  singleSourceShortestPath.insert(1, 3, 3);
  singleSourceShortestPath.insert(3, 2, 2);
  singleSourceShortestPath.insert(3, 4, 2);
  singleSourceShortestPath.insert(3, 5, 8);
  singleSourceShortestPath.insert(3, 6, 4);
  cout << "非加权图" << endl;
  singleSourceShortestPath.unweightedShortDistance('2', INT_MAX);
  cout << "加权图" << endl;
  //singleSourceShortestPath.dijkstra('1', INT_MAX);
  singleSourceShortestPath.dijkstra('2', INT_MAX);

  //有向带负权值图的单源最短路径
  AdjListGraph<char, int> singleSourceShortestPathWeightedNegative(7, "0123456", true, true);
  singleSourceShortestPathWeightedNegative.insert(0, 1, 2);
  singleSourceShortestPathWeightedNegative.insert(1, 4, 10);
  singleSourceShortestPathWeightedNegative.insert(4, 6, 6);
  singleSourceShortestPathWeightedNegative.insert(6, 5, 1);
  singleSourceShortestPathWeightedNegative.insert(2, 0, 4);
  singleSourceShortestPathWeightedNegative.insert(2, 5, 3);
  singleSourceShortestPathWeightedNegative.insert(0, 3, 1);
  singleSourceShortestPathWeightedNegative.insert(1, 3, 3);
  singleSourceShortestPathWeightedNegative.insert(3, 2, 2);
  singleSourceShortestPathWeightedNegative.insert(3, 4, 2);
  singleSourceShortestPathWeightedNegative.insert(3, 5, -8);
  singleSourceShortestPathWeightedNegative.insert(3, 6, 4);
  cout << "带负权值图" << endl;
  singleSourceShortestPathWeightedNegative.weightedNegative('2', INT_MAX);

  //有向图所有顶点对的最短路径
  cout << "所有顶点对的最短路径:" << endl;
  AdjMatrixGraph<char, int> allVertexPairShortestPath(3, "012", INT_MAX, true, true);
  allVertexPairShortestPath.insert(0, 1, 8);
  allVertexPairShortestPath.insert(1, 0, 3);
  allVertexPairShortestPath.insert(0, 2, 5);
  allVertexPairShortestPath.insert(2, 0, 6);
  allVertexPairShortestPath.insert(2, 1, 2);
  allVertexPairShortestPath.floyd();

  int ttt = 0;
  return 0;
}
时间: 2024-08-11 00:29:41

图的实现、无向图的最小生成树、有向图的最短路径的相关文章

POJ 1734 无向图最小环/有向图最小环

给定一张图,求图中一个至少包含三个点的环,环上的点不重复,并且环上的边的长度之和最小. 点数不超过100个 输出方案 无向图: 1 /*Huyyt*/ 2 #include<bits/stdc++.h> 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 #define pb push_back 5 using namespace std; 6 typedef long long ll; 7 typedef unsigned long long ull; 8

图的基本算法(最小生成树)

假设以下情景,有一块木板.板上钉上了一些钉子.这些钉子能够由一些细绳连接起来.假设每一个钉子能够通过一根或者多根细绳连接起来.那么一定存在这种情况,即用最少的细绳把全部钉子连接起来. 更为实际的情景是这种情况.在某地分布着N个村庄.如今须要在N个村庄之间修路,每一个村庄之前的距离不同,问怎么修最短的路,将各个村庄连接起来. 以上这些问题都能够归纳为最小生成树问题,用正式的表述方法描写叙述为:给定一个无方向的带权图G=(V, E),最小生成树为集合T, T是以最小代价连接V中全部顶点所用边E的最小

基于无向图且权重单一的最短路径Dijkstra算法——JAVA实现

做一个无向图的权重单一的最短路径算法. 模拟停车场最近车位的选择. 首先参考了博友JavaMan_chen的博文 http://blog.csdn.net/javaman_chen/article/details/8254309 但是这个算法是有问题的. 算法中,如果A点是当前点,是选取距离A点权重最小的那一点作为下一个路径点的. 这就带来了一个问题,即,距离A点的2个点如果权重相同,那就会随机选取其中一条. 于是,在数据量稍微大点的时候,就出错了. 在这里使用Dijkstra算法使用的是用OP

数据结构基础温故-5.图(中):最小生成树算法

图的“多对多”特性使得图在结构设计和算法实现上较为困难,这时就需要根据具体应用将图转换为不同的树来简化问题的求解. 一.生成树与最小生成树 1.1 生成树 对于一个无向图,含有连通图全部顶点的一个极小连通子图成为生成树(Spanning Tree).其本质就是从连通图任一顶点出发进行遍历操作所经过的边,再加上所有顶点构成的子图. 采用深度优先遍历获得的生成树称为深度优先生成树(DFS生成树),采用广度优先遍历获得的生成树称为广度优先生成树(BFS生成树).如下图所示,无向图的DFS生成树和BFS

畅通工程 (最小生成树)(最短路径和)

Problem Description 省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可).经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本.现请你编写程序,计算出全省畅通需要的最低成本.   Input 测试输入包含若干测试用例.每个测试用例的第1行给出评估的道路条数 N.村庄数目M ( < 100 ):随后的 N行对应村庄间道路的成本,每行给出一对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也

golang 实现斐波那契堆

二叉堆提供了o(lgn) 时间的插入, 删除最小,降级等操作,o(n) 时间的合并操作;  斐波那契堆提供了更优操作时间界限:o(1) 插入, o(lgn) 删除最小, o(lgn) 删除, o(1)合并. 根据算法导论上说,斐波那契堆在删除最小或删除操作被执行次数相比其他操作少得多时,尤为适用.一些图的算法中(计算最小生成树,单源最短路径)作为基本构建块(作为优先队用). 考虑到斐波那契堆实现的复杂,可能二叉堆在实践上更具可用性.就像rob pike 在 <notes on programmi

朱刘算法 有向图定根的最小生成树poj3164

关于为什么不能用Prim求解此类问题,如下 Prim可以看成是维护两个顶点集或者看成维护一颗不断生成的树(感觉前一种说法好一点) 倘若是有向图有三个顶点1.2.3 边的情况如下 1->2:          5 1->3:         6 2->3:       1000861 3->2:         2 显然若是按照Prim算法来说,先将顶点一压入集合.而后顺势找到最小的顶点2,然后1.2中到三的最短边是1000861,那么花费就是1000866,显然不对的.: 而若是无

PGM——从有向图到无向图的转化(moralization)

在解决实际问题的过程中我们经常需要将有向图(directed graph)转化成一个与之对应的无向图(undirected graph),但是相同结构的有向图和无向图能够表达的变量间的独立性是不同的,如何将一个有向图转化成一个无向图,这个无向图最大化的表达了原来的信息,又尽量少地丢失有向图里包含的条件独立性呢? 首先从一个straightforward的例子说起: 有向图(a)的联合分布是一系列条件概率因子的乘积: 转化成无向图如(b)所示,很简单,这个无向图中的maximal cliques就

图基本算法 最小生成树 Prim算法(邻接表+优先队列STL)

这篇文章是对<算法导论>上Prim算法求无向连通图最小生成树的一个总结,其中有关于我的一点点小看法. 最小生成树的具体问题可以用下面的语言阐述: 输入:一个无向带权图G=(V,E),对于每一条边(u, v)属于E,都有一个权值w. 输出:这个图的最小生成树,即一棵连接所有顶点的树,且这棵树中的边的权值的和最小. 举例如下,求下图的最小生成树: 这个问题是求解一个最优解的过程.那么怎样才算最优呢? 首先我们考虑最优子结构:如果一个问题的最优解中包含了子问题的最优解,则该问题具有最优子结构. 最小