图的存储结构

简介: 一直想写一篇关于图的博客,但是奈何功力不够,迟迟没有下手。查看多方资料后,觉得写一篇笔记供自己参考,各位看官轻喷。感谢这个博客https://blog.csdn.net/qq_35644234/article/details/57083107图是顶点(vetex)和边(edge)的集合。

一直想写一篇关于图的博客,但是奈何功力不够,迟迟没有下手。查看多方资料后,觉得写一篇笔记供自己参考,各位看官轻喷。感谢这个博客https://blog.csdn.net/qq_35644234/article/details/57083107
图是顶点(vetex)和边(edge)的集合。因为图的数据结构有很多种表示方式,容易给我这种渣渣造成很多困扰。就是在没有搞会图的算法之前,先被这些存储方式搞晕了。简单来说,图有各种存储方式是因为每个存储方式有优缺点,我主要讲两种,一种是邻接矩阵,一种是邻接表。
下面待我一一道来。

1. 图的存储结构--邻接矩阵。

这种方式很简单,构建两个数组存储图的信息,一个一维数组存储顶点数据的信息,一个二维数组(也就是矩阵)存储边的信息。
如果图有n个顶点,那么邻接矩阵为n*n的方阵,方阵每个元素的值如下:


img_25da6fa8247f6bf627ed7946bedea844.png
邻接矩阵

举个栗子:


img_c381ea6a1bccafd439f6c08778497540.png
图实例

有向图类似,不在赘述。
这里再说一句,如果我们需要将图表示成一个网的时候(也就是边赋权重)。假设有n个顶点,公式如下:
img_2e498cb58825293c8ead2de7f734f53f.png

接下来是代码实现

import java.util.Scanner;

public class Graph {

    private int[] vex; //顶点数组
    private int[][] adjMatrix; //图的邻接矩阵
    private int vexNum; //顶点个数
    private int edge; //边的条数

    public void createGraph(){
        Scanner s = new Scanner(System.in);
        System.out.println("请输入顶点个数:");
        this.vexNum = s.nextInt();
        System.out.println("请输入边的个数:");
        this.edge = s.nextInt();

        this.vex = new int[vexNum];
        this.adjMatrix = new int[vexNum][vexNum];

        //后面省略
    }
    

2. 图的存储结构--邻接表

邻接表是一种链式存储结构。因为当图的顶点多边少的时候,矩阵将会很庞大,但是里边全都是0,浪费空间。邻接表主要是声明两个结构,一个是用来存储顶点信息的数组(对象数组,存储数据和被指向顶点的地址),一个是表节点(被指向的顶点)。


img_689bf4ce6616c08ed4f3bf4d031d0a49.png
邻接表结构

举个例子:


img_55e2b12164b3b966630012fde8ad3c0a.png
无向图例子

下面结合代码说明邻接表的结构:
import java.util.Scanner;

public class Graph2 {
    
    private int vexNum;//图的顶点数
    private int edge; //图的边数

    //存储被指向的顶点信息
    class ArcNode{
        int adjvex; //某条边指向的那个顶点的位置,一般是数组的下标
        ArcNode nextarc; //指向下一个表结点
    }

    //存储顶点的信息
    class Vnode{
        int data; //顶点信息
        ArcNode firstArc; //指向第一条依附于该顶点边的信息
    }

    public void createGraph(){
        Scanner s = new Scanner(System.in);
        System.out.println("请输入顶点个数:");
        this.vexNum = s.nextInt();
        System.out.println("请输入边的个数:");
        this.edge = s.nextInt();
        
        Vnode[] vnodes = new Vnode[vexNum];

        //后面省略
    }
}

后面还有针对有向图的存储结构---十字链表,针对无向图的存储结构,邻接多重表,只要理解了上面的这些,这些结构不难理解。

《算法第四版》推荐的存储结构,无论是有向图还是无向图,都用邻接表的形式,比较通用。还有,无向图的邻接表一般都是一条边<w,v>,w顶点要接v,v也要接w。
下面是完整的图的代码,代码的实现方式和上图中的结构有一丢丢的不同,是这样的图,不过大体上也差不多:

img_2cb6a66ad14ce8ea0554e03fa401e54e.png

package com.xushu.Undirectedgraph;



/**
 * Java: 邻接表表示的"无向图(List Undirected Graph)"
 */

import java.io.IOException;
import java.util.Scanner;

public class ListUDG {
    // 邻接表中表对应的链表的顶点
    private class ENode {
        int ivex;       // 该边所指向的顶点的位置
        ENode nextEdge; // 指向下一条弧的指针
    }

    // 邻接表中表的顶点
    private class VNode {
        char data;          // 顶点信息
        ENode firstEdge;    // 指向第一条依附该顶点的弧
    };

    private VNode[] mVexs;  // 顶点数组


//    /* 
//     * 创建图(自己输入数据)
//     */
//    public ListUDG() {
//
//        // 输入"顶点数"和"边数"
//        System.out.printf("input vertex number: ");
//        int vlen = readInt();
//        System.out.printf("input edge number: ");
//        int elen = readInt();
//        if ( vlen < 1 || elen < 1 || (elen > (vlen*(vlen - 1)))) {
//            System.out.printf("input error: invalid parameters!\n");
//            return ;
//        }
//        
//        // 初始化"顶点"
//        mVexs = new VNode[vlen];
//        for (int i = 0; i < mVexs.length; i++) {
//            System.out.printf("vertex(%d): ", i);
//            mVexs[i] = new VNode();
//            mVexs[i].data = readChar();
//            mVexs[i].firstEdge = null;
//        }
//
//        // 初始化"边"
//        //mMatrix = new int[vlen][vlen];
//        for (int i = 0; i < elen; i++) {
//            // 读取边的起始顶点和结束顶点
//            System.out.printf("edge(%d):", i);
//            char c1 = readChar();
//            char c2 = readChar();
//            int p1 = getPosition(c1);
//            int p2 = getPosition(c2);
//            // 初始化node1
//            ENode node1 = new ENode();
//            node1.ivex = p2;
//            // 将node1链接到"p1所在链表的末尾"
//            if(mVexs[p1].firstEdge == null)
//              mVexs[p1].firstEdge = node1;
//            else
//                linkLast(mVexs[p1].firstEdge, node1);
//            // 初始化node2
//            ENode node2 = new ENode();
//            node2.ivex = p1;
//            // 将node2链接到"p2所在链表的末尾"
//            if(mVexs[p2].firstEdge == null)
//              mVexs[p2].firstEdge = node2;
//            else
//                linkLast(mVexs[p2].firstEdge, node2);
//        }
//    }

    /*
     * 创建图(用已提供的矩阵)
     *
     * 参数说明:
     *     vexs  -- 顶点数组
     *     edges -- 边数组
     */
    public ListUDG(char[] vexs, char[][] edges) {
        
        // 初始化"顶点数"和"边数"
        int vlen = vexs.length;
        int elen = edges.length;

        // 初始化"顶点"
        mVexs = new VNode[vlen];
        for (int i = 0; i < mVexs.length; i++) {
            mVexs[i] = new VNode();
            mVexs[i].data = vexs[i];
            mVexs[i].firstEdge = null;
        }

        // 初始化"边"
        for (int i = 0; i < elen; i++) {
            // 读取边的起始顶点和结束顶点
            char c1 = edges[i][0];
            char c2 = edges[i][1];
            // 读取边的起始顶点和结束顶点
            int p1 = getPosition(edges[i][0]);
            int p2 = getPosition(edges[i][1]);
            
            
            //初始化两次,保证w后有v,v后有w
            
            // 初始化node1
            ENode node1 = new ENode();
            node1.ivex = p2;
            // 将node1链接到"p1所在链表的末尾"
            if(mVexs[p1].firstEdge == null)
              mVexs[p1].firstEdge = node1;
            else
                linkLast(mVexs[p1].firstEdge, node1);
            // 初始化node2
            ENode node2 = new ENode();
            node2.ivex = p1;
            // 将node2链接到"p2所在链表的末尾"
            if(mVexs[p2].firstEdge == null)
              mVexs[p2].firstEdge = node2;
            else
                linkLast(mVexs[p2].firstEdge, node2);

        }
    }

    /*
     * 将node节点链接到list的最后
     */
    private void linkLast(ENode list, ENode node) {
        ENode p = list;

        while(p.nextEdge!=null)
            p = p.nextEdge;
        p.nextEdge = node;
    }

    /*
     * 返回ch位置
     */
    private int getPosition(char ch) {
        for(int i=0; i<mVexs.length; i++)
            if(mVexs[i].data==ch)
                return i;
        return -1;
    }

    /*
     * 读取一个输入字符
     */
    private char readChar() {
        char ch='0';

        do {
            try {
                ch = (char)System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } while(!((ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z')));

        return ch;
    }

    /*
     * 读取一个输入字符
     */
    private int readInt() {
        Scanner scanner = new Scanner(System.in);
        return scanner.nextInt();
    }

    /*
     * 打印矩阵队列图
     */
    public void print() {
        System.out.printf("List Graph:\n");
        for (int i = 0; i < mVexs.length; i++) {
            System.out.printf("%d(%c): ", i, mVexs[i].data);
            ENode node = mVexs[i].firstEdge;
            while (node != null) {
                System.out.printf("%d(%c) ", node.ivex, mVexs[node.ivex].data);
                node = node.nextEdge;
            }
            System.out.printf("\n");
        }
    }

    public static void main(String[] args) {
        char[] vexs = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
        char[][] edges = new char[][]{
            {'A', 'C'}, 
            {'A', 'D'}, 
            {'A', 'F'}, 
            {'B', 'C'}, 
            {'C', 'D'}, 
            {'E', 'G'}, 
            {'F', 'G'}};
        ListUDG pG;

        // 自定义"图"(输入矩阵队列)
        //pG = new ListUDG();
        // 采用已有的"图"
        pG = new ListUDG(vexs, edges);

        pG.print();   // 打印图
    }
}
目录
相关文章
|
3天前
|
人工智能 自然语言处理 JavaScript
2026年Windows+Ollama本地部署OpenClaw保姆级教程:本地AI Agent+阿里云上快速搭建
2026年OpenClaw凭借本地部署、私有化运行的特性,成为打造个人智能体的核心工具,而Ollama作为轻量级本地大模型管理工具,能让OpenClaw摆脱对云端大模型的依赖,实现**本地推理、数据不泄露、全流程私有化**的智能体验。本文基于Windows 11系统,从硬件环境准备、Ollama安装与模型定制、OpenClaw部署配置、技能扩展到常见问题排查,打造保姆级本地部署教程,同时补充阿里云OpenClaw(Clawdbot)快速部署步骤,兼顾本地私有化需求与云端7×24小时运行需求,文中所有代码命令均可直接复制执行,确保零基础用户也能快速搭建属于自己的本地智能体。
5337 29
|
10天前
|
存储 人工智能 负载均衡
阿里云OpenClaw多Agent实战宝典:从极速部署到AI团队搭建,一个人=一支高效军团
在AI自动化时代,单一Agent的“全能模式”早已无法满足复杂任务需求——记忆臃肿导致响应迟缓、上下文污染引发逻辑冲突、无关信息加载造成Token浪费,这些痛点让OpenClaw的潜力大打折扣。而多Agent架构的出现,彻底改变了这一现状:通过“单Gateway+多分身”模式,让一个Bot在不同场景下切换独立“大脑”,如同组建一支分工明确的AI团队,实现创意、写作、编码、数据分析等任务的高效协同。
4328 29
|
14天前
|
人工智能 自然语言处理 监控
OpenClaw skills重构量化交易逻辑:部署+AI全自动炒股指南(2026终极版)
2026年,AI Agent领域最震撼的突破来自OpenClaw(原Clawdbot)——这个能自主规划、执行任务的智能体,用50美元启动资金创造了48小时滚雪球至2980美元的奇迹,收益率高达5860%。其核心逻辑堪称教科书级:每10分钟扫描Polymarket近千个预测市场,借助Claude API深度推理,交叉验证NOAA天气数据、体育伤病报告、加密货币链上情绪等多维度信息,捕捉8%以上的定价偏差,再通过凯利准则将单仓位严格控制在总资金6%以内,实现低风险高频套利。
7732 66
|
4天前
|
人工智能 JSON JavaScript
手把手教你用 OpenClaw + 飞书,打造专属 AI 机器人
手把手教你用 OpenClaw(v2026.2.22-2)+ 飞书,10分钟零代码搭建专属AI机器人!内置飞书插件,无需额外安装;支持Claude等主流模型,命令行一键配置。告别复杂开发,像聊同事一样自然对话。
2191 7
手把手教你用 OpenClaw + 飞书,打造专属 AI 机器人
|
4天前
|
人工智能 运维 安全
OpenClaw极速部署:ZeroNews 远程管理OpenClaw Gateway Dashboard指南+常见错误解决
OpenClaw作为高性能AI智能体网关平台,其Gateway Dashboard是管理模型调用、渠道集成、技能插件的核心操作界面,但默认仅支持本地局域网访问。官方推荐的Tailscale、VPN等远程访问方案在国内网络环境中体验不佳,而ZeroNews凭借轻量化部署、专属域名映射、多重安全防护的特性,成为适配国内网络的最优远程管理解决方案。
1521 2
|
5天前
|
存储 人工智能 BI
2026年OpenClaw(Clawdbot)极简部署:接入小红书全自动运营,一个人=一支团队
2026年的小红书运营赛道,AI自动化工具已成为核心竞争力。OpenClaw(原Clawdbot)凭借“Skill插件化集成、全流程自动化、跨平台联动”的核心优势,彻底颠覆传统运营模式——从热点追踪、文案创作、封面设计到自动发布、账号互动,仅需一句自然语言指令,即可实现全链路闭环。而阿里云作为OpenClaw官方推荐的云端部署载体,2026年推出专属秒级部署方案,预装全套运行环境与小红书运营插件,让零基础用户也能10分钟完成部署,轻松拥有7×24小时在线的“专属运营团队”。
1673 8
|
9天前
|
人工智能 自然语言处理 安全
2026年OpenClaw Skills安装指南:Top20必装清单+阿里云上部署实操(附代码命令)
OpenClaw(原Clawdbot)的强大之处,不仅在于其开源免费的AI执行引擎核心,更在于其庞大的Skills生态——截至2026年2月,官方技能市场ClawHub已收录1700+各类技能插件,覆盖办公自动化、智能交互、生活服务等全场景。但对新手而言,面对海量技能往往无从下手,盲目安装不仅导致功能冗余,还可能引发权限冲突与安全风险。
2462 10
|
2月前
|
人工智能 自然语言处理 Shell
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
本教程指导用户在开源AI助手Clawdbot中集成阿里云百炼API,涵盖安装Clawdbot、获取百炼API Key、配置环境变量与模型参数、验证调用等完整流程,支持Qwen3-max thinking (Qwen3-Max-2026-01-23)/Qwen - Plus等主流模型,助力本地化智能自动化。
47212 160
🦞 如何在 OpenClaw (Clawdbot/Moltbot) 配置阿里云百炼 API
|
2天前
|
人工智能 自然语言处理 安全
OpenClaw双模式部署指南:Windows+Ollama本地私有化+阿里云OpenClaw云端搭建(保姆级教程)
在AI智能体爆发的2026年,OpenClaw凭借本地部署、私有化运行、多工具集成的核心优势,成为个人与企业打造专属智能助手的首选。而Ollama作为轻量级本地大模型管理工具,能让OpenClaw彻底摆脱对云端大模型的依赖,实现“本地推理、数据不泄露、全流程私有化”的安全体验;同时阿里云提供的专属云端部署方案,可满足7×24小时稳定运行需求,兼顾隐私与便捷性。
1033 2

热门文章

最新文章