邻接表:构造只有顶点没有边的图

84 篇文章 5 订阅
67 篇文章 2 订阅

问题描述 :

目的:使用C++模板设计并逐步完善图的邻接表抽象数据类型(ADT)。

内容:(1)请参照图的邻接矩阵模板类原型,设计并逐步完善图的邻接表ADT。(由于该环境目前仅支持单文件的编译,故将所有内容都集中在一个源文件内。在实际的设计中,推荐将抽象类及对应的派生类分别放在单独的头文件中。)

(2)使用构造函数,构造一个只有结点没有边的图。

注意:DG(有向图), DN(有向网), UDG(无向图), UDN(无向网)

参考函数原型:

/

/构造函数构造一个只有结点没有边的图。3个参数的含义:图的类型、结点数、结点值 

template<class TypeOfVer, class TypeOfEdge>

adjlist_graph<TypeOfVer, TypeOfEdge>::adjlist_graph( const string &kd, int vSize, const TypeOfVer d[]);

输入说明 :

第一行:图的类型

第二行:顶点数

第三行:顶点集

输出说明 :

第一行:图的类型

第二行:顶点集

第三行:邻接表

输入范例 :
UDG
6
A B C D E F
输出范例 :
UDG
A B C D E F
A
B
C
D
E
F
基本知识
  • 顶点表:表头向量成为顶点表
  • 边表:邻接表称为边表
  • 图示
    在这里插入图片描述
  • 顶点的构成

在这里插入图片描述

  • 边表的构成

在这里插入图片描述

实现伪码

在这里插入图片描述

  • 边表结点的ADT:
/*
	参数:data表示邻接顶点的位置
		 weight表示与边有关的权值,如边长等信息
		 *next表示指向下一个邻接顶点的指针
*/
template<class TypeOfEdge>
struct edgeNode
{

    int data;

    TypeOfEdge weight;

    edgeNode<TypeOfEdge> *next;

    edgeNode(const int &d, edgeNode<TypeOfEdge> *ptr = NULL) //构造函数,用于构造其他结点(无权图) 

    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面

    {

        next = ptr;

        data = d;

    }

    edgeNode(const int &d, const TypeOfEdge &w, edgeNode<TypeOfEdge> *ptr = NULL) //构造函数,用于构造其他结点(带权图) 

    //函数参数表中的形参允许有默认值,但是带默认值的参数需要放后面

    {

        next = ptr;

        data = d;

        weight = w;

    }

    int getData(){ return data;}  //取得结点的序号(顶点集) 

    TypeOfEdge getWeight(){ return weight;}  //取得边集中对应边的权值 

    void SetLink( edgeNode<TypeOfEdge> *link ){ next = link; }  //修改结点的next域 

    void SetData( int value ){ data = value; }   //修改结点的序号(顶点集) 

    void SetWeight(TypeOfEdge value ){ weight = value; }   //修改边集中对应边的权值   

};

在这里插入图片描述

  • 头结点的ADT
/*
	参数:ver:数据域存放当前结点的信息
		 head:当前结点对应的边表,指针域
*/
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{

    TypeOfVer ver;

    edgeNode<TypeOfEdge> *head;

    

    verNode(edgeNode<TypeOfEdge> *h = NULL){head = h;} 

    TypeOfVer getVer(){ return ver;}  //取得结点值(顶点集) 

    edgeNode<TypeOfEdge> getHead(){ return head;}  //取得对应的边表的头指针 

    void setVer(TypeOfVer value){ ver = value;}  //设置结点值(顶点集) 

    void setHead(edgeNode<TypeOfEdge> value){ head = value;}  //设置对应的边表的头指针



};
  • 完整邻接表的ADT
/*
	参数:vers:表示对应的顶点的数目
		 edges:表示对应的边的数目
		 verList:指向邻接顶点的数组的指针 
*/
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph{
    
    private:
       int Vers;           //顶点数 
       int Edges;          //边数 
       verNode<TypeOfVer,TypeOfEdge> *verList;
       string GraphKind;     //图的种类标志 

       

       bool Delete_Edge( int u, int v ); 

       bool DFS(int u, int &num, int visited[]); //DFS遍历(递归部分)



    public:

       adjlist_graph( const string &kd, int vSize, const TypeOfVer d[]); //构造函数构造一个只有结点没有边的图。 

       adjlist_graph( const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e); 构造函数构造一个无权图。5个参数的含义:图的类型、结点数、边数、结点集和边集 

       adjlist_graph( const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e, const TypeOfEdge w[]); //构造函数构造一个有权图。

       bool GraphisEmpty() { return Vers == 0; }  //判断图空否

       string GetGraphKind(){ return GraphKind; }

       bool GetVer(int u, TypeOfVer &data); //取得G中指定顶点的值 

       int GetFirstAdjVex(int u, int &v); //返回G中指定顶点u的第一个邻接顶点的位序(顶点集)。若顶点在G中没有邻接顶点,则返回-1

       int GetNextAdjVex(int u, int v, int &w); //返回G中指定顶点u的下一个邻接顶点(相对于v)的位序(顶点集)。若顶点在G中没有邻接顶点,则返回false

       bool PutVer(int u, TypeOfVer data); //对G中指定顶点赋值 

       bool InsertVer(const TypeOfVer &data); //往G中添加一个顶点 

       int LocateVer(TypeOfVer data); //返回G中指定顶点的位置 

       bool ExistEdge(int u, int v);

       bool PrintVer();  //输出顶点集 

       bool PrintAdjList();  //输出邻接矩阵 

       int GetVerNum(){ return Vers;}    //取得当前顶点数 

       int GetEdgeNum(){ return Edges;}  //取得当前边数 

       bool Insert_Edge(int u, int v); //无权图插入一条边

       bool Insert_Edge(int u, int v, TypeOfEdge w); //有权图插入一条边

       bool DeleteVer(const TypeOfVer &data); //往G中删除一个顶点 

       bool DeleteEdge( int u, int v ); //删除边 (外壳:有向(删除1条边), 无向(删除2条边))

       void DFS_Traverse(int u); //DFS遍历(外壳部分)

       void BFS_Traverse(int u); //BFS遍历

       ~adjlist_graph(); //析构函数 

};
思路分析
  • 主要在于析构函数,需要遍历到每一个结点对应边表进行清空,然后在清空整个结点对应的数组
实现伪码
析构函数
/*
    描述:析构函数
*/
template<class TypeOfVer, class TypeOfEdge>
adjlist_graph<TypeOfVer, TypeOfEdge>::~adjlist_graph(){

    //析构函数,主要分为两部分:删除邻接表的头结点的数组和删除对应结点对应的边表

    //生成临时头结点保存对应的值
    edgeNode<TypeOfEdge> *temp = NULL,*MidNode = NULL;

    //遍历所有的头结点
    for(int i = 0;i < Vers;i ++){

        //删除对应节点的边表
        temp = verList[i].getHead();
        MidNode = verList[i].getHead();
        //获取相关的头结点
        while(temp){
            temp = temp->next;
            delete MidNode;
            MidNode = temp;
        }
    }

    //删除头结点所在的对应的数组
    delete verList;

}
构造函数
/*
    描述:构造函数构造一个只有结点没有边的图。
*/
adjlist_graph( const string &kd, int vSize, const TypeOfVer d[]){

    //初始图中的各个基本的属性
    GraphKind = kd;
    Vers = vSize;

    //遍历对结点列表进行赋值
    verList = new verNode<TypeOfVer, TypeOfEdge>[vSize];
    for(int i = 0;i < vSize;i ++){

        verList[i].setHead(NULL);
        verList[i].setVer(d[i]);

    }

}
事故现场
提交了三次

在这里插入图片描述

  • 注意关于空格:最后一个字符那里是没有空格的,所以需要注意。
    在这里插入图片描述
  • 增加如下内容

在这里插入图片描述

分析与总结
  • 尤其要注意内存的释放,主要是两个部分,一个是链表,一个是动态数组,两种数据结构的释放方式都是不同的,需要单独进行操作
  • 上图中,题目给出的ADT有一点问题,就是关于顶点数据类型的返回头结点的函数返回值写错了
  • 如下:返回和设置的头结点都应该是指针类型,题目中少写了一个*
    在这里插入图片描述
如有不妥或者疑问,请留言或者加本人的扣扣,651378276
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值