鄰接表和鄰接矩陣實現拓撲排序

先貼代碼, 先貼簡要的解釋,週末更新.

  • 鄰接表的實現
#ifndef __ADJ_GRAPH__
#define __ADJ_GRAPH__

#include <iostream>
#include <vector>

struct ArchNode {
  int adj_vertex;
  ArchNode* next;
};

struct VertexNode {
  int vertex_id;
  ArchNode* first;
  ArchNode* tail;
};

struct Arch {
  int beg_vnode_idx, end_vnode_idx;
  int weight;

  Arch(int i, int j, int w):
    beg_vnode_idx(i), end_vnode_idx(j),
    weight(w) {}
  Arch(const Arch& other) {
    if (this != &other) {
      beg_vnode_idx = other.beg_vnode_idx;
      end_vnode_idx = other.end_vnode_idx;
      weight = other.weight;
    }
   }

  std::pair<int, int> GetPair() {
    return std::make_pair(beg_vnode_idx, end_vnode_idx);
  }
  int GetWeight() {
    return weight;
  }
};

enum GraphType {
  UDG, // 無向圖;
  DG   // 有向圖;
};

template <unsigned T>
class AdjacentListGraph {
 public:
  AdjacentListGraph(GraphType graph_type, int e, int n = T);
  AdjacentListGraph(GraphType graph_type, int e, const std::vector<Arch>& arch_list);
  void CreateAdjacentList(GraphType g);
  void AddToArchList(Arch* arch) {
    arch_list_.push_back(arch);
  }   
  void InsertArch(int vertex_idx, int adjacent_node_idx);
  void MakeArchList(const std::vector<Arch>& arch_list);
  void MakeArchList(const std::pair<int, int>*, size_t);

  void TopologicalSort();
  
 private:
  VertexNode* vertex_nodes_;
  std::vector<Arch*> arch_list_;

  int vertex_num_;
  int arch_num_;
  GraphType graph_type_;
};

////////////////////////////////////////////////////////////////////////////////

template <unsigned T>
AdjacentListGraph<T>::AdjacentListGraph(GraphType graph_type, int e, int n) :
  vertex_num_(n),
  arch_num_(e),
  graph_type_(graph_type) {

  vertex_nodes_ = new VertexNode[vertex_num_];
  for (int i = 0; i < vertex_num_; ++i) {
    vertex_nodes_[i].vertex_id = i + 1;
    vertex_nodes_[i].first = nullptr;
    vertex_nodes_[i].tail = nullptr;
  }

  if (arch_num_ <= 0) return;
  
  std::cout << "input the arch data: (v1, v2, weight)" << std::endl;
  int i, j, w;
  int count = 0;
  while (count++ < arch_num_) {
    std::cin >> i >> j >> w;
    Arch* arch = new Arch(i, j, w);
    AddToArchList(arch); 
  }   
  CreateAdjacentList(graph_type_);         
}

template <unsigned T>
AdjacentListGraph<T>::AdjacentListGraph(GraphType graph_type, int e, const std::vector<Arch>& arch_list) :
  vertex_num_(T),
  arch_num_(e),
  graph_type_(graph_type) {
   
  vertex_nodes_ = new VertexNode[vertex_num_];
  for (int i = 0; i < vertex_num_; ++i) {
    vertex_nodes_[i].vertex_id = i + 1;
    vertex_nodes_[i].first = nullptr;
    vertex_nodes_[i].tail = nullptr;
  }

  if (arch_num_ <= 0) return;
  
  MakeArchList(arch_list);
  CreateAdjacentList(graph_type_);         
}

template <unsigned T>
void AdjacentListGraph<T>::MakeArchList(const std::vector<Arch>& arch_list) {
  for (auto archItem : arch_list) {
    auto arch =  new Arch(archItem);
    AddToArchList(arch);
  } 
}

template <unsigned T>
void AdjacentListGraph<T>::MakeArchList(const std::pair<int, int>* arch_list, size_t size)  {
  for (unsigned int i = 0; i < size; ++i) {
    auto arch = new Arch(arch_list[i].first, arch_list[i].second, 0);
    AddToArchList(arch);
  }
}

template <unsigned T>
void AdjacentListGraph<T>::CreateAdjacentList(GraphType t) {
  for (auto arch : arch_list_) {
    auto pair = arch->GetPair();
    // std::cout << "pair.first=" << pair.first << ", pair.second=" << pair.second;
    int head = pair.first, end = pair.second;
    InsertArch(head, end);
    if (t == UDG) {
      InsertArch(end, head);
    }  
  } 
}

template <unsigned T>
void AdjacentListGraph<T>::InsertArch(int vertex_idx, int adjacent_node_idx) {
  ArchNode* a = new ArchNode{adjacent_node_idx, nullptr};
  VertexNode& v = vertex_nodes_[vertex_idx - 1];
  v.tail == nullptr ? v.first = a : v.tail->next = a;
  v.tail = a;
}

template <unsigned T>
void AdjacentListGraph<T>::TopologicalSort() {
  const size_t n = vertex_num_;
  int in_degree[n] = {0};
  std::vector<int> result;

  // initialize in_degree array, set up the in_degree array
  for (int i = 0; i < vertex_num_; ++i) {
    auto& m = vertex_nodes_[i];
    ArchNode* x = m.first;
    if (x == nullptr)
      continue;
    int j = x->adj_vertex;
    ++in_degree[j - 1];
    while ((x = x->next)) {
      j = x->adj_vertex;
      ++in_degree[j - 1]; 
    }
  } 
 
  int count = 0;
  while (count++ < vertex_num_) { 
    
    // find the node that its in-degree is 0;
    int start_idx = -1;
    for (int j = 0; j < vertex_num_; ++j) {
      if (in_degree[j] == 0) {
        start_idx = j;
        break;
      }
    }
    
    // when execute to some point, there is no node whose in-degree
    // is 0, we quit from the loop;
    if (start_idx == -1)
      break;
    result.push_back(start_idx);

    ArchNode* a = vertex_nodes_[start_idx].first;
    while (a) {
      in_degree[a->adj_vertex - 1]--;
      a = a->next;
    }
    in_degree[start_idx] = -1;
  }
  
  if (count < vertex_num_)
    std::cout << "not fully resolved DAG" << std::endl;
 
  std::cout << "Topological sort result is:";
  for (auto it : result) {
    int k = it;
    std::cout << k + 1 << " ";
  }
  std::cout << std::endl;   
}

#endif

測試:

#include <iostream>
#include <vector>
#include "adj_graph.h"

int main() {
  Arch dag_arches[] = {
    {1, 2, 0}, {1, 4, 0}, {2, 4, 0}, {2, 3, 0},
    {3, 5, 0}, {4, 3, 0}, {4, 5, 0}
  };
  AdjacentListGraph<5> dag(DG, sizeof(dag_arches), std::vector<Arch>(std::begin(dag_arches), std::end(dag_arches)));
  dag.TopologicalSort();   
  
  return 0;
}
  • 鄰接矩陣的實現

    • matrix_graph.h 頭文件
#include <iostream>
#include <unordered_map>

enum GraphType {
  DG, // 有向圖
  UDG // 無向圖
};

struct Arch {
  int beg_vertex_idx;
  int end_vertex_idx;
  int weight;

  Arch(int i, int j, int w):
    beg_vertex_idx(i), end_vertex_idx(j),
    weight(w) {}
  Arch(const Arch& other) {
    if (this != &other) {
      beg_vertex_idx = other.beg_vertex_idx;
      end_vertex_idx = other.end_vertex_idx;
      weight = other.weight;
    }
   }

  std::pair<int, int> GetPair() {
    return std::make_pair(beg_vertex_idx, end_vertex_idx);
  }
  int GetWeight() {
    return weight;
  }
};

struct VertexNode {
  int vertex_id; 
};

class ADJMatrixGraph {
 public:
  ADJMatrixGraph(GraphType type, const int vertex_num, struct Arch arch_list[], const int arch_num);
  
  void print_matrix();
  void TopologicalSort();

 private:
  void AddToArchList(Arch arch) {
    std::pair<int, int> arch_pair = arch.GetPair();
    std::string s = std::to_string(arch_pair.first - 1) + "_" + std::to_string(arch_pair.second - 1);
    arch_list_.insert(std::make_pair(s, arch));
  }
  void MakeArchList(struct Arch arch_list[], size_t arch_num);
  void CreateADJMatrixGraph(GraphType);

  GraphType graph_type_;
  int vertex_num_;
  int arch_num_;
  VertexNode* vertex_nodes_;
  std::unordered_map<std::string, Arch> arch_list_;
  void* matrix_;
};

matrix_graph.cc

#include <stdio.h>
#include <vector>
#include "matrix_graph.h"

ADJMatrixGraph::ADJMatrixGraph(GraphType type, const int vertex_num, struct Arch arch_list[], const int arch_num):
  graph_type_(type),
  vertex_num_(vertex_num),
  arch_num_(arch_num),
  vertex_nodes_(new VertexNode[vertex_num]) {
  MakeArchList(arch_list, arch_num);
  CreateADJMatrixGraph(type);
}

void ADJMatrixGraph::MakeArchList(struct Arch arch_list[], size_t arch_num) {
  for (unsigned int i = 0; i < arch_num; ++i) {
    auto arch = arch_list[i];
    AddToArchList(arch);
    
    // auto p = arch.GetPair();
    // int z = p.first, y = p.second;
    if (graph_type_ == UDG) {
      // TODO(cangpeng): to handle symmetrics arch for UDG
    }
  }
}

void ADJMatrixGraph::print_matrix() {
  int n = vertex_num_;
  int (*matrix_arr)[n][n] = static_cast<int (*)[n][n]>(matrix_);

  for (int i = 0; i < n; ++i) {
    std::cout << "\ni=" << i << ":"; 
    for (int j = 0; j < n; ++j) {
      std::cout << *(*(*matrix_arr + i) + j) << " ";
    }
  }
  std::cout << std::endl;
}

void ADJMatrixGraph::CreateADJMatrixGraph(GraphType type) {
  int n = vertex_num_;
  void* matrix = malloc(sizeof(int) * n * n);
  int (*matrix_arr)[n][n] = static_cast<int (*)[n][n]>(matrix);
  
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      std::string s = std::to_string(i) + "_" + std::to_string(j);
      auto archIt = arch_list_.find(s);
      if (archIt != arch_list_.end())  {
        *(*(*matrix_arr + i) + j) = (archIt->second).GetWeight();
      } else {
        *(*(*matrix_arr + i) + j) = 0;
      }
    } 
  }
  matrix_ = matrix;
}

void ADJMatrixGraph::TopologicalSort() {
  const size_t n = vertex_num_;
  // using matrix_arr = int[n][n];

  int in_degree[n] = {0};
  std::vector<int> result;
  // matrix_arr* matrix = static_cast<matrix_arr*>(matrix_);
  int (*matrix)[n][n] = static_cast<int (*)[n][n]>(matrix_);
   
  // initialize in_degree array, set  up the in_degree array;
  for (unsigned int i = 0; i < n; ++i) {
    for (unsigned int j = 0; j < n; ++j) {
      // std::cout << "matrix:" << i << ", " << j << ":"
        // << *(*(*matrix + i) + j) << ", " << matrix[i][j] << std::endl;
      if (*(*(*matrix + i) + j) > 0) {
        in_degree[j]++;
      }
    }
  }
  
  unsigned int count = 0;
  while (count++ < n) {
    
    int start_idx = -1;
    for (unsigned int j = 0; j < n; ++j) {
      if (in_degree[j] == 0) {
        start_idx = j;
        break;
      }
    }
    // when execute to some point, there is no node whose in-degree
    // is 0, we quit from the loop;
    if (start_idx == -1)
      break;
    result.push_back(start_idx);

    for (unsigned int k = 0; k < n; ++k) {
      // if (matrix[start_idx][k] > 0) {
      if (*(*(*matrix + start_idx) + k) > 0) {
        in_degree[k]--;
      }
    }
    in_degree[start_idx] = -1;
  }

  if (count < n)
    std::cout << "not fully resolved DAG" << std::endl;

  std::cout << "Topological sort result is:";
  for (auto it : result) {
    int k = it;
    std::cout << k + 1 << " ";
  }
  std::cout << std::endl;   
}

測試

#include "matrix_graph.h"

int main() {
  struct Arch dag_arches[] = {
    {1, 2, 1}, {1, 4, 1}, {2, 4, 1}, {2, 3, 1},
    {3, 5, 1}, {4, 3, 1}, {4, 5, 1}
  };
  
  ADJMatrixGraph matrix_graph(DG, 5, dag_arches, 7);
  matrix_graph.print_matrix();
  matrix_graph.TopologicalSort();
  return 0;
}

踩坑

  • 用nontype template實現鄰接表。 注意template的類實現,在真正出創建template實例的對象之前,不會真正實例化template類, 也就沒有符號表中某些元素, 如template類的構造函數; 只有在創建template類的定義時, 纔會在.o文件中出現該符號; 忽略此點, 很容易出現不理解的undefined reference to xxx錯誤;
  • 由於以上此點約束, 使用template類常常只有把全部實現寫在.h文件中; 這樣不利於模塊化代碼;
  • 鄰接矩陣實現使用malloc; 在gdb中輸出using過的type是有問題的; 需要使用原始的指針定義;

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章