王道408数据结构——第六章 图

文章目录

  • 一、图的基本概念
  • 二、图的储存
    • 邻接矩阵
    • 邻接表
    • 十字链表
    • 邻接多重表
  • 三、图的基本操作
  • 四、图的遍历
    • 广度优先搜索(BFS)
    • 深度优先搜索(DFS)
    • 图的遍历和图的连通性
  • 五、最小生成树
    • Prim算法
    • Kruskal算法
  • 六、最短路径
    • Dijkstra求单源最短路径
    • Floyd算法求解各顶点间的最短路径问题
  • 七、有向无环图(DAG图)描述表达式
  • 八、拓扑排序
  • 九、关键路径

一、图的基本概念

图G有定点集V和边集E组成,记为G=(V,E),其中V(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)集合。用∣V∣|V|V表示图G中顶点个数,用∣E∣|E|E表示图G中边的条数。图不能是空图,最少要有一个顶点。

对于无向图,|E|的取值范围为0到n(n−1)/2n(n-1)/2n(n1)/2,有n(n−1)/2n(n-1)/2n(n1)/2条边的无向图称为完全图
对于有向图,|E|的取值范围为0到n(n−1)n(n-1)n(n1),有n(n−1)n(n-1)n(n1)条弧的有向图称为完全图

若图G和图G’顶点相同,E(G’)是E(G)的子集,则成G’是G的生成子图

无向图中,任意两个顶点都是连通的。称为连通图。无向图中的极大连通子图称为连通分量。假设一个图有n个顶点,如果边数小于n-1,其必定是非连通图。

有向图中,如果有一对顶点v、w,从v到w和从w到v之间都有路径,称这两个顶点是强连通的。若图中任何一对顶点都是强连通的,称此图为前连通图。有向图的极大强连通子图称为强连通分量。假设一个图有n个顶点,至少需要n-1条边,构成强连通分量,此时为一个环路。

连通图的生成树是包含图中全部顶点的一个极小连通子图。若图中顶点数为n,则它的生成树有n-1条边。

无向图的全部顶点之和等于边数的两倍,;
有向图全部顶点的入度之和与出度之和相等,并且等于边数。有向图顶点的度为入度和出度之和。

一个顶点的入度为0、其余顶点入度均为1的有向图,称为有向树

二、图的储存

邻接矩阵

用一个一维数组储存图中顶点的信息,有一个二维数组(邻接矩阵)储存图中边的信息。
无向图的邻接矩阵是对称矩阵,实际储存时只需储存三角矩阵元素。

邻接矩阵的空间复杂度为O(∣V∣2)O(|V|^2)O(V2)

可以很方便地确定两个顶点之间是否有边相连,但要确定图中有多少条边,必须遍历每个元素。

适合表示稠密图

邻接矩阵储存结构定义如下

typedef struct{vertexType vex[MaxVertexNum];  // 顶点表edgeType edge[MaxVertexNum][MaxVertexNum];  // 邻接矩阵(边表)int vexNum, edgeNum;  // 当前顶点数和边数
}MGraph;

邻接表

对图中每个顶点建立一个单链表(边表、出边表),每个单链表中的结点表示依附与该顶点的边(对于有向图,表示以该顶点为尾的弧)。边表的头指针和顶点的数据采用顺序存储(顶点表)。

对于无向图,所需储存空间为O(2∣E∣+∣V∣)O(2|E|+|V|)O(2E+V)
对于有向图,所需存储空间为O(∣E∣+∣V∣)O(|E|+|V|)O(E+V)

可以很方便找到一个顶点的所有临边。
在有向图中,求顶点的出度只需计算邻接表的结点个数,但求入度需要遍历所有邻接表。

适合表示稀疏图,能极大节省存储空间。

邻接表储存结构定义如下

typedef struct{  // 顶点结点vertexType data;ArcNode *first;  // 指向第一个依附该顶点的弧
}VerNode, VerList[MaxVertexNum];struct ArcNode{  // 边结点int vertex;  // 该边指向的顶点序号edgeType data;struct ArcNode *next;  // 指向下一个边
}typedef struct{VerList VerList;  // 邻接表int vexNum, edgeNum;
}AlGraph;

十字链表

是有向图的一种链式储存结构。每条弧和每个顶点都有一个结点表示。顶点结点顺序存储。

弧结点结构tailvexheadveshlinktlinkinfo
作用尾域,标识弧尾顶点头域,标识弧头顶点指向弧头相同的下一条弧指向弧尾相同的下一条弧携带弧的相关信息
顶点结点结构datafirstinfirstout
作用存放顶底数据信息指向以该顶点为弧头的第一个弧结点指向以该顶点为弧尾的第一个弧结点

在这里插入图片描述
在十字链表中,既容易找到以一个顶点为尾的弧,又容易找到以一个顶点尾头的弧,因而容易求得入度和出度。

邻接多重表

是无向图的一种链式存储结构。每条边和每个顶点也各用一个结点表示。

顶点结点结构markivexilinkjvexjlinkinfo
作用标志域,记录该边是否被搜索过标识边依附的第一个顶点指向下一条依附ivex的边标识边依附的另一个顶点指向下一条依附jvex的边携带相关信息

在这里插入图片描述
在邻接多重表中,所有依附域同一顶点的边串联在同一链表中。由于每条边依附于两个顶点,所以每个边结点同时链接在两个链表中。
对于无向图,其邻接多重表和邻接表的差别仅在于,同一条表在邻接表中用两个结点表示,而在邻接多重表中只有一个结点。

三、图的基本操作

  • adjacent(G, x, y):判断图G中是否存在边<x, y>
  • neighbor(G, x):列出图G中于顶点x相邻的边
  • insertVertex(G, x):在图中插入顶点x
  • deleteVertex(G, x):在图中删除顶点x
  • addEdge(G, x, y):在图中添加边<x, y>
  • removeEdge(G, x, y):在图中删除边<x, y>
  • firstNerghbor(G, x):求顶点x的第一个邻接点
  • nextNerghbor(G, x, y):返回除y以外的顶点x的下一个邻接点
  • getEdgeValue(G, x, y)
  • setEdgeValue(G, x, y, v)

四、图的遍历

在遍历图的过程中,必须记下每个已访问过的顶点。

广度优先搜索(BFS)

类似树的层序遍历,广度优先搜索是一个分层的查找过程,没有回退的过程,必须借助一个辅助队列,记忆正在访问的顶点的下一层顶点。

int visited[MAX_VERTEX_NUM];void BFSTraverse(Graph G){for(int i=0; i<G.vexNum; i++)visited[i] = 0;for(int i=0; i<G.vexNum; i++)if( !visit[i] )BFS(G, i);
}void BFS(Graph G, int v){initQueue(Q);visit(v);visited[v] = 1;enQueue(Q, v);while( !isEmpty(Q) ){deQueue(Q, v);for(w=firstNeighbor(G, v); w>=0; w=nextNeighbor(G, v, w)){if(!visited[w]){visit(w);visited[w] = 1;enQueue(Q, w);}}}}

无论采用邻接表还是邻接矩阵,BFS都需要借助一个辅助队列,所有顶点均需入队一次。最坏情况下,空间复杂度为O(∣V∣)O(|V|)O(V)
采用邻接表存储时,每个顶点均需被搜索依次,时间复杂度为O(∣V∣)O(|V|)O(V);在搜索任一顶点的边时,每一条边至少访问依次,总时间复杂度为O(∣E∣)O(|E|)O(E)。算法总的时间复杂度为O(∣V∣+∣E∣)O(|V|+|E|)O(V+E)
采用邻接矩阵存储时,查找每个顶点的所有邻接点的时间为O(V)O(V)O(V),算法总的时间复杂度为O(∣V∣2)O(|V|^2)O(V2)

借助BFS,可以求解非带权图的单源最短路径问题。

在广度遍历中,可以得到一棵遍历树,称为广度优先生成树。邻接矩阵产生的生成树是唯一的,而邻接表产生的生成树不唯一。

深度优先搜索(DFS)

类似树的先序遍历,先尽可能“深”的搜索一个图,当不能继续向下访问时,依次退回最近被访问的顶点,若其还有未被访问的邻接顶点,则从这个邻接顶点继续该搜索过程。

DFS是一个递归的过程,需要借助一个递归工作栈,空间复杂度为O(∣V∣)O(|V|)O(V)
采用邻接表存储时,访问所有顶点的时间复杂度为O(∣V∣)O(|V|)O(V),查找所有顶点的邻接点的总时间复杂度为O(∣E∣)O(|E|)O(E),故算法总的时间复杂度为O(∣V∣+∣E∣)O(|V|+|E|)O(V+E)
采用邻接表存储是,查找一个顶点的所有邻接点所需时间为O(|V|),故总的时间复杂度为O(∣V∣2)O(|V|^2)O(V2)

借助DFS,可以求解有向无环图的拓扑排序问题。

在深度遍历中,可以得到一棵遍历树,称为深度优先生成树。邻接矩阵产生的生成树是唯一的,而邻接表产生的生成树不唯一。

图的遍历和图的连通性

对于无向图,若图是连通的,则从任一顶点出发,仅需一次遍历就可以访问图中的所有顶点。
对于有向图,若从初始顶点到图中每个顶点都有路径,则能访问到图中的所有顶点。一个有向图的连通子图分为强连通分量和非强连通分量,非强连通分量调用一次搜索过程无法访问到所有顶点。

五、最小生成树

最小生成树具有如下特征:

  • 最小生成树不是唯一的。但图中各边的权值互不相等是,生成树唯一。
  • 若无向连通图的边数比顶点数少1,它本身就是其的最小生成树。
  • 最小生成树边的权值之和总是唯一的,且是最小的。

Prim算法

初始时从图中任取一顶点加入树T,此时树中只含有一个顶点。之后选择一个与T中顶点距离最近的顶点,将顶点和相应的边加入T中。每次操作,T中的顶点数和边数都增加1,直到所有顶点都加入T。
prim算法基于贪心策略,其简单实现如下

def prim(G):T = set()  # 初始化空边集U = {w}  # 初始化顶点集,添加任一顶点w# 若树中未包含全部顶点,选择一个加入while not (V - U):  # (u,v)是u∈U,v∈(V-U)且权值最小的边# 此处最坏情况需要遍历所有n个顶点,时间复杂度为O(n)find a edge (u, v)  U.add(v)  # 将选定的点加入顶点集T.add((u, v))  # 将选定的边加入边集

算法的时间复杂度为O(∣V∣2)O(|V|^2)O(V2),适合求解稠密图的最小生成树。

Kruskal算法

初始时只有n个顶点而无边的非连通图T={ V,{ } },每个顶点自成一个连通分量。然后按边权值从小到大的顺序,查看当前为被选取且权值最小的边,若该边依附的两个顶点落在T中不同的连通分量中,则将此边加入T。
kruskal算法基于贪心策略,其简单实现如下

def kruskal(G):T = V  # 初始化树,仅含所有顶点numS = n  # 连通分量数while numS > 1:# 从边集中找到权值最小的边pop a edge with shortest length (u, v)if (u ,v) belong to different connected components:T.add((u, v))  # 将此边加入生成树中numS = numS - 1

通常在kruskal算法中,采用堆来存放边的集合,每次选择边只需O(log⁡∣E∣)O(\log |E|)O(logE)的时间。此外,由于生成树T中的所有边可视为一个等价类,每次添加新边的过程类似求解等价类的过程,可以采用并查集的数据结构来描述T,构造T总的时间复杂度为O(∣E∣log⁡∣E∣)O(|E|\log |E|)O(ElogE)。适合求解稀疏图的最小生成树。

六、最短路径

把带权路径长度最短的那条路径称为最短路径
重要性质:两点之间的最短路径也包含了路径上其他点间的最短路径。

Dijkstra求单源最短路径

设置一个集合S,记录已求得的最短路径的顶点。初始时把源点v0v_0v0放入SSS。集合S每并入一个新顶点viv_ivi,都要修改v0v_0v0到集合V−SV-SVS中顶点的当前最短路径长度。
设置两个辅助数组:

  • dist[]:记录从源点v0v_0v0到其他各顶点当前的最短路径长度。它的初态为:若从v0v_0v0viv_ivi有弧,则dist[i]设为弧上权值,否则置为∞\infty
  • path[]:path[i]表示从源点到顶点i最短路径的前驱结点。在算法结束时,可根据其值追溯到源点的最短路径。

假设从顶点0出发,即v0=0v_0=0v0=0,集合SSS最初只包含顶点0,邻接矩阵arcs表示带权有向图,arcs[i][j]表示有向边<i, j>的权值。若不存在有向边,arcs[i][j]置为∞\infty

Dijkstra算法基于贪心策略,步骤如下:

  1. 初始化:集合S初始为{0},dist[]初始值为dist[i] = arcs[0][i]。
  2. 从顶点集合V−SV-SVS中选出vjv_jvjvjv_jvj是集合V−SV-SVS中到v0v_0v0距离最短的顶点,即满足dist[j]=min{dist[i]∣vi∈V−S}dist[j] =min \{dist[i]\mid v_i\in V-S\}dist[j]=min{dist[i]viVS},此时 vjv_jvj就是当前求得的一条从v0v_0v0出发的最短路径的终点。再令S=S∪{j}S=S\cup\{j\}S=S{j}
  3. 修改从v0v_0v0到集合V−SV-SVS上所有顶点vkv_kvk可达的最短路径长度:
    若dist[j] + arcs[j][k] <dist[k], 更新dist[k] = dist[j] + arcs[j][k]。
  4. 重复二、三步n-1次,直到所有顶点都包含在S中。

Djkstra算法并不适用于带负权值的有向图

算法时间复杂度为O(∣V∣2)O(|V|^2)O(V2)

Floyd算法求解各顶点间的最短路径问题

递推产生一个n阶方阵序列A(−1),A(0),...,A(k),...,A(n−1)A^{(-1)}, A^{(0)},...,A^{(k)},...,A^{(n-1)}A(1),A(0),...,A(k),...,A(n1),其中A(k)[i][j]A^{(k)}[i][j]A(k)[i][j]表示从顶点viv_ivivjv_jvj的路径长度,k表示绕行第k个顶点的运算步骤。
初始时,对于任意两个顶点,若它们之间存在弧,则以此边上的权值作为它们之间的最短路径长度;若它们不存在有向边,则置为∞\infty
以后逐步尝试在原路径中加入顶点k作为中间顶点,若增加中间顶点后,它们之间的路径长度比原来的路径减少了,则以此新路径代替原路径。

算法描述如下:
定义一个n阶反正序列A(−1),A(0),...,A(n−1)A^{(-1)}, A^{(0)},...,A^{(n-1)}A(1),A(0),...,A(n1),其中

  • A(−1)[i][j]=arcs[i][j]A^{(-1)}[i][j]=arcs[i][j]A(1)[i][j]=arcs[i][j]
  • A(k)=min⁡{A(k−1)[i][j],A(k−1)[i][k]+A(k−1)[k][j]}A^{(k)}=\min\{A^{(k-1)}[i][j],A^{(k-1)}[i][k]+A^{(k-1)}[k][j]\}A(k)=min{A(k1)[i][j],A(k1)[i][k]+A(k1)[k][j]}

Floyd算法是一个迭代的过程,每迭代一次,在从viv_ivivjv_jvj的最短路径上就多考虑一个顶点。经过n次迭代后,所得到的A(n−1)[i][k]A^{(n-1)}[i][k]A(n1)[i][k]就是viv_ivivjv_jvj的最短路径,方阵A(n−1)A^{(n-1)}A(n1)保存了任意一对顶点之间的最短路径长度。

Floyd算法允许图中有带负权值的边,但不允许有包含带负权值边的回路。
Floyd算法同样适合带权无向图,因为无向图可视为权值相同往返二重边的有向图。

算法的时间复杂度为O(∣V∣3O(|V|^3O(V3),但对于中等规模的输入,仍然有效。

七、有向无环图(DAG图)描述表达式

DAG图是描述含有公共子式的表达式的有效工具。
用二叉树描述表达式时,相同的子式会重复出现,使用DAG图可以对相同子式的共享,从而节省存储空间。
在这里插入图片描述

八、拓扑排序

AOV网:若用DAG图表示一个工程,其顶点表示活动,用有向边<vi,vj><v_i,v_j><vi,vj>表示活动ViV_iVi必须先于ViV_iVi进行,则间这种有向图称为顶点表示活动的网络,记为AOV网。
拓扑排序:由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时:

  1. 每个顶点出现且仅出现一次;
  2. 若顶点A在序列中排在B的前面,则在图中不存在从B到A的路径。

称这个序列为该图的一个拓扑排序。每个AOV网都有一个或多个拓扑排序序列。

拓扑排序常用算法如下

  1. 从AOV网中选择一个没有前驱的顶点并输出;
  2. 从网中删除该顶点和以该顶点为起点的所有边;
  3. 重复前面两部直到AOV网为空或网中不存在无前驱的顶点位置。后一种情况说明有向图中存在环

由于输出每个顶点的同时还有删除以它为起点的边,故拓扑排序的时间复杂度为O(∣V∣+∣E∣)O(|V|+|E|)O(V+E)

由于AOC网中各顶点地位平等,每个顶点的编号都是人为的,因此可以按拓扑排序的结果重新编号,生成AOV网的新的邻接存储矩阵,这种邻接矩阵可以时三角矩阵。对于一个图,若其邻接矩阵是三角矩阵,其必存在拓扑排序。

九、关键路径

AOE网:在带权有向无环图中,若以顶点表示事件,以有向边表示活动,以边上的权值代表活动的开销,则称其为用边表示活动的图,记为AOE网。
在AOE网中仅有一个入度为0的点,称为开始顶点(源点),表示整个工程的开始;仅有一个出度为0的点,称为结束顶点(汇点),表示整个工程的结束。
从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径,它决定了完成整个工程的最短时间。关键路径上的活动称为关键活动

  • 事件最早发生时间ve(k)ve(k)ve(k)
    指从源点viv_ivi到顶点vkv_kvk的最长路径长度,决定了所有从vkv_kvk开始的活动能够开工的最早时间。可以用下面的递推公式计算:
    {ve(源点)=0ve(k)=max⁡{ve(j)+weight(vj,vk)},vk为vj的任意后继\left\{ \begin{array}{l} ve(源点)=0\\ ve(k)=\max\{{ve(j)}+weight(v_j,v_k)\},v_k为v_j的任意后继 \end{array} \right.{ve()=0ve(k)=max{ve(j)+weight(vj,vk)},vkvj
    计算ve()ve()ve()时,按从前往后的顺序进行,可以在拓扑排序的基础上进行。
  • 事件最迟发生时间vl(k)vl(k)vl(k)
    指在不推迟整个工程完成的前提下(即保证它的后继事件在其最迟发生时间内能够发生),该事件最迟必须发生时间。可以用下面的递推公式计算:
    {vl(汇点)=ve(汇点)vl(k)=min⁡{vl(j)−weight(vk,vj)},vk为vj的任意前驱\left\{ \begin{array}{l} vl(汇点)=ve(汇点) \\ vl(k)=\min\{vl(j)-weight(v_k,v_j)\},v_k为v_j的任意前驱 \end{array} \right. {vl()=ve()vl(k)=min{vl(j)weight(vk,vj)}vkvj
    在计算vl()vl()vl()时,按从后往前的顺序进行,可以在逆拓扑排序的基础上计算(可以在计算ve()时设置一个栈记录拓扑序列,拓扑排序结束后从栈顶至栈底变为逆拓扑排序序列)
  • 活动最早开始时间e(i)e(i)e(i)
    指活动弧的起点所表示的事件的最早发生时间。若<vk,vj><v_k,v_j><vk,vj>表示活动aia_iai,则有e(i)=ve(k)e(i)=ve(k)e(i)=ve(k)
  • 活动最迟开始时间l(i)l(i)l(i)
    指活动弧的终点所表示的事件的最迟发生事件与该活动所需时间的差值。若<vk,vj><v_k,v_j><vk,vj>表示活动aia_iai,则有l(i)=vl(j)−weight(vk,vj)l(i)=vl(j)-weight(v_k,v_j)l(i)=vl(j)weight(vk,vj)
  • 活动最早开始时间和最迟开始时间的差额d(i)d(i)d(i)
    指该活动完成的时间余量,即在不增加整个工程所需总时间的情况下,活动aia_iai可以拖延的时间。d(i)=l(i)−e(i)d(i)=l(i)-e(i)d(i)=l(i)e(i)
    若一个活动的时间余量为0,即l(i)=e(i)l(i)=e(i)l(i)=e(i),说明该活动必须要如期完成,否则就会拖延整个工程的进度,称其为关键活动。

求解关键路径的算法步骤如下:

  1. 从源点出发,令ve(源点)=0ve(源点)=0ve()=0,按拓扑有序求其余顶点的最早发生时间;
  2. 从汇点出发,令le(汇点)=ve(汇点)le(汇点)=ve(汇点)le()=ve(),按逆拓扑有序求其余顶点的最迟发生时间;
  3. 根据各顶点的ve()ve()ve()值求所有弧的最早开始时间;
  4. 根据各顶点的vl()vl()vl()值求所有弧的最迟开始时间;
  5. 求AOE网中所有活动的差额,找出所有d()=0d()=0d()=0的活动,构成关键路径。

关键路径上的所有活动都是关键活动,可以通过加快关键活动来缩短整个工程的工期。但不能任意缩短关键活动,因为一旦缩短到一定程度,关键活动就可能会变成非关键活动。
AOE网中的关键路径不是唯一的,对于有多条关键路径的AOE网,只提高一条关键路径上的关键活动速度并不能缩短整个工期。

可以判断一个有向图是否有环的算法:

  • 深度优先遍历
  • 拓扑排序
  • 求关键路径(预先要使用拓扑排序判断是否有环)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290467.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 python 的 urllib2和 urllib模块爆破 form 表单的简易脚本

python 的 http 中 urllib2和 urllib模块在web 表单爆破的使用方法脚本中还增加了 urllib2和 urllib模块如何添加代理的方法# -*- coding: utf-8 -*- import urllib2 import urllib import timedef brute_force(user, password):#strip() 方法用于移除字符串头尾指定的字符&…

如何在 ASP.NET Core 中为同一接口配置不同的实现

前言通常&#xff0c;我们使用依赖注入时&#xff0c;一个接口仅对应一种实现&#xff0c;使用时可以直接得到实现类的实例&#xff0c;类似这样&#xff1a;services.AddScoped<IServiceA,ServiceA>();public WeatherForecastController(IServiceA service) { }但是&…

分析windows宿主机Ping不通linux虚拟机的其中一种情况

ping不通的情况是由于设置网络选项的时候&#xff0c;可以看到界面名称的选择如下(当前选择的是无线网卡驱动): ping得通的情况是由于设置网络选项的时候&#xff0c;可以看到界面名称的选择如下(当前选择的是有线网卡驱动): 分析原因是由于电脑有两个网卡驱动&#xff0c;一个…

同事都说有SQL注入风险,我非说没有

前言现在的项目&#xff0c;在操作数据库的时候&#xff0c;我都喜欢用ORM框架&#xff0c;其中EF是一直以来用的比较多的&#xff1b;EF 的封装的确让小伙伴一心注重业务逻辑就行了&#xff0c;不用过多的关注操作数据库的具体细节。但是在某些场景会选择执行SQL语句&#xff…

​【v2.x OGE-example 第二节】 实体参数

【v2.x OGE-example 第二节】 实体参数1. 位置&#xff1a;Drawing_example --> SpriteParameters2. 类名&#xff1a;SpriteParameters(1)旋转精灵&#xff1a;sprite.setRotation(float pRotation) 设置旋转角度sprite.setRotationCenter(float pRotationCenterX, float p…

王道408数据结构——第七章 查找

文章目录一、基本概念二、顺序查找&#xff08;线性查找&#xff09;一般线性表的顺序查找有序表的顺序查找二、折半查找&#xff08;二分查找&#xff09;三、分块查找&#xff08;索引顺序查找&#xff09;四、B树五、B树六、散列表构造散列函数1. 直接定址法2. 除留取余法3.…

设置utf8编码问题

注意&#xff1a;乱码和request的具体实现类有关&#xff0c;现在已经查到的是RequestDispatcher.forward调用前使用的是org.apache.catalina.connector.RequestFacade类而RequestDispatcher.forward调用后使用的是org.apache.catalina.core.ApplicationHttpRequest&#xff0c…

王道408数据结构——第八章 排序

文章目录一、排序定义二、插入排序——直接插入排序1. 描述2. 代码和示例3. 空间效率4. 时间效率5. 稳定性6. 适用性三、插入排序——折半插入排序1. 描述2. 时间效率3. 稳定性四、插入排序——希尔排序&#xff08;缩小增量排序&#xff09;1. 描述2. 代码和示例3. 空间效率4.…

Avalonia跨平台入门第二十一篇之玩耍CEF

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果、控件的置顶和置底、控件的锁定、自定义Window样式、动画效果、Expander控件、ListBox折叠列表、聊天窗口、ListBox图片消息、窗口抖动、语音发送、语音播放、语音播放问题;今…

golang实现自定义驱动的Cache

近期在写 ActivedRouter项目的时候需求一个缓存模型&#xff0c;要求缓存模型支持不同驱动,例如:memory、file、redis、mysql&#xff0c;实现思路代码如下: cache.go文件,定义缓存对外接口 //ActivedRouter //Author:usher.yue //Amail:usher.yuegmail.com //TencentQQ:422366…

【自定义控件】c#winform自定义控件实现标签控件

介绍首先我们设计这个控件的时候要明白控件是怎样交互的&#xff0c; 熟悉b站的小伙伴应该知道 &#xff0c;我们上传视频的时候会去选择标签 &#xff0c;我们输入标签文本 按下回车就代表该标签已经添加成功了&#xff0c;效果图如下&#xff01;控件拆分我们首先拆分一下该控…

ASP.NET 使用Ajax(转)

之前在Ajax初步理解中介绍了对Ajax的初步理解&#xff0c;本文将介绍在ASP.NET中如何方便使用Ajax&#xff0c;第一种当然是使用jQuery的ajax&#xff0c;功能强大而且操作简单方便&#xff0c;第二种是使用.NET封装好的ScriptManager。 $.ajax向普通页面发送get请求 这是最简单…

fir.im 持续集成技术实践

互联网时代&#xff0c;人人都在追求产品的快速响应、快速迭代和快速验证。不论是创业团队还是大中型企业&#xff0c;都在探索属于自己的敏捷开发、持续交付之道。fir.im 团队也在全面实施敏捷&#xff0c;并推出新持续集成服务— flow.ci &#xff0c;以帮助企业将开发测试流…

宇宙最強的IDE - Visual Studio 25岁生日快乐

每位开发者从入门开始或多或少都会接触过 Visual Studio &#xff0c; 现今的 Visual Studio 除了支持传统的 C , C# , Visual Basic.NET ,F# 的编程语言外&#xff0c;还可以做 Python , Node.js 的开发。在应用场景上也从单一的桌面应用&#xff0c;延伸到 Web &#xff0c; …

有没有一段代码,让你觉得人类的智慧也可以璀璨无比?【转】

转自&#xff1a;https://www.zhihu.com/question/30262900 作者&#xff1a;烧茄子链接&#xff1a;https://www.zhihu.com/question/30262900/answer/48741026来源&#xff1a;知乎著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。当然是这个…

如何使用 abp 创建 module 并应用单独的数据库迁移

最近在学习使用 abp 来做一些小程序。abp 是一个功能丰富的 .NET 开发框架&#xff0c;完全开源&#xff0c;遵循 DDD&#xff08;领域驱动&#xff09;设计模式&#xff0c;支持微服务开发&#xff0c;集成了 Identity、角色权限、本地化、动态代理、后台任务、分布式消息、审…

MinGW安装和使用基础教程

MinGW全称Minimalist GNU For Windows&#xff0c;是个精简的Windows平台C/C、ADA及Fortran编译器&#xff0c;相比Cygwin而言&#xff0c;体积要小很多&#xff0c;使用较为方便。MinGW提供了一套完整的开源编译工具集&#xff0c;以适合Windows平台应用开发&#xff0c;且不依…

px,em,rem,vw单位在网页和移动端的应用

px&#xff1a; 是网页设计中最常用的单位&#xff0c;然而1px到底是多大长&#xff0c;恐怕没有人能回答上来 它用来表示屏幕设备物理上能显示的最小的一个点&#xff0c;这个点不是固定宽度的&#xff0c;不同设备上点的长度、比例有可能会不同。 假设&#xff1a;你现在用的…

cs-Panination

ylbtech-Unitity: cs-PaninationPager.cs IPagingOption.cs IPagedList.cs PagingOption.cs PagedList.cs PagingExtensions.cs 1.A,效果图返回顶部 1.B,源代码返回顶部1.B.1,Pager.cs using System; using System.Collections.Generic; using System.Linq; using System.Text…

SignalR的使用

什么是 SignalR&#xff1f;ASP.NET Core SignalR 是一个开放源代码库&#xff0c;可用于简化向应用添加实时 Web 功能。实时 Web 功能使服务器端代码能够将内容推送到客户端。适合 SignalR 的候选项&#xff1a;需要从服务器进行高频率更新的应用。示例包括游戏、社交网络、投…