C++实现有向图的邻接表表示

本文实例为大家分享了C++有向图的邻接表表示,供大家参考,具体内容如下

一、思路:

有向图的插入有向边、删除边、删除顶点和无向图的有区别。其他的和无向图的类似。

1.插入有向边<e1, e2>

只需要插入<e1, e2>边就行,不需要插入对称边<e2, e1>

2.删除边<e1,e2>:

只需要删除<e1, e2>边就行,不需要仔找对称边<e2, e1>进行删除。

3.删除顶点v:

首先,要在邻接表中删除以v为头的边<v, w>;

同时,也要在邻接表中删除以v为尾的边<k, v>, 不能通过对称边来找,只能一个个顶点找,浪费时间。

二、实现程序

1.DirectedGraph.h:有向图

#ifndef DirectedGraph_h
#define DirectedGraph_h
#include <iostream>
using namespace std;

const int DefaultVertices = 30;

template <class T, class E>
struct Edge { // 边结点的定义
 int dest; // 边的另一顶点位置
 E cost; // 表上的权值
 Edge<T, E> *link; // 下一条边链指针
};

template <class T, class E>
struct Vertex { // 顶点的定义
 T data; // 顶点的名字
 Edge<T, E> *adj; // 边链表的头指针
};

template <class T, class E>
class Graphlnk {
public:
 const E maxValue = 100000; // 代表无穷大的值(=∞)
 Graphlnk(int sz=DefaultVertices); // 构造函数
 ~Graphlnk(); // 析构函数
 void inputGraph(); // 建立邻接表表示的图
 void outputGraph(); // 输出图中的所有顶点和边信息
 T getValue(int i); // 取位置为i的顶点中的值
 E getWeight(int v1, int v2); // 返回边(v1, v2)上的权值
 bool insertVertex(const T& vertex); // 插入顶点
 bool insertEdge(int v1, int v2, E weight); // 插入边
 bool removeVertex(int v); // 删除顶点
 bool removeEdge(int v1, int v2); // 删除边
 int getFirstNeighbor(int v); // 取顶点v的第一个邻接顶点
 int getNextNeighbor(int v,int w); // 取顶点v的邻接顶点w的下一邻接顶点
 int getVertexPos(const T vertex); // 给出顶点vertex在图中的位置
 int numberOfVertices(); // 当前顶点数
private:
 int maxVertices; // 图中最大的顶点数
 int numEdges; // 当前边数
 int numVertices; // 当前顶点数
 Vertex<T, E> * nodeTable; // 顶点表(各边链表的头结点)
};

// 构造函数:建立一个空的邻接表
template <class T, class E>
Graphlnk<T, E>::Graphlnk(int sz) {
 maxVertices = sz;
 numVertices = 0;
 numEdges = 0;
 nodeTable = new Vertex<T, E>[maxVertices]; // 创建顶点表数组
 if(nodeTable == NULL) {
  cerr << "存储空间分配错误!" << endl;
  exit(1);
 }
 for(int i = 0; i < maxVertices; i++)
  nodeTable[i].adj = NULL;
}

// 析构函数
template <class T, class E>
Graphlnk<T, E>::~Graphlnk() {
 // 删除各边链表中的结点
 for(int i = 0; i < numVertices; i++) {
  Edge<T, E> *p = nodeTable[i].adj; // 找到其对应链表的首结点
  while(p != NULL) { // 不断地删除第一个结点
   nodeTable[i].adj = p->link;
   delete p;
   p = nodeTable[i].adj;
  }
 }
 delete []nodeTable; // 删除顶点表数组
}

// 建立邻接表表示的图
template <class T, class E>
void Graphlnk<T, E>::inputGraph() {
 int n, m; // 存储顶点树和边数
 int i, j, k;
 T e1, e2; // 顶点
 E weight; // 边的权值

 cout << "请输入顶点数和边数:" << endl;
 cin >> n >> m;
 cout << "请输入各顶点:" << endl;
 for(i = 0; i < n; i++) {
  cin >> e1;
  insertVertex(e1); // 插入顶点
 }

 cout << "请输入图的各边的信息:" << endl;
 i = 0;
 while(i < m) {
  cin >> e1 >> e2 >> weight;
  j = getVertexPos(e1);
  k = getVertexPos(e2);
  if(j == -1 || k == -1)
   cout << "边两端点信息有误,请重新输入!" << endl;
  else {
   insertEdge(j, k, weight); // 插入边
   i++;
  }
 } // while
}

// 输出有向图中的所有顶点和边信息
template <class T, class E>
void Graphlnk<T, E>::outputGraph() {
 int n, m, i;
 T e1, e2; // 顶点
 E weight; // 权值
 Edge<T, E> *p;

 n = numVertices;
 m = numEdges;
 cout << "图中的顶点数为" << n << ",边数为" << m << endl;
 for(i = 0; i < n; i++) {
  p = nodeTable[i].adj;
  while(p != NULL) {
   e1 = getValue(i); // 有向边<i, p->dest>
   e2 = getValue(p->dest);
   weight = p->cost;
   cout << "<" << e1 << ", " << e2 << ", " << weight << ">" << endl;
   p = p->link; // 指向下一个邻接顶点
  }
 }
}

// 取位置为i的顶点中的值
template <class T, class E>
T Graphlnk<T, E>::getValue(int i) {
 if(i >= 0 && i < numVertices)
  return nodeTable[i].data;
 return NULL;
}

// 返回边(v1, v2)上的权值
template <class T, class E>
E Graphlnk<T, E>::getWeight(int v1, int v2) {
 if(v1 != -1 && v2 != -1) {
  Edge<T , E> *p = nodeTable[v1].adj; // v1的第一条关联的边
  while(p != NULL && p->dest != v2) { // 寻找邻接顶点v2
   p = p->link;
  }
  if(p != NULL)
   return p->cost;
 }
 return maxValue; // 边(v1, v2)不存在,就存放无穷大的值
}

// 插入顶点
template <class T, class E>
bool Graphlnk<T, E>::insertVertex(const T& vertex) {
 if(numVertices == maxVertices) // 顶点表满,不能插入
  return false;
 nodeTable[numVertices].data = vertex; // 插入在表的最后
 numVertices++;
 return true;
}

// 插入边
template <class T, class E>
bool Graphlnk<T, E>::insertEdge(int v1, int v2, E weight) {
 if(v1 >= 0 && v1 < numVertices && v2 >= 0 && v2 < numVertices) {
  Edge<T, E> *p = nodeTable[v1].adj; // v1对应的边链表头指针
  while(p != NULL && p->dest != v2) // 寻找邻接顶点v2
   p = p->link;
  if(p != NULL) // 已存在该边,不插入
   return false;
  p = new Edge<T, E>; // 创建新结点
  p->dest = v2;
  p->cost = weight;
  p->link = nodeTable[v1].adj; // 链入v1边链表
  nodeTable[v1].adj = p;
  numEdges++;
  return true;
 }
 return false;
}

// 有向图删除顶点较麻烦
template <class T, class E>
bool Graphlnk<T, E>::removeVertex(int v) {
 if(numVertices == 1 || v < 0 || v > numVertices)
  return false; // 表空或顶点号超出范围

 Edge<T, E> *p, *s;
 // 1.清除顶点v的边链表结点w 边<v,w>
 while(nodeTable[v].adj != NULL) {
  p = nodeTable[v].adj;
  nodeTable[v].adj = p->link;
  delete p;
  numEdges--; // 与顶点v相关联的边数减1
 } // while结束
 // 2.清除<w, v>,与v有关的边
 for(int i = 0; i < numVertices; i++) {
  if(i != v) { // 不是当前顶点v
   s = NULL;
   p = nodeTable[i].adj;
   while(p != NULL && p->dest != v) {// 在顶点i的链表中找v的顶点
    s = p;
    p = p->link; // 往后找
   }
   if(p != NULL) { // 找到了v的结点
    if(s == NULL) { // 说明p是nodeTable[i].adj
     nodeTable[i].adj = p->link;
    } else {
     s->link = p->link; // 保存p的下一个顶点信息
    }
    delete p; // 删除结点p
    numEdges--; // 与顶点v相关联的边数减1
   }
  }
 }
 numVertices--; // 图的顶点个数减1
 nodeTable[v].data = nodeTable[numVertices].data; // 填补,此时numVertices,比原来numVertices小1,所以,这里不需要numVertices-1
 nodeTable[v].adj = nodeTable[numVertices].adj;
 // 3.要将填补的顶点对应的位置改写
 for(int i = 0; i < numVertices; i++) {
  p = nodeTable[i].adj;
  while(p != NULL && p->dest != numVertices) // 在顶点i的链表中找numVertices的顶点
   p = p->link; // 往后找
  if(p != NULL) // 找到了numVertices的结点
   p->dest = v; // 将邻接顶点numVertices改成v
 }
 return true;
}

// 删除边
template <class T, class E>
bool Graphlnk<T, E>::removeEdge(int v1, int v2) {
 if(v1 != -1 && v2 != -1) {
  Edge<T, E> * p = nodeTable[v1].adj, *q = NULL;
  while(p != NULL && p->dest != v2) { // v1对应边链表中找被删除边
   q = p;
   p = p->link;
  }
  if(p != NULL) { // 找到被删除边结点
   if(q == NULL) // 删除的结点是边链表的首结点
    nodeTable[v1].adj = p->link;
   else
    q->link = p->link; // 不是,重新链接
   delete p;
   return true;
  }
 }
 return false; // 没有找到结点
}

// 取顶点v的第一个邻接顶点
template <class T, class E>
int Graphlnk<T, E>::getFirstNeighbor(int v) {
 if(v != -1) {
  Edge<T, E> *p = nodeTable[v].adj; // 对应链表第一个边结点
  if(p != NULL) // 存在,返回第一个邻接顶点
   return p->dest;
 }
 return -1; // 第一个邻接顶点不存在
}

// 取顶点v的邻接顶点w的下一邻接顶点
template <class T, class E>
int Graphlnk<T, E>::getNextNeighbor(int v,int w) {
 if(v != -1) {
  Edge<T, E> *p = nodeTable[v].adj; // 对应链表第一个边结点
  while(p != NULL && p->dest != w) // 寻找邻接顶点w
   p = p->link;
  if(p != NULL && p->link != NULL)
   return p->link->dest; // 返回下一个邻接顶点
 }
 return -1; // 下一个邻接顶点不存在
}

// 给出顶点vertex在图中的位置
template <class T, class E>
int Graphlnk<T, E>::getVertexPos(const T vertex) {
 for(int i = 0; i < numVertices; i++)
  if(nodeTable[i].data == vertex)
   return i;
 return -1;
}

// 当前顶点数
template <class T, class E>
int Graphlnk<T, E>::numberOfVertices() {
 return numVertices;
}

#endif /* DirectedGraph_h */

2.main.cpp

/*
 测试数据:
5 7
0 1 2 3 4
0 1 10
0 3 30
0 4 100
1 2 50
2 4 10
3 2 20
3 4 60
 */

#include "DirectedGraph.h"

int main(int argc, const char * argv[]) {
 Graphlnk<char, int> st; // 声明对象
 bool finished = false;
 int choice;
 char e1, e2, next;
 int weight;

 while(!finished) {
  cout << "[1]创建基于邻接表的有向图" << endl;
  cout << "[2]输出图的所有顶点和边信息" << endl;
  cout << "[3]取顶点v的第一个邻接顶点" << endl;
  cout << "[4]取v的邻接顶点w的下一个邻接顶点" << endl;
  cout << "[5]插入顶点" << endl;
  cout << "[6]插入边" << endl;
  cout << "[7]删除顶点" << endl;
  cout << "[8]删除边" << endl;
  cout << "[9]退出" << endl;
  cout << "请输入选择[1-9]:";
  cin >> choice;
  switch(choice) {
   case 1:
    st.inputGraph();
    break;
   case 2:
    st.outputGraph();
    break;
   case 3:
    cout << "请输入顶点:";
    cin >> e1;
    e2 = st.getValue(st.getFirstNeighbor(st.getVertexPos(e1)));
    if(e2)
     cout << "顶点" << e1 << "的第一个邻接顶点为:" << e2 << endl;
    else
     cout << "顶点" << e1 << "没有邻接顶点!" << endl;
    break;
   case 4:
    cout << "请输入顶点v和邻接顶点w:";
    cin >> e1 >> e2;
    next = st.getValue(st.getNextNeighbor(st.getVertexPos(e1), st.getVertexPos(e2)));
    if(next)
     cout << "顶点" << e1 << "的邻接顶点" << e2 << "的下一个邻接顶点为:" << next << endl;
    else
     cout << "顶点" << e1 << "的邻接顶点" << e2 << "没有下一个邻接顶点!" << endl;
    break;
   case 5:
    cout << "请输入要插入的顶点:";
    cin >> e1;
    if(st.insertVertex(e1))
     cout << "插入成功!" << endl;
    else
     cout << "表已满,插入失败!" << endl;
    break;
   case 6:
    cout << "请输入要插入的边的信息:" << endl;
    cin >> e1 >> e2 >> weight;
    st.insertEdge(st.getVertexPos(e1), st.getVertexPos(e2), weight);
    break;
   case 7:
    cout << "请输入要删除的顶点:";
    cin >> e1;
    if(st.removeVertex(st.getVertexPos(e1)))
     cout << "顶点" << e1 << "已删除!" << endl;
    else
     cout << "顶点" << e1 << "不在图中!" << endl;
    break;
   case 8:
    cout << "请输入要删除的边的两个端点:" << endl;
    cin >> e1 >> e2;
    st.removeEdge(st.getVertexPos(e1), st.getVertexPos(e2));
    break;
   case 9:
    finished = true;
    break;
   default:
    cout << "选择输入错误,请重新输入!" << endl;
  }
 }
 return 0;
}

测试结果:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++实现邻接表顶点的删除

    本文实例为大家分享了C++实现邻接表顶点的删除代码,供大家参考,具体内容如下 这里的边是无向边 删除顶点v时,要找到顶点v的邻接顶点w,把w中指向v的边删除掉,再删除边(v,w).循环这个过程,直到把和顶点v有关的边都删除掉为止. 再接着需要删除顶点v. 不可以直接像数组那样直接把顶点v之后的顶点位置像前移动一位,因为这样其他顶点的位置将会发生变化,顶点边中的顶点位置将会出错. 边和顶点的定义如下: struct Edge{//边节点的定义 int dest;//边的另一顶点位置 E cost;

  • C++数据结构之实现邻接表

    本文实例为大家分享了C++数据结构之实现邻接表的具体代码,供大家参考,具体内容如下 一.图的邻接表实现 1.实现了以顶点顺序表.边链表为存储结构的邻接表: 2.实现了图的创建(有向/无向/图/网).边的增删操作.深度优先递归/非递归遍历.广度优先遍历的算法: 3.采用顶点对象列表.边(弧)对象列表的方式,对图的创建进行初始化:引用 "ObjArrayList.h"头文件,头文件可参看之前博文"数据结构之顺序列表(支持对象元素)"代码: 4.深度优先遍历分别采用递归/

  • C++实现有向图的邻接表表示

    本文实例为大家分享了C++有向图的邻接表表示,供大家参考,具体内容如下 一.思路: 有向图的插入有向边.删除边.删除顶点和无向图的有区别.其他的和无向图的类似. 1.插入有向边<e1, e2> 只需要插入<e1, e2>边就行,不需要插入对称边<e2, e1> 2.删除边<e1,e2>: 只需要删除<e1, e2>边就行,不需要仔找对称边<e2, e1>进行删除. 3.删除顶点v: 首先,要在邻接表中删除以v为头的边<v, w&

  • C语言邻接表建立图详解

    目录 有向图 无向图 邻接表存图进行拓扑排序 总结 有向图 代码: #include<stdio.h> #include<stdlib.h> #include<string.h> #include<stack> using namespace std; #define maxn 200 int v, e; //表结点 typedef struct _Enode { int ivex; //该边所指向的节点位置 int value;//如果边有权值的话,就对其

  • C++实现有向图邻接表的构建

    本文实例为大家分享了C++实现有向图邻接表的构建代码,供大家参考,具体内容如下 数据结构里面的一道基础题,分享下自己的写法,验证可跑. #include<iostream> #include<string> const int MAX = 20; using namespace std; struct ArcNode { //弧结点 int adjvex = -1; //所指顶点位置 ArcNode *nextarc = nullptr; //下一条狐指针 size_t info

  • java实现图的邻接表存储结构的两种方式及实例应用详解

    前言 本篇来谈一谈图的邻接表实现的两种方式,首先我们明确一点"学会图的邻接表实现的关键点在于":你所建立的图的邻接表的对象是什么! 首先我们看一下<算法导论>中关于图的邻接表的定义: 图G=(V,E)的邻接表表示有一个包含 |V| 个列表的数组Adj所组成,其中每个列表对应于V中的一个顶点,对于每一个u∈V,邻接表Adj[u]包含所有满足条件(u,v)∈E的顶点v,亦即,Adj[u]包含图G中所有和顶点u相邻的顶点.(或者他也可能指向这些顶点的指针),每个邻接表中的顶点一般

  • Java用邻接表存储图的示例代码

    目录 一.点睛 1.无向图 2.无向图的链接表 3.说明 4.无向图 二.邻接表的数据结构 1.节点 2.邻接点 三.算法步骤 四.实现 五.测试 一.点睛 邻接表是图的一种链式存储方法,其数据结构包括两部分:节点和邻接点. 用邻接表可以表示无向图,有向图和网.在此用无向图进行说明. 1.无向图 2.无向图的链接表 3.说明 节点 a 的邻接点是节点 b.d,其邻接点的存储下标为1.3,按照头插法(逆序)将其放入节点 a 后面的单链表中. 节点 b 的邻接点是节点 a.c.d,其邻接点的存储下标

  • C/C++浅析邻接表拓扑排序算法的实现

    目录 前言 一.拓扑排序算法的思路 二.实现步骤 1.求个顶点的入度 2.拓扑排序的实现 三.测试结果 总结 前言 在软件开发.施工过程.教学安排等等的一系列活动中,往往需要一个有向无环图来表示其是否成成功进行下去. 在一个有向图为顶点表示活动的网中,我们称为AOV网(Activity On Vertex Network).设G={V,E}是一个具有n个顶点的有向图,V中的顶点序列v1,v2,…,vn,满足若从顶点vi到vj有一条路径,则在顶点序列中顶点vi必在vj之前.则我们称这样的顶点为一个

  • Python如何自定义邻接表图类

    目录 Python自定义邻接表图类 图抽象数据类型(ADT)的术语 邻接矩阵和邻接表的优缺点 自定义顶点类 python图的邻接表表示 总结 Python自定义邻接表图类 图抽象数据类型(ADT)的术语 顶点(Vertex):也称节点(node),是图的基础部分.具有名称标识“key”.顶点也可以有附加信息项“playload”. 边(Edge):也称弧(arc),也是图的基础组成部分.如果一条边连接两个顶点,则表示两者具有联系.边可以是单向的,也可以是双向的.如果图中的边都是单向的,则称这个图

  • python实现邻接表转邻接矩阵

    目录 python邻接表转邻接矩阵 图的存储—邻接矩阵与邻接表 邻接矩阵 邻接表 入度与出度 书面练习 编程练习 总结 python邻接表转邻接矩阵 闲话少说,前段时间看到有同学问怎么把邻接表转成邻接矩阵,想了想做了一下,仅供参考.= = _python 2.7 _ 包:networkX,numpy # coding:utf-8 #将一个图,network转换为邻接矩阵 import networkx  as nx import numpy as np G = nx.read_weighted_

  • 图的邻接表存储表示示例讲解

    复制代码 代码如下: //---------图的邻接表存储表示------- #include<stdio.h>#include<stdlib.h> #define MAX_VERTEXT_NUM 20 typedef int InfoType;typedef char VertextType; typedef struct ArcNode{    int adjvex;    struct ArcNode *nextArc;    InfoType *info;}ArcNode;

随机推荐