【高阶数据结构】图详解第一篇:图的基本概念及其存储结构(邻接矩阵和邻接表)
文章目录
- 1. 图的基本概念
- 1.1 什么是图
- 1.2 有向图和无向图
- 1.3 完全图
- 1.4 邻接顶点
- 1.5 顶点的度
- 1.6 路径
- 1.7 路径长度
- 1.8 简单路径与回路
- 1.9 子图
- 1.10 连通图
- 1.11 强连通图
- 1.12 生成树
- 2. 图的存储结构
- 2.1 邻接矩阵
- 2.2 邻接矩阵代码实现
- 结构定义
- 构造函数
- 添加边
- 打印图
- 测试
- 2.3 邻接表
- 2.4 邻接表代码实现
- 结构定义
- 构造函数
- 添加边
- 打印图
- 测试
- 3. 源码
- 3.1 Graph.h
- 3.2 Test.cpp
这篇文章开始,我们来学习一种高阶数据结构——图
1. 图的基本概念
1.1 什么是图
图是由顶点集合及顶点间的关系(边)组成的一种数据结构:G = (V, E)。
其中:
顶点集合V = {x|x属于某个数据对象集}是有穷非空集合;
E = {(x,y)|x,y属于V}或者E = {<x, y>|x,y属于V && Path(x, y)}是顶点间关系的有穷集合,也叫做边的集合。
(x, y)表示x到y的一条双向通路,即(x, y)是无方向的;Path(x, y)表示从x到y的一条单向通路,即Path(x, y)是有方向的。
顶点和边:
图中结点称为顶点,第i个顶点记作vi。两个顶点vi和vj相关联称作顶点vi和顶点vj之间有一条边,图中的第k条边记作ek,ek = (vi,vj)或<vi,vj>。
1.2 有向图和无向图
图分为有向图和无向图
有向图中,顶点对<x, y>是有序的,顶点对<x,y>称为顶点x到顶点y的一条边(弧),<x, y>和<y, x>是两条不同的边,比如下图G3和G4为有向图
无向图中,顶点对(x, y)是无序的,顶点对(x,y)称为顶点x和顶点y相关联的一条边,这条边没有特定方向,(x, y)和(y,x)是同一条边,比如下图G1和G2为无向图
注意:无向边(x, y)等于有向边<x, y>和<y, x>。
简单总结一下:
图是一种非线性的数据结构,用于表示元素之间的关系。它由节点(也称为顶点)和连接节点的边组成。每个节点可以与其他节点直接或间接连接,这些连接关系可以具有方向性(有向图)或无方向性(无向图)。因此,图可用于表示各种关系,如网络、社交关系、地图等,并且在计算机科学和现实生活中有广泛的应用。
1.3 完全图
在有n个顶点的无向图中,若有
n * (n-1)/2
条边,即任意两个顶点之间有且仅有一条边,则称此图为无向完全图,比如上图G1
在n个顶点的有向图中,若有n * (n-1)
条边,即任意两个顶点之间有且仅有两条方向相反的边,则称此图为有向完全图,比如上图G4
1.4 邻接顶点
在无向图中G中,若(u, v)是E(G)中的一条边,则称u和v互为邻接顶点,并称边(u,v)依附于顶点u和v;
在有向图G中,若<u, v>是E(G)中的一条边,则称顶点u邻接到v,顶点v邻接自顶点u,并称边<u, v>与顶点u和顶点v相关联。
1.5 顶点的度
顶点v的度是指与它相关联的边的条数,记作deg(v)。
在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(v);顶点v的出度是以v为起始点的有向边的条数,记作outdev(v)。因此:dev(v) = indev(v) + outdev(v)。
注意:对于无向图,顶点的度等于该顶点的入度和出度,即dev(v) = indev(v) = outdev(v)。
1.6 路径
在图G = (V, E)中,若从顶点vi出发有一组边使其可到达顶点vj,则称顶点vi到顶点vj的顶点序列为从顶点vi到顶点vj的路径。
比如,在上面这个有向图中,顶点1到顶点7的路径有:
1,3,6,7
1,4,7
可能有多条
1.7 路径长度
对于不带权的图,一条路径的路径长度是指该路径上的边的条数;对于带权的图,一条路径的路径长度是指该路径上各个边权值的总和
1.8 简单路径与回路
若路径上各顶点v1,v2,v3,…,vm均不重复,则称这样的路径为简单路径。
若路径上第一个顶点v1和最后一个顶点vm重合,则称这样的路径为回路或环。
1.9 子图
设图G = {V, E}和图G1 = {V1,E1},若V1属于V且E1属于E,则称G1是G的子图(即G1的顶点和边都是原图的一部分)
1.10 连通图
在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的;
如果图中任意一对顶点都是连通的,则称此图为连通图。
1.11 强连通图
在有向图中,若每一对顶点vi和vj之间都存在一条从vi到vj的路径,也存在一条从vj到vi的路径,则称此图是强连通图
1.12 生成树
无向图中,一个连通图的最小连通子图称作该图的生成树。
有n个顶点的连通图的生成树有n个顶点和n-1条边。
比如:
2. 图的存储结构
因为图中既有节点,又有边(节点与节点之间的关系),因此,在图的存储中,只需要保存:节点和边关系即可。
节点保存比较简单,只需要一段连续空间即可,那边关系该怎么保存呢?
2.1 邻接矩阵
首先我们来学习图的第一种存储结构——邻接矩阵
那邻接矩阵是如何保存图的顶点和边呢?
因为节点与节点之间的关系就是连通与否,即为0或者1,因此邻接矩阵(二维数组)即是:先用一个数组将顶点保存,然后采用矩阵来表示节点与节点之间的关系(边)
比如:
值为1就表示对应的这两个顶点是连通的,为0就表示两个顶点不连通
那其实观察上面的图我们可以发现:
无向图的邻接矩阵是对称的,第i行(列)元素之和,就是顶点i的度(边没有权值,只存0/1的情况下,元素和就是度)
有向图的邻接矩阵则不一定是对称的,第i行(列)元素之和就是顶点i 的出(入)度(边没有权值,只存0/1的情况下)
另外呢:
1. 如果边带有权值,并且两个节点之间是连通的,上图中的边的关系(1/0)就用权值代替,如果两个顶点不通,可以使用无穷大代替(后面我们实现的时候就要增加一个表示无穷大的模板参数)
2. 用邻接矩阵存储图的优点是能够快速知道两个顶点是否连通,取到权值
3. 缺陷是如果顶点比较多,边比较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间;所以邻接矩阵比较适合存储稠密图(边比较多的图),不适合存储稀疏图(边比较少的图)
而且要求两个节点之间的路径不好求;
还有求一个顶点相连的顶点有哪些也不好求(O(N),这个用后面的邻接表结构存储的话就很好求)。
2.2 邻接矩阵代码实现
那下面我们就来实现一下邻接矩阵:
结构定义
那我们这里呢还是搞成模板,因为顶点的值可以是任意类型,那我们的模板都需要给哪些参数呢?
这里我们先给了3个模板参数,解释一下:
V接收顶点(vertex)的类型,W接收权值的类型(权值不一定非得是整数),然后我们再给一个非类型模板参数来决定我们要定义的图是有向图还是无向图(比如Direction==false就是无向图,等于true就是有向图),一般用无向图居多,所以可以给个缺省值false,我们不传默认就是无向图。
那现在图里面要存顶点和边:
顶点呢我们就可以用一个vector来存储。
那边我们要如何存呢?
上面有提到邻接矩阵是用一个二维数组(即矩阵)来存储边(顶点之间的关系)的,我们可以再来看一下图
那这里就涉及到一个问题:
这里面二维数组的每一个下标是不是都要跟一个顶点进行映射啊。
比如二维数组中某一个元素_vertexs[i][j]
是1,那就表示下标i
和j
对应的两个顶点是连通的。
那怎么建立顶点和数组下标的映射呢?
🆗,我们上一篇文章并查集里面其实就讲了一种方法,我们当时说了图里面也会用到。
用一个map就搞定了嘛。
构造函数
然后我们来想一下构造函数可以怎么写?
那我们可以这样搞:
创建一个图对象的时候可以先把顶点存一些,给一个顶点的数组就可以,然后后面我们可以再增加一个增加边的接口,我们可以手动创建边和赋权值。
所以,构造函数
就可以这样写
添加边
然后我们来增加一个添加边的接口:
那首先我们要获取一下顶点的下标,因为我们添加边其实就是在邻接矩阵里面改这两个顶点对应位置的值嘛
可以再封装一个接口
然后AddEdge里面我们就可以获取两个顶点对应的下标然后在邻接矩阵里面添加边
然后添加边这里有一个问题
我们的代码是要同时针对有向图和无向图的,如果是无向图的话我们添加一条边比如AB,那就完了;但是如果是有向图添加AB就是AB,如果要添加BA的就需要再添加一次。
所以我们这样写:
打印图
然后我们再写一个打印,搞些数据测试一波:
测试
来测试一下
我们就以这个为例
运行一下
没问题,只不过上面图中ij相等的位置打印的是0
2.3 邻接表
邻接表:
使用数组存储顶点的集合,使用链表存储顶点的关系(边)。
比如
无向图邻接表存储:
一个顶点与哪些顶点相连,相连的顶点就存到这个顶点对应的链表中,当然如果带权的话也要存上对应边的权值。
(每个顶点都有一个对应的链表,多条链表用一个指针数组就可以维护起来)
注意:无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点vi 对应链表集合中结点的数目即可
有向图邻接表存储:
那通过上面的了解其实我们可以得出,对于邻接表的存储方式
1. 适合存储稀疏图(边比较少的图),因为邻接表的话有多少边链表里面就存几个对应的顶点,不需要额外的空间;而上面邻接矩阵不论边多边少都要开一个N*N的矩阵(二维数组),边少的时候那就大部分位置都存的是0
2. 方便查找从一个顶点连接出去的边有哪些,因为它对应的边链表里面存的就是与这个顶点相连的顶点
3. 但是不方便确定两个顶点是否相连和获取权值(要遍历其中一个顶点的边链表查找O(N))
2.4 邻接表代码实现
那我们再来实现一下邻接表。
结构定义
首先来定义一下邻接表的结构:
首先对于邻接表来说,模板参数这里就不需要MAX_W
这个非类型模板参数了。
因为上面邻接矩阵之所以需要是因为矩阵不相连的边矩阵里面对应得位置要存这个值来标识一下,但是邻接表我们上面了解了,每个顶点连接的边有多少,就存多少个顶点,不相连的顶点直接是不存的。
然后呢顶点我们还是用一个vector来存,还要建立顶点根下标的映射(每个顶点要跟指针数组的下标一一对应),与邻接矩阵不同的在于这里的边要用链表来存,一个顶点与哪些顶点相连,相连的顶点就存到这个顶点对应的边链表中。
如果带权的话还要存上权值,所以我们可以把边链表封装成一个类:
其实就是一个链表的结构,因为我们要用链表来存储边嘛
然后,图的结构里面
邻接表其实就是一个指针数组嘛,每个位置存一个指针,指针指向一个链表,该位置的下标就映射对应的顶点,对应的链表里面存的就是与之相连的顶点以及对应边的权值
构造函数
那下面我们来写一下邻接表结构图的构造函数:
逻辑其实根上面邻接矩阵是一样的
添加边
然后添加边:
首先还是获取一下边的起始顶点和终止顶点映射的下标
然后添加边的时候:
如果是无向图,比如添加一个边AB,那要在A的链表里面挂B顶点,也要在B的链表里面挂A顶点;
如果是有向图,只在A的链表里面挂B就行了(当然有向图的话我们看到上面还分为出边表和入边表,但是入边表一般不需要搞,我们这里就只存一个出边表,有需要的话可以再添加)
所以呢,添加的逻辑我们这样写:
打印图
那我们再来写个打印的函数,然后测试一下
这个函数没什么难度,就不解释了
测试
然后我们来搞一组数据测试一下:
我们这里不传第三个模板参数,默认是无向图
看一下结果
没问题!
我们也可以试一下有向图
也没问题!
3. 源码
3.1 Graph.h
#pragma once//邻接矩阵
namespace matrix
{template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>class Graph{public:Graph(const V* ver, size_t n){//存储顶点并与下标建立映射_vertexs.reserve(n);for (size_t i = 0; i < n; i++){_vertexs.push_back(ver[i]);_indexMap[ver[i]] = i;}//给邻接矩阵开空间_matrix.resize(n);for (auto& e : _matrix){e.resize(n, MAX_W);}}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{throw invalid_argument("顶点不存在");return -1;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src); size_t dsti = GetVertexIndex(dst);_matrix[srci][dsti] = w;if (Direction == false)//无向图{_matrix[dsti][srci] = w;}}void Print(){// 打印顶点和下标映射关系for (size_t i = 0; i < _vertexs.size(); ++i){cout << _vertexs[i] << "-" << i << " ";}cout << endl << endl;cout << " ";for (size_t i = 0; i < _vertexs.size(); ++i){cout << i << " ";}cout << endl;// 打印矩阵for (size_t i = 0; i < _matrix.size(); ++i){cout << i << " ";for (size_t j = 0; j < _matrix[i].size(); ++j){if (_matrix[i][j] != MAX_W)cout << _matrix[i][j] << " ";elsecout << "#" << " ";}cout << endl;}cout << endl << endl; 打印所有的边//for (size_t i = 0; i < _matrix.size(); ++i)//{// for (size_t j = 0; j < _matrix[i].size(); ++j)// {// if (i < j && _matrix[i][j] != MAX_W)// {// cout << _vertexs[i] << "-" << _vertexs[j] << ":" << _matrix[i][j] << endl;// }// }//}}private:vector<V> _vertexs;//顶点集合map<V, int> _indexMap;//顶点和下标建立映射vector<vector<W>> _matrix;//存储边的矩阵};void TestGraph(){Graph<char, int, INT_MAX, true> g("0123", 4);g.AddEdge('0', '1', 1);g.AddEdge('0', '3', 4);g.AddEdge('1', '3', 2);g.AddEdge('1', '2', 9);g.AddEdge('2', '3', 8);g.AddEdge('2', '1', 5);g.AddEdge('2', '0', 3);g.AddEdge('3', '2', 6);g.Print();}
}//邻接表
namespace link_table
{template<class W>struct Edge{int _dsti;//边的终止顶点下标W _w; //权值Edge<W>* _next;Edge(const int& dsti, const W& w):_dsti(dsti),_w(w),_next(nullptr){}};template<class V, class W, bool Direction = false>class Graph{typedef Edge<W> Edge;public:Graph(const V* ver, size_t n){//存储顶点并与下标建立映射_vertexs.reserve(n);for (size_t i = 0; i < n; i++){_vertexs.push_back(ver[i]);_indexMap[ver[i]] = i;}//给邻接表开空间_tables.resize(n, nullptr);}size_t GetVertexIndex(const V& v){auto it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else{throw invalid_argument("顶点不存在");return -1;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);size_t dsti = GetVertexIndex(dst);//src->dstEdge* eg = new Edge(dsti, w);eg->_next = _tables[srci];_tables[srci] = eg;//如果是无向图,再添加反向边dst->srcif (Direction == false){Edge* eg = new Edge(srci, w);eg->_next = _tables[dsti];_tables[dsti] = eg;}}void Print(){// 打印顶点for (size_t i = 0; i < _vertexs.size(); ++i){cout << "[" << i << "]" << "->" << _vertexs[i] << endl;}cout << endl;//遍历打印每个顶点的边链表for (size_t i = 0; i < _tables.size(); ++i){cout << _vertexs[i] << "[" << i << "]->";Edge* cur = _tables[i];while (cur){cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}}private:vector<V> _vertexs;//顶点集合map<V, int> _indexMap;//顶点和下标建立映射vector<Edge*> _tables; // 邻接表};void TestGraph(){string a[] = { "张三", "李四", "王五", "赵六" };Graph<string, int, true> g1(a, 4);g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.Print();}
}
3.2 Test.cpp
#define _CRT_SECURE_NO_WARNINGS#include <iostream>
using namespace std;
#include <vector>
#include <map>
#include <string>
#include "Graph.h"int main()
{//matrix::TestGraph();link_table::TestGraph();return 0;
}
相关文章:
【高阶数据结构】图详解第一篇:图的基本概念及其存储结构(邻接矩阵和邻接表)
文章目录 1. 图的基本概念1.1 什么是图1.2 有向图和无向图1.3 完全图1.4 邻接顶点1.5 顶点的度1.6 路径1.7 路径长度1.8 简单路径与回路1.9 子图1.10 连通图1.11 强连通图1.12 生成树 2. 图的存储结构2.1 邻接矩阵2.2 邻接矩阵代码实现结构定义构造函数添加边打印图测试 2.3 邻…...
IPV4跟IPV6的区别
如今互联网快速发展ipv4已经满足不了现在的需求,那么这时候就需要用更大的地址空间来代替,这时候ipv6就可以满足这一需求,相比ipv4它有更大的地址空间可供使用。下面我将分享一下有何区别。 IPv4与IPv6之间的区别: 1、地址长度的区别:IPv4具…...
利用fitnesse实现api接口自动化测试
上午在园子里乱逛,看了不少小伙伴们分享的接口测试方面的知识,仔细想想,我做接口测试也有几个年头了,大家所叙述到的一些经验或多或少,我也曾遇到过,突然意识到知识的点滴积累是多么的重要,我记…...
【LeetCode】1154.一年中的第几天
题目描述: 给你一个字符串 date ,按 YYYY-MM-DD 格式表示一个 现行公元纪年法 日期。返回该日期是当年的第几天。 示例 1: 输入:date "2019-01-09" 输出:9 解释:给定日期是2019年的第九天。示…...
4.物联网射频识别,RFID开发【智能门禁项目】
补充:学习路径 一。项目介绍及需求分析 1.酒店智能门禁使用场景介绍 1.客人入住 客人在前台办理入住手续,前台管理员通过门禁管理系统为客户开一张门禁卡 客户持卡到相应客房,用IC 卡刷卡开门 客人过了入住时间后,卡自动失效&a…...
CompletableFuture 和 Future 的选择,以及CompletableFuture的用法
在 Java 编程中,异步编程是一种重要的技术,它允许你在执行长时间运行的任务时不会阻塞主线程。为了支持异步编程,Java 提供了 Future 和 CompletableFuture 这两个关键的类。在本文中,我们将比较它们的特点、优缺点以及使用场景。…...
美国第三大财产和意外险公司利宝保险集团利用 OpenText EnCase 取证收集技术控制法律风险和成本
美国第三大财产和意外险公司利宝保险集团利用 OpenText EnCase 取证收集技术控制法律风险和成本 利宝保险集团通过内部取证收集技术控制法律风险和成本。OpenText EnCase Information Assurance(以前称为 EnCase eDiscovery)使保险公司巨头能够自信高效地…...
打包报错JavaScript heap out of memory
npm run build 的时候出现了Reached heap limit Allocation failed - JavaScript heap out of memory,报错信息如下图所示。 奇怪的时候这个报错信息在本地不会出现,通过jekins在服务器打包部署的时候才会出现。于是进入服务器执行下面一句代码ÿ…...
Android Camera FW 里的requestId和frameId
安卓相机frameworks里面经常出现requestId和frameId,最近简单看了一下代码,发现相关流程还是很复杂的,总结来看requestId 就是上层(java)发送的repeating(capture)请求的id,是从0开始递增的。 这是CameraD…...
代理IP与Socks5代理在技术世界的多元应用
在数字化时代,网络工程师的任务不仅是维护网络的稳定性,还需要应对各种技术挑战。代理IP与Socks5代理作为技术工具箱中的两把利器,在跨界电商、爬虫、出海业务、网络安全和游戏领域中发挥了关键作用。本文将深入探讨这两项技术在不同领域的多…...
计算机专业毕业设计项目推荐12-志愿者管理系统(Spring+Js+Mysql)
志愿者管理系统(SpringJsMysql) **介绍****各部分模块实现** 介绍 本系列(后期可能博主会统一为专栏)博文献给即将毕业的计算机专业同学们,因为博主自身本科和硕士也是科班出生,所以也比较了解计算机专业的毕业设计流程以及模式,在编写的过程…...
苹果文件传到mac电脑用什么软件?
在数字化时代,文件传输已经成为我们日常生活中不可或缺的一部分。然而,苹果用户在将手机文件传输到电脑时,往往会面临一些困扰。曾经的“文件传输助手”并不能完全满足用户的需求。于是,很多人开始寻找更便捷的解决方案。在本文中…...
深入理解Docker:简化部署与管理的利器
文章目录 引言Docker简介Docker的背景和发展Docker的优势和特点 Docker的基本概念和架构镜像(Image)容器(Container)仓库(Repository)Docker架构 Docker的常用命令和操作Docker的安装和配置Docker镜像的管理…...
软考对找工作有用吗?
软考是指软件技术专业资格考试,是由中国人力资源和社会保障部主管的一项国家级考试。软考的目标是评估和认证软件技术人员的专业能力,提高软件行业的整体素质和竞争力。那么,软考对找工作有用吗?本文将从以下几个方面进行分析。 首…...
Android系统启动之init进程启动+Zygote进程启动分析
一、基础概念理解 init进程 Android系统所有进程的祖先,是Android系统内核初始化完毕后,进入用户空间启动的第一个进程。 Android虚拟机 Dalvik虚拟机是谷歌自己设计的用于Android平台的虚拟机。Android4.4同时提供了Dalvik和ART虚拟机。Android5.0以后…...
微信这样的加人方式,既安全又解放双手
在当今竞争激烈的市场环境下,如何高效地管理和运营私域流量成为企业发展的关键。 1.批量自动化加好友的优势 (1)提高效率:批量自动化添加好友功能可以帮助企业添加大量潜在客户或目标客户。相比手动逐个添加好友,自动…...
CVE-2023-5129:libwebp开源库10分漏洞
谷歌为libwebp漏洞分配新的CVE编号,CVSS评分10分。 Libwebp是一个用于处理WebP格式图像编解码的开源库。9月6日,苹果公司安全工程和架构(SEAR)部门和加拿大多伦多大学研究人员在libwebp库中发现了一个0 day漏洞,随后&…...
从零开始的C++(六)
1.类和对象补充: 静态成员,有静态成员函数和静态成员变量,特点是不为类的某个对象所有,而是为同类所有对象共有。因为是为同类对象共同拥有,所以计算对象的大小的时忽略静态成员。因为静态成员是放在静态区࿰…...
leetcode 518. 零钱兑换 II、377. 组合总和 Ⅳ
518. 零钱兑换 II 给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 …...
【网络安全 --- kali2022安装】kali2022 超详细的安装教程(提供镜像)
如果你还没有安装vmware 虚拟机,请参考下面博客安装 【网络安全 --- 工具安装】VMware 16.0 详细安装过程(提供资源)-CSDN博客【网络安全 --- 工具安装】VMware 16.0 详细安装过程(提供资源)https://blog.csdn.net/m0…...
网络安全(黑客)——自学笔记
前言: 想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“…...
【C++】List -- 详解
一、list的介绍及使用 https://cplusplus.com/reference/list/list/?kwlist list 是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。 list 的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中&…...
浅谈.net 垃圾回收机制(1)
大家都知道.net程序创建对象后没法写代码销毁对象,它有它自己的处理机制,今天来大概说说它的原理,探讨下它是如何管理对象即管理内存的 在程序里使用new 关键字实例化一个对象 如果这个对象类型是引用类型则在堆上分配然后由GC管理 new 操作…...
超大视频如何优雅切片
背景 有一次录屏产生了一个大小为33G的文件, 我想把他上传到B站, 但是B站最大只支持4G. 无法上传, 因此做了一个简单的探索. 质疑与思考 a. 有没有一个工具或一个程序协助我做分片呢? 尝试 a. 必剪 > 有大小限制, 添加素材加不进去(而且报错信息也提示的不对) b. PR &…...
计算机竞赛 题目:基于深度学习卷积神经网络的花卉识别 - 深度学习 机器视觉
文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 基…...
Spring总结的question
Spring 一. 控制反转(IoC) 1.手动 使用了Spring的Configuration和Bean注解来明确指定了哪些类需要被纳入容器的管理。在AppConfig配置类中,通过Bean注解创建了Service和Controller的实例,Spring会自动将这些实例纳入容器的管理,并处理它们…...
LVS和keepalived
Keepalived及其工作原理 Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器(MASTER)和备份服务器(BACKUP)两种角色的服务器&#x…...
2023年腾讯云优惠券(代金券)无门槛领取方法汇总
腾讯云作为国内知名的云计算服务提供商,为了吸引用户,腾讯云经常推出各种优惠活动,其中包括优惠券的免费发放。通过使用优惠券,可以享受到更多的折扣和优惠,节省成本,获得更好的用户体验。那么,…...
linux scsi命令读取文件
SCSI Read(10)是一种用于从SCSI设备读取数据的命令。下面是一个简单的示例代码,演示如何使用SCSI Read(10)命令来读取指定大小的文件: #include <stdio.h> #include <stdlib.h> #include <string.h>#define READ_CAPACITY_CMD 0x2…...
c#设计模式-行为型模式 之 策略模式
🚀简介 🐤作为一个开发人员,开发需要选择一款开发工具,如在编写C#时,我们可以选择VisualStudio进行开发,也可以使用Rider 进行开发。 🐳该模式定义了一系列算法,并将每个算法封装起来…...
企业做网站怎么做/厦门人才网官方网站
前不久,SuperSocket v1.0 正式发布了。 作为.NET语言为数不多的socket服务器端框架, SuperSocket很好的支持了命令行格式的协议,很多经典的应用都可以用它来构建, 例如FTP, SMTP/POP3等等。 近期,SuperSocket又进行了几次比较大的…...
wordpress去掉图片width/搜索引擎营销的常见方式
package com.qf.greaph;import java.util.ArrayList;import java.util.Arrays;import java.util.HashMap;import java.util.Map;import java.util.Map.Entry;/*** author jiayoo* 7 / 30* Dijkstra最短路径算法是一种单源最短路径* 本文采用的是邻接表表示图。** 图的表示&…...
哈尔滨网站优化推广公司/黄石seo
在解释敏捷需求曲线时,我在上一篇文章中讲了一个好消息。 这次我想讲一个坏消息。 这是每一个经典项目经理对敏捷的恐惧,我们不经常讲述它的故事,但是它可能会发生。 一旦我讲了这个故事,我们就可以对敏捷需求曲线进行适当的分析。…...
迅当网络深圳外贸网站建设/个人网页模板
KVM是Kernel Based Virtual Machine的简称,能够利用硬件虚拟扩展来提供多种操作系统的虚拟化软件,KVM能够通过两种方式来管理,一种是命令行,另一种是图形化界面。 Virt-Manager(Virtual Machine Manager)是基于KVM使用最为频繁的管…...
网站改造设计方案/《新闻联播》 今天
通过在agent中加入脚本,来获取数据,生成图形 转载于:https://www.cnblogs.com/li-tian-jun/p/10073804.html...
暂时没有域名怎么做网站/在线磁力搜索引擎
1. 系统监视和进程控制工具—top和free1) top命令的功能:top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。2) 使用top命令列出系统状态时,系统默认每5秒刷新一下屏幕上的显示结果。1. 第一行是…...