浅谈【数据结构】图-图的存储

目录

1、图的存储

2、邻接表

3、十字链表


谢谢帅气美丽且优秀的你看完我的文章还要点赞、收藏加关注

没错,说的就是你,不用再怀疑!!!

希望我的文章内容能对你有帮助,一起努力吧!!!


1、图的存储

  • 邻接矩阵:数组表示法
    • 优势:存储/设计比较简单
    • 劣势:浪费空间。遍历出度比较费时间
  • 邻接表:通过数组+链表的形式来存储顶点出度关系
    • 优势:节省空间,遍历出度关系比较快
    • 劣势:操作相对邻接矩阵来说比较繁琐

2、邻接表

构建图类型

上述方式可以但是不够简洁

***领接表代码示例***

cpp 复制代码
#include <iostream>
#include <cstring>

// 关系类型
typedef struct relation
{
    int index; // 下标
    int weight; // 权值
    struct relation *next; // 下一个关系的顶点的下标指针
}Relation_t;

// 顶点类型
typedef struct 
{
    std::string data; // 顶点数据
    Relation_t *first; // 该顶点的关系集
}Vertex_t;


// 当前顶点数
int current_count = 0;

/*
    @brief  创建一个图:邻接表
    @param  count 该图的最大顶点数量 
    @return 成功返回创建好的图指针
*/
Vertex_t *creatGraph(int count)
{
    // 申请空间
    Vertex_t *graph = new Vertex_t[count];

    // 初始化
    memset(graph,0,sizeof(Vertex_t)*count);

    std::cout << "请输入顶点数据空格分开("结束"输入):";
    // 接受顶点

    while(1)
    {
        std::string data = "结束";
        std::cin >> data;
        if(data == "结束")
            break;

        if(current_count == count)
            break;

        // 新增顶点位置
        graph[current_count].data  = data;
        graph[current_count].first = nullptr;

        current_count++;
    }

    // 增加关系
    while(1)
    {
        std::cout << "请输入顶点关系(结束 结束 -1):";

        // 出发顶点和终止顶点 权值
        std::string start;
        std::string end;
        int data;
        std::cin >> start >> end >> data;

        if(start=="结束"||end=="结束"||data == -1)
            break;

        // 存储关系
        // 获取start和end在图数组的什么位置
        int index_s = 0,index_e = 0;
        for(;index_s < current_count;index_s++)
            if(graph[index_s].data == start)
                break;
        for(;index_e < current_count;index_e++)
            if(graph[index_e].data == end)
                break;

        // 两个顶点的下标找到了
        if(index_s == current_count||index_e == current_count)
            continue;
        
        // 添加关系
        Relation_t *rt = new Relation_t;
        rt->index = index_e;
        rt->weight = data;
        rt->next = nullptr;

        // 当至少存在出度顶点的时候
        if(graph[index_s].first)
        {
            Relation_t *rt_ptr = graph[index_s].first;
            while(rt_ptr->next)
                rt_ptr = rt_ptr->next;
            
            // 存进关系链表
            rt_ptr->next = rt;
        }
        else{ // 一个出度结点都没有的时候
            graph[index_s].first = rt;
        }
    }

    return graph;
}

void printrelation(Vertex_t *graph)
{
    if(!graph)
        std::cout << "空图" << std::endl;
    
    for(int count_v = 0;count_v < current_count;count_v++)
    {
        std::cout << "顶点<"<< graph[count_v].data <<">:";
        
        Relation_t *rt_ptr = graph[count_v].first;
        while(rt_ptr)
        {
            std::cout<< "<"<< graph[count_v].data <<","<< 
            graph[rt_ptr->index].data <<">" 
            << "("<<rt_ptr->weight<<")";
        
            rt_ptr = rt_ptr->next;
        }
        std::cout << std::endl;
    }
}


int main()
{
    Vertex_t *graph = creatGraph(10);

    printrelation(graph);

    delete []graph;

    return 0;
}

逆邻接表:通过数组+链表的形式来存储顶点入度关系

**3、**十字链表

  • 十字链表:通过邻接表+逆邻接表形式实现,用来存储一个顶点的入度出度
    • 更方便的遍历一个顶点的入度和出度顶点

***十字链表示例代码***

cpp 复制代码
#include <iostream>
#include <list>
#include <vector>

using std::list;
using std::vector;

template <typename _v_type_,typename _r_type_>
class OrthogonalList
{
    // 关系结构体
    typedef struct 
    {
        int      index; // 下标
        _r_type_ weight;// 权值
    }Relation_t;

    // 顶点结构体
    typedef struct 
    {
        _v_type_ data; // 顶点
        list<Relation_t> enter_r; // 入度集
        list<Relation_t> out_r;   // 出度集
    }Vertex_t;

    // 顶点集
    vector<Vertex_t> vertex;

    // 计算下标
    int getIndex(_v_type_ vertex_v)
    {
        for(int index = 0;index < vertex.size();index++)
        {
            if(vertex_v == vertex[index].data)
                return index;
        }
        return -1;
    }
public:
    OrthogonalList() // 构造函数
        : vertex(0)
    {}
    ~OrthogonalList() // 析构函数
    {}
    void addVertex(_v_type_ vertex_v) // 增加顶点
    {
        Vertex_t vt;
        vt.data = vertex_v;
        vertex.push_back(vt);
    }
    void addRelation(_v_type_ vertex_s,_v_type_ vertex_e,_r_type_ relation) // 增加弧
    {
        // 获取顶点下标
        int vt_start = getIndex(vertex_s);
        int vt_end   = getIndex(vertex_e);
        if(vt_start==-1||vt_end==-1)
            return;

        // 出度
        Relation_t rt_o;
        rt_o.index = vt_end;
        rt_o.weight = relation;
        vertex[vt_start].out_r.push_back(rt_o);

        // 入度
        Relation_t rt_e;
        rt_e.index = vt_start;
        rt_e.weight = relation;
        vertex[vt_end].enter_r.push_back(rt_e);
    }
    void print()
    {
        std::cout << "顶点关系集" << std::endl;
        for(auto v : vertex)
        {
            std::cout << v.data << ":" << std::endl;
            std::cout << "入弧集:"; 
            for(auto r : v.enter_r)
                std::cout << vertex[r.index].data << ":" << r.weight << "  ";
            std::cout << std::endl;
            std::cout << "出弧集:";
            for(auto r : v.out_r)
                std::cout << vertex[r.index].data << ":" << r.weight << "  ";
            std::cout << std::endl;
        }
    }
};

int main()
{
    OrthogonalList<std::string,int> graph;

    std::cout <<"请输入顶点:";
    while(1)
    {
        std::string vertex = "结束";
        std::cin >> vertex;
        if(vertex == "结束")
            break;
        graph.addVertex(vertex);
    }

    while(1)
    {
        std::cout <<"请输入关系:";
        std::string vertex_s = "结束";
        std::string vertex_e = "结束";
        int data = -1;
        std::cin >> vertex_s >> vertex_e >> data;
        if(vertex_s == "结束"||vertex_e == "结束"||data == -1)
            break;
        graph.addRelation(vertex_s,vertex_e,data);
    }

    graph.print();
    return 0;
}
相关推荐
XiaoLeisj28 分钟前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
励志成为嵌入式工程师1 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉2 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer2 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq2 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown2 小时前
【数据结构】选择排序
数据结构·算法·排序算法
记录成长java3 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山3 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
hikktn4 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
青花瓷4 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode