【东华大学oj】邻接表:构造只有顶点没有边的图

问题描述

目的:使用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[]);

图的邻接表模板类原型参考如下:

/* 边表的结点定义 */

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; }   //修改边集中对应边的权值   

};

//图的邻接表类

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;}  //设置对应的边表的头指针

};

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(); //析构函数 

};

输入说明

第一行:图的类型

第二行:顶点数

第三行:顶点集

输出说明

第一行:图的类型

第二行:顶点集

第三行:邻接表


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

template<class TypeOfEdge>
struct edgeNode
{
    int data;
    TypeOfEdge weight;
    edgeNode<TypeOfEdge> *next;

    edgeNode(const int &d, const TypeOfEdge &w, edgeNode<TypeOfEdge> *ptr = nullptr)
    {
        data = d;
        weight = w;
        next = ptr;
    }
};

template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
    TypeOfVer ver;
    edgeNode<TypeOfEdge> *head;

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

template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph
{
private:
    int Vers; // Number of vertices
    verNode<TypeOfVer,TypeOfEdge> *verList;
    string GraphKind;

    void BFS_Util(queue<int> &q, vector<bool> &visited)
    {
        // 如果队列为空,表示遍历完成
        if (q.empty())
            return;

        // 从队列中取出一个顶点并输出
        int u = q.front();
        cout << verList[u].ver;

        // 删除已访问的顶点
        q.pop();

        // 遍历 u 的所有邻接顶点
        edgeNode<TypeOfEdge> *curr = verList[u].head;
        while (curr != nullptr)
        {
            int v = curr->data;
            // 如果 v 未访问过,则加入队列并标记为已访问
            if (!visited[v])
            {
                q.push(v);
                visited[v] = true;
            }
            curr = curr->next;
        }

        // 递归遍历下一个顶点
        if (!q.empty())
        {
            cout << "->";
            BFS_Util(q, visited);
        }
    }


    void DFS_Util(int u, vector<bool> &visited, bool &isFirst)
    {
        // Mark the current vertex as visited
        visited[u] = true;

        // Output the current vertex
        if (!isFirst)
        {
            cout << "->";
        }
        cout << verList[u].ver;

        // Set isFirst to false after printing the first vertex
        if (isFirst)
        {
            isFirst = false;
        }

        // Traverse all neighbors of the current vertex
        edgeNode<TypeOfEdge> *curr = verList[u].head;
        while (curr != nullptr)
        {
            int v = curr->data;
            // If the neighbor has not been visited, recursively visit it
            if (!visited[v])
            {
                DFS_Util(v, visited, isFirst);
            }
            curr = curr->next;
        }
    }

public:
    void DFS_Traverse(int u)
    {
        // Record visited vertices
        vector<bool> visited(Vers, false);
        bool isFirst = true; // Flag to track the first vertex printed
        // Recursively traverse
        DFS_Util(u, visited, isFirst);
    }




    adjlist_graph(const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e) : Vers(vSize), GraphKind(kd)
    {
        verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
        for (int i = 0; i < Vers; ++i)
        {
            verList[i].ver = d[i];
            verList[i].head = nullptr;
        }

        for (int i = 0; i < eSize; ++i)
        {
            int u = e[i][0];
            int v = e[i][1];
            edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, 0, verList[u].head);
            verList[u].head = newNode;

            newNode = new edgeNode<TypeOfEdge>(u, 0, verList[v].head);
            verList[v].head = newNode;
        }
    }

    adjlist_graph(const string &kd, int vSize, int eSize, const TypeOfVer d[], int **e, const TypeOfEdge w[]) : Vers(vSize), GraphKind(kd)
    {
        verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
        for (int i = 0; i < Vers; ++i)
        {
            verList[i].ver = d[i];
            verList[i].head = nullptr;
        }

        for (int k = 0; k < eSize; ++k)
        {
            int u = e[k][0];
            int v = e[k][1];
            TypeOfEdge weight = w[k];

            // 根据图的类型来区分有权图和无权图
            if (GraphKind == "DG" || GraphKind == "DN")
            {
                // 有向图或有向网
                edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
                verList[u].head = newNode;
            }
            else
            {
                // 无向图或无向网,需要添加两条边
                edgeNode<TypeOfEdge> *newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
                verList[u].head = newNode;

                newNode = new edgeNode<TypeOfEdge>(u, weight, verList[v].head);
                verList[v].head = newNode;
            }
        }
    }


    ~adjlist_graph()
    {
        for (int i = 0; i < Vers; ++i)
        {
            edgeNode<TypeOfEdge> *curr = verList[i].head;
            while (curr != nullptr)
            {
                edgeNode<TypeOfEdge> *temp = curr;
                curr = curr->next;
                delete temp;
            }
        }
        delete[] verList;
    }

    void printAdjList()
    {
        for (int i = 0; i < Vers; ++i)
        {
            cout << verList[i].ver;
            edgeNode<TypeOfEdge> *curr = verList[i].head;
            while (curr != nullptr)
            {
                cout << "->" << curr->data;// << "(" << curr->weight << ")";
                curr = curr->next;
            }
            cout << "->nullptr" << endl;
        }
    }

    bool PrintMatrix()
    {
        cout << GraphKind << endl;
        for (int i = 0; i < Vers; ++i)
        {
            cout << verList[i].ver;
            if (i != Vers - 1)
                cout << " ";
        }
        cout<<endl;
        return true;
    }
    bool GetWeight(int u, int v, TypeOfEdge &w);

    int Get_Degree(int u)
    {
        // 首先检查顶点是否有效
        if (u < 0 || u >= Vers)
            return -1; // 顶点不存在,返回-1

        int degree = 0; // 初始化顶点的度

        // 遍历顶点 u 的邻接表
        edgeNode<TypeOfEdge> *curr = verList[u].head;
        while (curr != nullptr)
        {
            degree++; // 每遍历一条边,度加1
            curr = curr->next;
        }

        return degree;
    }

    adjlist_graph(const string &kd, int vSize, const TypeOfVer d[]) : Vers(vSize), GraphKind(kd)
    {
        verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
        for (int i = 0; i < Vers; ++i)
        {
            verList[i].ver = d[i];
            verList[i].head = nullptr; // 将每个顶点的邻接表指针初始化为nullptr
        }
    }



};
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::GetWeight(int u, int v, TypeOfEdge &w)
{
    // 首先检查顶点是否有效
    if (u < 0 || u >= Vers || v < 0 || v >= Vers)
        return false;

    // 遍历顶点 u 的邻接表
    edgeNode<TypeOfEdge> *curr = verList[u].head;
    while (curr != nullptr)
    {
        if (curr->data == v)
        {
            w = curr->weight; // 找到边,将权值赋给 w
            return true;
        }
        curr = curr->next;
    }

    return false; // 没有找到与顶点 v 相连接的边
}
int main()
{
    string graphType;
    int n;
    cin >> graphType >> n;

    string *verArr = new string[n];
    for (int i = 0; i < n; ++i)
    {
        cin >> verArr[i];
    }

    adjlist_graph<string, int> graph(graphType, n, verArr);

// 输出图的类型、顶点集和邻接表
    graph.PrintMatrix();
    graph.printAdjList();

// 释放动态内存
    delete[] verArr;





    return 0;
}

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ixll625

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值