无向图的邻接矩阵和邻接表实现各种操作 -- C++语言描述
2016-08-16 19:00
369 查看
一:实现代码
#ifndef _GRAPH_H #define _GRAPH_H #include <iostream> #include <string.h> using namespace::std; /////////////////////////////////////////////////////////////////////////////////////////// //通用图结构 template <typename T> class graph{ public: bool is_empty()const; bool is_full()const; int get_numvertices()const; //当前顶点数 int get_numedges()const; //当前边数 public: virtual bool insert_vertex(const T&) = 0; //插入顶点 virtual bool insert_edge(const T&, const T&) = 0; //插入边 virtual bool remove_vertex(const T&) = 0; //删除定点 virtual bool remove_edge(const T&, const T&) = 0; //删除边 virtual int get_firstneighbor(const T&)const = 0; //得到第一个邻接顶点 virtual int get_nextneighbor(const T&, const T&)const = 0; //某邻接顶点的下一个邻接顶点 virtual void print_graph()const = 0; virtual int get_vertex_index(const T&)const = 0; //得到顶点序号 protected: static const int VERTICES_DEFAULT_SIZE = 10; //默认图顶点数 int max_vertices; int num_vertices; int num_edges; }; template <typename T> bool graph<T>::is_empty()const { return num_edges == 0; } template <typename T> bool graph<T>::is_full()const { return num_vertices >= max_vertices || num_edges >= max_vertices*(max_vertices-1)/2; //判满,分为顶点满和边满 } template <typename T> int graph<T>::get_numvertices()const { return num_vertices; } template <typename T> int graph<T>::get_numedges()const { return num_edges; } /////////////////////////////////////////////////////////////////////////////////////////// #define VERTICES_DEFAULT_SIZE graph<T>::VERTICES_DEFAULT_SIZE //派生类继承父类,若父类为模板,派生类不可直接调用父类保护成员 #define num_vertices graph<T>::num_vertices //以宏来代替每个位置写作用域的做法 #define num_edges graph<T>::num_edges #define max_vertices graph<T>::max_vertices //另一种方法派生类内定义自己成员函数,可用using graph<T>::num_edges,在类外则不可 /////////////////////////////////////////////////////////////////////////////////////////// //图的邻接矩阵表示法 template <typename T> class graph_mtx : public graph<T>{ public: graph_mtx(int); graph_mtx(int (*)[4], const int); //矩阵构造 ~graph_mtx(); public: bool insert_vertex(const T&); bool insert_edge(const T&, const T&); bool remove_vertex(const T&); bool remove_edge(const T&, const T&); int get_firstneighbor(const T&)const; int get_nextneighbor(const T&, const T&)const; int get_vertex_index(const T&)const; void print_graph()const; private: T* vertices_list; //顶点线性表 int **edge; //内部矩阵 }; template <typename T> graph_mtx<T>::graph_mtx(int sz = VERTICES_DEFAULT_SIZE) { max_vertices = sz > VERTICES_DEFAULT_SIZE ? sz : VERTICES_DEFAULT_SIZE; vertices_list = new T[max_vertices]; edge = new int*[max_vertices]; //动态申请二维数组 for(int i=0; i<max_vertices; ++i){ edge[i] = new int[max_vertices]; memset(edge[i], 0, sizeof(int)*max_vertices); //清空图 } num_vertices = 0; num_edges = 0; } template <typename T> graph_mtx<T>::graph_mtx(int (*mt)[4], const int arr_size) { int edge_count = 0; max_vertices = arr_size > VERTICES_DEFAULT_SIZE ? arr_size : VERTICES_DEFAULT_SIZE; vertices_list = new T[max_vertices]; edge = new int*[max_vertices]; for(int i=0; i<max_vertices; ++i){ edge[i] = new int[max_vertices]; memset(edge[i], 0, sizeof(int)*max_vertices); } for(int i=0; i<arr_size; ++i) for(int j=0; j<arr_size; ++j){ edge[i][j] = mt[i][j]; if(mt[i][j] != 0) ++edge_count; } num_vertices = arr_size; num_edges = edge_count / 2; } template <typename T> graph_mtx<T>::~graph_mtx() { for(int i=0; i<max_vertices; ++i) delete []edge[i]; //分别析构,再总析构 delete edge; delete []vertices_list; } template <typename T> bool graph_mtx<T>::insert_vertex(const T& vert) { if(this->is_full()) //派生类函数调用父类函数,用this或加作用域 return false; vertices_list[num_vertices++] = vert; return true; } template <typename T> bool graph_mtx<T>::insert_edge(const T& vert1, const T& vert2) { if(this->is_full()) //判满 return false; int index_v1 = get_vertex_index(vert1); //得到顶点序号 int index_v2 = get_vertex_index(vert2); if(index_v1 == -1 || index_v2 == -1 ) return false; edge[index_v1][index_v2] = edge[index_v2][index_v1] = 1; //无向图 ++num_edges; return true; } template <typename T> bool graph_mtx<T>::remove_vertex(const T& vert) //用最后一个节点直接覆盖删除的节点,转化为删除最后一个节点 { int edge_count = 0; int index = get_vertex_index(vert); if(index == -1) return false; for(int i=0; i<num_vertices; ++i){ if(edge[index][i] != 0) ++edge_count; } if(index != num_vertices-1){ vertices_list[index] = vertices_list[num_vertices-1]; for(int i=0; i<num_vertices; ++i){ //此处两个循环不可合并,因为要分别执行,否则右下角数据出错 edge[index][i] = edge[num_vertices-1][i]; } for(int i=0; i<num_vertices; ++i){ edge[i][index] = edge[i][num_vertices-1]; } } for(int i=0; i<num_vertices; ++i){ edge[num_vertices-1][i] = 0; edge[i][num_vertices-1] = 0; } --num_vertices; num_edges -= edge_count; return true; } template <typename T> bool graph_mtx<T>::remove_edge(const T& vert1, const T& vert2) { int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 == -1 || index_v2 == -1) return false; edge[index_v1][index_v2] = edge[index_v2][index_v1] = 0; --num_edges; return true; } template <typename T> int graph_mtx<T>::get_firstneighbor(const T& vert)const { int index = get_vertex_index(vert); if(index != -1){ for(int i=0; i<num_vertices; ++i){ if(edge[index][i] != 0) return i; } } return -1; } template <typename T> int graph_mtx<T>::get_nextneighbor(const T& vert1, const T& vert2)const { int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 != -1 && index_v2 != -1){ for(int i=index_v2+1; i<num_vertices; ++i){ if(edge[index_v1][i] != 0) return i; } } return -1; } template <typename T> int graph_mtx<T>::get_vertex_index(const T& vert)const { for(int i=0; i<num_vertices; ++i){ if(vertices_list[i] == vert) return i; } return -1; } template <typename T> void graph_mtx<T>::print_graph()const { if(this->is_empty()){ cout << "nil graph" << endl; //空图输出nil return; } for(int i=0; i<num_vertices; ++i){ cout << vertices_list[i] << " "; } cout << endl; for(int i=0; i<num_vertices; ++i){ for(int j=0; j<num_vertices; ++j) cout << edge[i][j] << " "; cout << vertices_list[i] << endl; } } /////////////////////////////////////////////////////////////////////////////////////////// //图的邻接表表示法 template <typename T> struct node{ //节点用来存储与它相连接的顶点 int dest; struct node* link; node(int d) : dest(d), link(nullptr) {} }; template <typename T> struct vertex{ //顶点结构体 T vert; //顶点 struct node<T>* adj; //指向描述其他节点的链表 vertex() : vert(T()), adj(nullptr) {} }; template <typename T> class graph_lnk : public graph<T>{ public: graph_lnk(int); ~graph_lnk(); public: bool insert_vertex(const T& vert); bool insert_edge(const T& vert1, const T& vert2); bool remove_vertex(const T& vert); bool remove_edge(const T& vert1, const T& vert2); int get_firstneighbor(const T& vert)const; int get_nextneighbor(const T& vert1, const T& vert2)const; void print_graph()const; int get_vertex_index(const T& vert)const; protected: void remove_point_self(const int, const int); void modify_point_self(const int, const int, const int); private: vertex<T>* vertices_table; }; template <typename T> graph_lnk<T>::graph_lnk(int sz = VERTICES_DEFAULT_SIZE) { max_vertices = sz > max_vertices ? sz : VERTICES_DEFAULT_SIZE; vertices_table = new vertex<T>[max_vertices]; //不用再清空,结构体构造函数已清空 num_vertices = 0; num_edges = 0; } template <typename T> graph_lnk<T>::~graph_lnk() { for(int i=0; i<max_vertices; ++i){ auto tmp = vertices_table[i].adj; auto next_tmp = tmp; while(tmp != nullptr){ //删除节点 next_tmp = tmp->link; delete tmp; tmp = next_tmp; } } delete []vertices_table; //删除表 } template <typename T> bool graph_lnk<T>::insert_vertex(const T& vert) { if(this->is_full()) return false; vertices_table[num_vertices++].vert = vert; return true; } template <typename T> bool graph_lnk<T>::insert_edge(const T& vert1, const T& vert2) { if(this->is_full()) return false; int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 == -1 || index_v2 == -1) return false; auto tmp = vertices_table[index_v1].adj; while(tmp != nullptr){ if(tmp->dest == index_v2) return false; tmp = tmp->link; } tmp = new node<T>(index_v2); //采用前插法,比尾插法效率高,省事 tmp->link = vertices_table[index_v1].adj; vertices_table[index_v1].adj = tmp; tmp = new node<T>(index_v1); tmp->link = vertices_table[index_v2].adj; vertices_table[index_v2].adj = tmp; ++num_edges; return true; } template <typename T> bool graph_lnk<T>::remove_vertex(const T& vert) { int index = get_vertex_index(vert); int edge_count = 0; if(index == -1) return false; auto tmp = vertices_table[index].adj; auto next_tmp = tmp; while(tmp != nullptr){ remove_point_self(index, tmp->dest); //删除目标顶点指向自己的节点 ++edge_count; //记录边数 next_tmp = tmp->link; delete tmp; tmp = next_tmp; } if(index != num_vertices-1){ vertices_table[index].adj = vertices_table[num_vertices-1].adj; //用最后一个顶点覆盖要删除的顶点 vertices_table[index].vert = vertices_table[num_vertices-1].vert; } tmp = vertices_table[index].adj; while(tmp != nullptr){ modify_point_self(tmp->dest, num_vertices-1, index); //调整原指向最后一个顶点的节点,使其指向新的位置 tmp = tmp->link; } --num_vertices; num_edges -= edge_count; return true; } template <typename T> bool graph_lnk<T>::remove_edge(const T& vert1, const T& vert2) { int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 == -1 || index_v2 == -1) return false; remove_point_self(index_v1, index_v2); //相互删除指向自己的节点,相当于删除边 remove_point_self(index_v2, index_v1); return true; } template <typename T> int graph_lnk<T>::get_firstneighbor(const T& vert)const { int index = get_vertex_index(vert); if(index != -1 && vertices_table[index].adj != nullptr){ //第一个结点即为所求 return vertices_table[index].adj->dest; } return -1; } template <typename T> int graph_lnk<T>::get_nextneighbor(const T& vert1, const T& vert2)const //目标结点的下一个邻接节点即为所求 { int index_v1 = get_vertex_index(vert1); int index_v2 = get_vertex_index(vert2); if(index_v1 != -1 && index_v2 != -1){ auto tmp = vertices_table[index_v1].adj; while(tmp != nullptr && tmp->dest != index_v2) tmp = tmp->link; if(tmp->dest == index_v2 && tmp->link != nullptr) return tmp->link->dest; } return -1; } template <typename T> void graph_lnk<T>::remove_point_self(const int self_index, const int other_index) //删除指向自己的结点 { auto tmp = vertices_table[other_index].adj; auto pre_tmp = tmp; while(tmp->dest != self_index){ pre_tmp = tmp; tmp = tmp->link; } if(pre_tmp == tmp) vertices_table[other_index].adj = tmp->link; else pre_tmp->link = tmp->link; delete tmp; } template <typename T> void graph_lnk<T>::modify_point_self(const int other_index, const int old_index, const int new_index) //调整原指向最后一个顶点的节点,使其指向新的位置 { auto tmp = vertices_table[other_index].adj; while(tmp->dest != old_index){ tmp = tmp->link; } tmp->dest = new_index; } template <typename T> int graph_lnk<T>::get_vertex_index(const T& vert)const { for(int i=0; i<num_vertices; ++i){ if(vertices_table[i].vert == vert) return i; } return -1; } template <typename T> void graph_lnk<T>::print_graph()const { if(this->is_empty()){ cout << "nil graph" << endl; return ; } for(int i=0; i<num_vertices; ++i){ cout << vertices_table[i].vert << " : "; auto tmp = vertices_table[i].adj; while(tmp != nullptr){ cout << tmp->dest << "-->"; tmp = tmp->link; } cout << "nil" << endl; } } #endif
二:相关测试代码
1.邻接矩阵测试代码#include "graph.h" #define VERTEX_SIZE 4 int main() { int mtx[][VERTEX_SIZE] = {{0,1,0,1}, {1,0,1,0}, {0,1,0,1}, {1,0,1,0}}; //graph_mtx<int> gm(mtx, VERTEX_SIZE); graph_mtx<char> gm; gm.insert_vertex('A'); gm.insert_vertex('B'); gm.insert_vertex('C'); gm.insert_vertex('D'); gm.insert_edge('A', 'B'); gm.insert_edge('A', 'D'); gm.insert_edge('B', 'C'); gm.insert_edge('C', 'D'); //cout << gm.get_firstneighbor('A') << endl; //cout << gm.get_nextneighbor('A', 'B') << endl; //gm.remove_vertex('B'); gm.remove_edge('A', 'B'); gm.print_graph(); return 0; }*/
部分测试结果:
2.邻接表测试代码
#include "graph.h" #define VERTEX_SIZE 4 int main() { graph_lnk<char> gl; gl.insert_vertex('A'); gl.insert_vertex('B'); gl.insert_vertex('C'); gl.insert_vertex('D'); gl.insert_edge('A','B'); gl.insert_edge('A','C'); gl.insert_edge('B','D'); gl.print_graph(); cout << "-------------after remove-------------" << endl; gl.remove_vertex('A'); gl.print_graph(); //gl.remove_edge('A', 'B'); //gl.print_graph(); cout << gl.get_firstneighbor('A') << endl; cout << gl.get_nextneighbor('A', 'C') << endl; return 0; }
部分测试结果:
上文所有代码均经过测试,图中并未给全。
相关文章推荐
- 十字链表 邻接表实现各种操作
- 用C++语言创建一棵二叉树及实现二叉树的各种操作
- java实现对文件的各种操作
- 数据库操作基类,实现对Sql数据库的各种操作.
- 图的基本算法实现(邻接矩阵与邻接表两种方法)
- 一个javabean轻松实现对数据库的各种操作
- 详解JAVA POI导出EXCEL报表的操作(包括各种格式及样式的实现)
- 一个javabean轻松实现对数据库的各种操作
- 图的基本算法实现(邻接矩阵与邻接表两种方法)
- 链表的各种操作实现 链表逆序 链表排序 有序链表归并 链表存在环的判定
- java实现对文件的各种操作(转)
- 数据库操作基类,实现对Sql数据库的各种操作.
- 图的遍历和生成树求解实现|图遍历,生成树,实现,邻接矩阵,邻接表,深度广度遍历,最小生成树
- 用C#实现对目录,文件的各种操作
- 图的基本算法实现(邻接矩阵与邻接表两种方法)
- java实现对文件的各种操作
- 用C++语言实现目录文件的非递归遍历并用仿函数来进行文件操作
- 该文简要描述了DOM概念和内部逻辑结构,给出了DOM文档操作和XML文件互相转换java实现过程。
- 图的基本算法实现(邻接矩阵与邻接表两种方法)
- 一个javabean轻松实现对数据库的各种操作