每日一题28:图的基本操作

本文记录了基于邻接表表示的有向有权图的基本操作。邻接表表示的图的结构就是用一个散列表存储图的节点,而每个节点后面跟着从节点出发的所有边的集合,这些边用链表连接起来,所以在这样的图中寻找一个节点发出的边是容易的,但是寻找进入一个节点的边是困难的,需要遍历所有的边。删除一条边也比较容易,删除一个节点则需要寻找与该节点相关的所有边,并将这些边也删除。

#ifndef _NOWEIGHTGRAPH_H_
#define _NOWEIGHTGRAPH_H_
#include "../include/Vector.h"

namespace MyDataStructure
{
    template<typename Value, typename Edge>
    struct Vertice
    {
        typedef Value ValueType;
        typedef Edge* EdgePtr;
        typedef Edge EdgeType;
        ValueType value;
        EdgeType* adj;
    };

    template<typename Weight>
    struct Edge
    {
        typedef Weight WeightType;
        typedef typename Edge<WeightType> EdgeType;
        typedef EdgeType* EdgePtr;
        int src;
        int dst;
        WeightType weight;
        EdgeType* next;
    };

    template<typename Value, typename Weight>
    class DirectedWeightGraph
    {
    public:
        typedef Value ValueType;
        typedef Weight WeightType;
        typedef typename Vertice<ValueType, Edge<WeightType>> VerticeType;
        typedef typename Edge<WeightType> EdgeType;
        typedef VerticeType* VerticePtr;
        typedef EdgeType* EdgePtr;
        typedef DirectedWeightGraph<ValueType, WeightType> self;

    public:
        DirectedWeightGraph(){}
        DirectedWeightGraph(ValueType values[], int vertice_count,
            int src[], int dst[], WeightType weight[], int edge_count)
        {
            for (int i = 0; i < vertice_count; ++i)
            {
                AddVertice(values[i]);
            }
            for (int i = 0; i < edge_count; ++i)
            {
                AddEdge(src[i], dst[i], weight[i]);
            }
        }
        DirectedWeightGraph(const Vector<ValueType>& values,
            const Vector<int>& src,const Vector<int>& dst,
            const Vector<WeightType>& weight)
        {
            int vertice_count = values.Size();
            for (int i = 0; i < vertice_count; ++i)
            {
                AddVertice(values[i]);
            }
            int edge_count = weight.Size();
            for (int i = 0; i < edge_count; ++i)
            {
                AddEdge(src[i], dst[i], weight[i]);
            }
        }
        ~DirectedWeightGraph(){}
        VerticePtr CreateVertice(ValueType value)
        {
            VerticeType* vertice = new VerticeType;
            vertice->value = value;
            vertice->adj = nullptr;
            return vertice;
        }
        EdgePtr CreateEdge(int src, int dst, WeightType weight)
        {
            EdgeType* edge = new EdgeType;
            edge->src = src;
            edge->dst = dst;
            edge->next = nullptr;
            edge->weight = weight;
            return edge;
        }
        int AddVertice(ValueType value)
        {
            VerticePtr v = CreateVertice(value);
            return AddVertice(v);
        }
        int AddVertice(VerticePtr vertice)
        {
            int size = Vertices.Size();
            int i = 0;
            while (i < size)
            {
                if (Vertices[i] == nullptr)
                {
                    Vertices[i] = vertice;
                    break;
                }
                ++i;
            }
            if (i >= size)
            {
                Vertices.PushBack(vertice);
            }
            ++VerticeCount;
            return i;
        }
        bool IsVerticeContianed(int v) const
        {
            if (v < 0 || v >= Vertices.Size()) return false;
            //有些节点是哑的,这样的节点占用空间,但实际上是不存在的
            return Vertices[v] != nullptr;
        }

        bool IsVerticeContianed(VerticePtr v) const
        {
            if (v == nullptr) return false;
            int size = Vertices.Size();
            for (int i = 0; i < size; ++i)
            {
                if (Vertices[i] == v) return true;
            }
            return false;
        }

        //允许两个顶点间有多条路径,这些不同路径也可以具有同样的权值
        bool AddEdge(int src, int dst, WeightType weight)
        {
            if (IsVerticeContianed(src) && IsVerticeContianed(dst) && src != dst)
            {
                EdgeType* e = Vertices[src]->adj;
                if (e == nullptr)
                {
                    Vertices[src]->adj = CreateEdge(src, dst, weight);
                }
                else
                {
                    e = e->next;
                    Vertices[src]->adj = CreateEdge(src, dst, weight);
                    Vertices[src]->adj->next = e;
                }
                ++EdgeCount;
                return true;
            }
            return false;
        }
        bool IsConnected(int src, int dst) const
        {
            if (src == dst) return true;
            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                EdgePtr e = Vertices[src].adj;
                while (e != nullptr)
                {
                    if (e->dst == dst) return true;
                }
            }
            return false;
        }
        bool GetVerticeValue(int v, ValueType& value) const
        {
            if (IsVerticeContianed(v))
            {
                value = Vertices[v]->value;
                return true;
            }
            return false;
        }
        bool GetWeight(int src, int dst, WeightType& weight) const
        {

            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                if (src == dst)
                {
                    weight = 0;
                    return true;
                }
                EdgePtr e = Vertices[src]->adj;
                while (e != nullptr)
                {
                    if (e->dst == dst)
                    {
                        weight = e->weight;
                        return true;
                    }
                    e = e->next;
                }
            }
            return false;
        }
        void RemoveVertice(int v)
        {
            if (IsVerticeContianed(v))
            {
                int size = Vertices.Size();
                EdgePtr e = Vertices[v].adj;
                //移除从待删除节点出发的边
                while (e != nullptr)
                {
                    EdgePtr temp = e->next;
                    delete e;
                    --EdgeCount;
                    e = temp;
                }
                //删除节点,但是这个位置不能丢弃,
                //让它存放一个表示哑节点的空指针
                delete Vertices[v];
                Vertices[v] = nullptr;
                //移除进入删除节点的边
                for (int i = 0; i < size; ++i)
                {
                    if (Vertices[i] != nullptr)
                        remove_edge(i, v);
                }
            }
        }
        void RemoveEdge(int src, int dst)
        {
            if (IsVerticeContianed(src) && IsVerticeContianed(dst))
            {
                remove_edge(src, dst);
            }
        }
        //返回实际存储的节点个数
        int GetVerticeCount() const { return VerticeCount; }
        //返回实际存储的边的个数
        int GetEdgeCount() const { return EdgeCount; }
        //返回为保存节点已经占用的空间,有的空间被占用了,
        //但实际上存放的是哑节点
        int GetVerticeSize() const
        {
            return Vertices.Size();
        }
        VerticePtr GetVertice(int v) const
        {
            if (v < 0 || v >= Vertices.Size()) return nullptr;
            return Vertices[v];
        }
    private:
        void remove_edge(int src, int dst)
        {
            if (src == dst) return;
            EdgePtr e = Vertices[src]->adj;
            EdgePtr pre;
            while (e != nullptr)
            {
                pre = e;
                if (e->dst == dst)
                {
                    if (e == Vertices[src]->adj)
                    {
                        Vertices[src]->adj = e->next;
                        delete pre;
                        e = Vertices[src]->adj;
                    }
                    else
                    {
                        pre->next = e->next;
                        delete e;
                        e = pre->next;
                    }
                    --EdgeCount;
                }
                else e = e->next;
            }
        }
    private:
        int VerticeCount;
        int EdgeCount;
        Vector<VerticePtr> Vertices;
    };
}
#endif

这些数据结构都是为后面的算法准备的,所以就不贴测试代码,就我目前已经完成的算法来看,这些基本操作没有出错。

时间: 2024-12-15 11:56:10

每日一题28:图的基本操作的相关文章

老男孩教育每日一题-2017年4月28日- MySQL主从复制常见故障及解决方法?

MySQL主从复制常见故障及解决方法? 1.1.1故障1:从库数据与主库冲突 show slave status; 报错:且show slave status\G Slave_I/O_Running:Yes Slave_SQL_Running:No Seconds_Behind_Master:NULL Last_error:Error 'Can't create database 'xiaoliu'; database exists' on query. Default   database:'

老男孩教育每日一题-第126天-通过shell脚本打印乘法口诀表

问题背景: 生成9*9乘法表 [[email protected] ~]# seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}' 1x1=1 1x2=2   2x2=4 1x3=3   2x3=6   3x3=9 1x4=4   2x4=8   3x4=12  4x4=16 1x5=5

&#8203;老男孩教育每日一题-第99天-服务器上有哪些常用的操作系统,各有什么特点?

Linux发行版版本选择 Linux桌面系统 Ubuntu(乌班图)(开发人员开发平台) 服务器端linux系统 推荐CentOS系统,有钱任性RedHat Enterprise Linux 如果对安全要求很高 Debian或FreeBSD 使用数据库高级服务或电子邮件网络用户 SUSE(德国多) 想新技术,新功能 Fedora,相当于是RedHatEnterprise Linux的测试版 新功能新特性会先放在 Fedora里面 中文Linux 红旗linux,麒麟linux 注意: Redha

老男孩教育每日一题-2017年5月17日-使用三剑客进行变化格式

1.题目 原始数据: 17/Apr/2015:09:29:24 +0800 17/Apr/2015:09:30:26 +0800 17/Apr/2015:09:31:56 +0800 18/Apr/2015:09:34:12 +0800 18/Apr/2015:09:35:23 +0800 19/Apr/2015:09:23:34 +0800 19/Apr/2015:09:22:21 +0800 20/Apr/2015:09:45:22 +0800 期望结果: 2015-04-17 09:29:

数据结构 【实验9 图的基本操作】

实验9  图的基本操作 实验目的 1.  掌握图的各种存储结构,特别要熟练掌握邻接矩阵和邻接表存储结构. 2.遍历是图各种应用的算法的基础,要熟练掌握图的深度优先遍历和广度优先遍历算法,复习栈和队列的应用. 实验内容 程序1 /* 定义邻接矩阵类型 */ typedef int  adjmatrix[n+1][n+1]; /* 建立图的邻接矩阵 */ void CreatMatrix(adjmatrix GA) /* 从初始点v出发深度优先遍历邻接矩阵GA表示的图 */ void DfsMatr

C语言每日一题之No.9

再做决定之前,我还是做好自己该做的.我不希望几年后会悔恨自己为什么在最该努力的时候不愿意吃苦.尊敬的女王陛下,请接题: 一.题目:有已按升序排好顺序的字符串a,编写程序将字符串s中的每个字符按升序的规则插到字符串a中,最后输出"abdefghjkmnptwy". 二.思路:既然是已经排好序的,就用二分法查找的思想 将字符串s中的每个字符依次作为key拿来和字符串a做比较并且插入 三.程序 1 #include <stdio.h> 2 #include <string.

C语言每日一题之No.1

鉴于在学校弱弱的接触过C,基本上很少编程,C语言基础太薄弱.刚好目前从事的是软件编程,难度可想而知.严重影响工作效率,已无法再拖下去了.为此,痛下决心恶补C语言.此前只停留在看书,光看好像也记不住,C这东西毕竟是练出来的,所以从今天开始,每日一道C语言题目,从题目入手来补知识漏洞.题目比较基础,如不堪入目,还请见谅. 题目:输入三个整数,输出最大的数 思路:定义三个变量用来存储输入的整数 比较三个变量的大小,找到最大的数 定义一个变量存储来存储最大的数 程序: 1 #include <stdio

老男孩教育每日一题-day59-Linux root 密码忘了,如何找回来?

1.开机时手要快按任意键,因为默认时间5s 图1.1 倒数计时 2.grub菜单,只有一个内核,没什么好上下选的,按e键.不过如果你升级了系统或安装了Xen虚拟化后,就会有多个显示了. 图2.1 选择系统内核并进行编辑 3.接下来显示如下,选择第二项,按e键 图3.1 选择编辑的项目 图3.2 只修改第二项-内核相关的启动参数 4.接下来显示如下,在rhgb quiet最后加"空格",然后键入"1"或"s"或"S"或"

C语言每日一题之No.8

正式面对自己第二天,突然一种强烈的要放弃的冲动,在害怕什么?害怕很难赶上步伐?害怕这样坚持到底是对还是错?估计是今天那个来了,所以身体激素有变化导致情绪起伏比较大比较神经质吧(☆_☆)~矮油,女人每个月总有这么几天的....晚上闺蜜打电话来,共同探讨了作为单身女性身在一线城市的生活,互相安慰互相关心,心里一下子就温暖了许多.总在这个时候,你会觉得,这个冷静的城市里你不是一个人在行走,还有另一颗心牵挂着你.嘿嘿,回来该学习还学习.现在不管坚持是对的还是错的,你都踏上了研发这条不归路,那就一条黑走到