【学习笔记】网络流算法简单入门

【学习笔记】网络流算法简单入门


【大前言】

网络流是一种神奇的问题,在不同的题中你会发现各种各样的神仙操作。

而且从理论上讲,网络流可以处理所有二分图问题。

二分图和网络流的难度都在于问题建模,一般不会特意去卡算法效率,所以只需要背一两个简单算法的模板就能应付大部分题目了。


\[ QAQ \]


一:【基本概念及性质】

【网络流基本概念】

  • 网络流 \((NetWork\) \(Flow)\) 一种类比水流的解决问题的方法。
    (下述概念均会用水流进行解释)

  • 网络 \((NetWork)\) 可以理解为拥有源点汇点有向图
    (运输水流的水管路线路)

  • \((arc)\) 可以理解为有向边。下文均用 “边” 表示。
    (水管)

  • 弧的流量 \((Flow)\) 简称流量。在一个流量网络中每条边都会有一个流量,表示为 \(f(x,y)\) ,根据流函数 \(f\) 的定义,\(f(x,y)\) 可为负。
    (运输的水流量)

  • 弧的容量 \((Capacity)\) 简称容量。在一个容量网络中每条边都会有一个容量,表示为 \(c(x,y)\)
    (水管规格。即可承受的最大水流量)

  • 源点 \((Sources)\) 可以理解为起点。它会源源不断地放出流量,表示为 \(S\)
    (可无限出水的 \(NB\) 水厂)

  • 汇点 \((Sinks)\) 可以理解为终点。它会无限地接受流量,表示为 \(T\)
    (可无限收集水的 \(NB\) 小区)

  • 容量网络: 拥有源点汇点且每条边都给出了容量网络
    (安排好了水厂,小区和水管规格的路线图)

  • 流量网络: 拥有源点汇点且每条边都给出了流量网络
    (分配好了各个水管水流量的路线图)

  • 弧的残留容量: 简称残留容量。在一个残量网络中每条边都会有一个残留容量 。对于每条边,残留容量 \(=\) 容量 \(-\) 流量。初始的残量网络即为容量网络
    (表示水管分配了水流量后还能继续承受的水流量)

  • 残量网络: 拥有源点汇点且每条边都有残留容量网络残量网络 \(=\) 容量网络 \(-\) 流量网络
    (表示了分配了一定的水流量后还能继续承受的水流量路线图)

关于流量,容量,残留容量的理解见下图:
(用 \(c\) 表示容量,\(f\) 表示流量,\(flow\) 表示残留容量
o_NetWork_1_.png


【网络流三大性质】

  • 容量限制: \(\forall (x,y) \in E,f(x,y) \leqslant c(x,y)\)
    (如果水流量超过了水管规格就爆了呀)

  • 流量守恒: \(\forall x \in V且x \ne S且x \ne T,\sum_{(u,x) \in E}f(u,x) = \sum_{(x,v) \in E}f(x,v)\)
    (对于所有的水管交界处,有多少水流量过来,就应有多少水流量出去,保证水管质量良好不会泄露并且不会无中生有)

  • 斜对称性: \(\forall (x,y) \in E,f(y,x)=-f(x,y)\)
    (可以暂且感性理解为矢量的正负。在网络流问题中,这是非常重要的一个性质)


还有一些其他的概念和性质将在后面补充。


\[ QAQ \]


二:【最大流】

1.【概念补充】

  • 网络的流量: 在某种方案下形成的流量网络汇点接收到的流量值。
    (小区最终接收到的总水流量)

  • 最大流: 网络的流量的最大值。
    (小区最多可接受到的水流量)

  • 最大流网络: 达到最大流流量网络
    (使得小区接收到最多水流量的分配方案路线图)


2.【增广路算法 ( EK )】

【概念补充】
  • 增广路 \((Augmenting\) \(Path)\) 一条在残量网络中从 \(S\)\(T\) 的路径,路径上所有边的残留容量都为正。
    (可以成功从水厂将水送到小区的一条路线)

  • 增广路定理 \((Augmenting\) \(Path\) \(Theorem)\) 流量网络达到最大流当且仅当残量网络中没有增广路
    (无法再找到一路线使得小区获得更多的流量了)

  • 增广路方法 \((Ford-Fulkerson)\) 不断地在残量网络中找出一条从 \(S\)\(T\)增广路,然后根据木桶定律汇点发送流量并修改路径上的所有边的残留容量,直到无法找到增广路为止。该方法的基础为增广路定理,简称 \(FF\) 方法。
    (如果有一条路径可以将水运到小区里就执行,直到无法再运送时终止)

  • 增广路算法 \((Edmonds-Karp)\) 基于增广路方法的一种算法,核心为 \(bfs\) 找最短增广路,并按照 \(FF\) 方法执行操作。增广路算法的出现使得最大流问题被成功解决,简称 \(EK\) 算法。

【算法流程】

下面对 \(EK\) 算法作详细介绍。

\((1).\)\(bfs\) 找到任意一条经过边数最少的最短增广路,并记录路径上各边残留容量的最小值 \(cyf\)(残\(c\)\(y\) \(flow\))。 (木桶定律。众多水管一个也不能爆,如果让最小的刚好不会爆,其它的也就安全了)

\((2).\) 根据 \(cyf\) 更新路径上边及其反向边的残留容量值。答案(最大流)加上 \(cyf\)

\((3).\) 重复 \((1),(2)\) 直至找不到增广路为止。

对于 \((2)\) 中的更新操作,利用链表的特性,从 \(2\) 开始存储,那么 \(3\)\(2\) 就互为一对反向边,\(5\)\(4\) 也互为一对反向边 \(......\)
只需要记录增广路上的每一条边在链表中的位置下标,然后取出来之后用下标对 \(1\) 取异或就能快速得到它的反向边。

【算法理解】

关于建图

在具体实现中,由于增广路是在残量网络中跑的,所以只需要用一个变量 \(flow\) 记录残留容量就足够了,容量流量一般不记录。

为了保证算法的最优性(即网络的流量要最大),可能在为某一条边分配了流量后需要反悔,所以要建反向边。在原图中,正向边的残留容量初始化为容量,反向边的残留容量初始化为 \(0\)(可理解为反向边容量\(0\))。

当我们将边 \((x,y)\)(在原图中可能为正向也可能为反向)的残留容量 \(flow\) 用去了 \(F\) 时,其流量增加了 \(F\)残留容量 \(flow\) 应减少 \(F\)。根据斜对称性,它的反边 \((y,x)\) 流量增加了 \(-F\)残留容量 \(flow'\) 应减去 \(-F\)(即加上 \(F\))。

那么如果在以后找增广路时选择了这一条边,就等价于:将之前流出去的流量的一部分(或者全部)反悔掉了个头,跟随着新的路径流向了其它地方,而新的路径上在到达这条边之前所积蓄的流量 以及 之前掉头掉剩下的流量 则顺着之前的路径流了下去

同理,当使用了反向边 \((y,x)\)残留容量时也应是一样的操作。

还是之前那个图,下面是找到了一条最短增广路 \(1 → 3 → 2 → 4\)(其中三条边均为黑边)后的情况:
(不再显示容量和流量,用 \(flow\) 表示残留容量,灰色边表示原图上的反向边,蓝色小水滴表示水流量)
o_NetWork_2_.png

然后是第二条最短增广路 \(1 → 7 → 6 → 2 \dashrightarrow 3 → 8 → 5 → 4\)(其中 \(f(2,3)\)灰边,其余均为黑边,紫色小水滴表示第二次新增的水流量):
o_NetWork_3_.png

注:由于在大部分题目中都不会直接使用容量和流量,所以通常会直接说某某之间连一条流量为某某的边,在没有特别说明的情况下,其要表示的含义就是残留容量。后面亦不再强调“残留”,直接使用“流量”。

【时间复杂度分析】

每条边最多会被增广 \(O(\frac{n}{2}-1)\) 次(证明),一共 \(m\) 条边,总增广次数为 \(nm\)
一次 \(bfs\) 增广最坏是 \(O(m)\) 的,\(bfs\) 之后更新路径上的信息最坏为 \(O(n)\)(可忽略)。
最坏时间复杂度为:\(O(nm^2)\)

实际应用中效率较高,一般可解决 \(10^4\) 以内的问题。

【Code】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define Re register int
using namespace std;
const int N=1e4+3,M=1e5+3,inf=2e9;
int x,y,z,o=1,n,m,h,t,st,ed,maxflow,Q[N],cyf[N],pan[N],pre[N],head[N];
struct QAQ{int to,next,flow;}a[M<<1];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z){a[++o].flow=z,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline int bfs(Re st,Re ed){
    for(Re i=0;i<=n;++i)pan[i]=0;
    h=1,t=0,pan[st]=1,Q[++t]=st,cyf[st]=inf;//注意起点cfy的初始化
    while(h<=t){
        Re x=Q[h++];
        for(Re i=head[x],to;i;i=a[i].next)
            if(a[i].flow&&!pan[to=a[i].to]){//增广路上的每条边残留容量均为正
                cyf[to]=min(cyf[x],a[i].flow);
                //用cyf[x]表示找到的路径上从S到x途径边残留容量最小值
                Q[++t]=to,pre[to]=i,pan[to]=1;//记录选择的边在链表中的下标
                if(to==ed)return 1;//如果达到终点,说明最短增广路已找到,结束bfs
            }
    }
    return 0;
}
inline void EK(Re st,Re ed){
    while(bfs(st,ed)==1){
        Re x=ed;maxflow+=cyf[ed];//cyf[ed]即为当前路径上边残留容量最小值
        while(x!=st){//从终点开始一直更新到起点
            Re i=pre[x];
            a[i].flow-=cyf[ed];
            a[i^1].flow+=cyf[ed];
            x=a[i^1].to;//链表特性,反向边指向的地方就是当前位置的父亲
        }
    }
}
int main(){
    in(n),in(m),in(st),in(ed);
    while(m--)in(x),in(y),in(z),add(x,y,z),add(y,x,0);
    EK(st,ed);
    printf("%d",maxflow);
}

3.【Dinic】

\(EK\) 算法中,每一次 \(bfs\) 最坏可能会遍历整个残量网络,但都只会找出一条最短增广路

那么如果一次 \(bfs\) 能够找到多条最短增广路,速度嗖~嗖~地就上去了。

\(Dinic\) 算法便提供了该思路的一种实现方法。

网络流的算法多且杂,对于初学者来说,在保证效率的前提下优化\(Dinic\)应该是最好写的一种了。

【算法流程】

\((1).\) 根据 \(bfs\) 的特性,找到 \(S\) 到每个点的最短路径(经过最少的边的路径),根据路径长度对残量网络进行分层,给每个节点都给予一个层次,得到一张分层图

\((2).\) 根据层次反复 \(dfs\) 遍历残量网络,一次 \(dfs\) 找到一条增广路并更新,直至跑完能以当前层次到达 \(T\) 的所有路径。

【多路增广】

可以发现,一次 \(bfs\) 会找到 \([1,m]\)增广路,大大减少了 \(bfs\) 次数,但 \(dfs\) 更新路径上的信息仍是在一条一条地进行,效率相较于 \(EK\) 并没有多大变化。

为了做到真正地多路增广,还需要进行优化。
\(dfs\) 时对于每一个点 \(x\),记录一下 \(x \rightsquigarrow T\) 的路径上往后走已经用掉的流量,如果已经达到可用的上限则不再遍历 \(x\) 的其他边,返回在 \(x\) 这里往后所用掉的流量,回溯更新 \(S \rightsquigarrow x\) 上的信息。
如果到达汇点则返回收到的流量,回溯更新 \(S \rightsquigarrow T\) 上的信息。

【当前弧优化】

原理:在一个分层图当中,\(\forall x \in V\),任意一条从 \(x\) 出发处理结束的边(弧),都成了 “废边”,在下一次到达 \(x\) 时不会再次使用。
(水管空间已经被榨干净了,无法再通过更多的水流,直接跳过对这些边的无用遍历)

实现方法:用数组 \(cur[x]\) 表示上一次处理 \(x\) 时遍历的最后一条边(即 \(x\) 的当前弧),其使用方法与链表中的 \(head\) 相同,只是 \(cur\) 会随着图的遍历不断更新。由于大前提是在一个分层图当中,所以每一次 \(bfs\) 分层后都要将 \(cur\) 初始化成 \(head\)

特别的,在稠密图中最能体现当前弧优化的强大。

【时间复杂度分析】

最坏时间复杂度为:\(O(n^2m)\)。(看不懂的证明

(特别的,对于二分图\(Dinic\) 最坏时间复杂度为 \(m\sqrt{n}\)

实际应用中效率较高,一般可解决 \(10^5\) 以内的问题。

【Code】

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define Re register int
using namespace std;
const int N=1e4+3,M=1e5+3,inf=2147483647;
int x,y,z,o=1,n,m,h,t,st,ed,Q[N],cur[N],dis[N],head[N];long long maxflow;
struct QAQ{int to,next,flow;}a[M<<1];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z){a[++o].flow=z,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline int bfs(Re st,Re ed){//bfs求源点到所有点的最短路
    for(Re i=0;i<=n;++i)cur[i]=head[i],dis[i]=0;//当前弧优化cur=head
    h=1,t=0,dis[st]=1,Q[++t]=st;
    while(h<=t){
        Re x=Q[h++],to;
        for(Re i=head[x];i;i=a[i].next)
            if(a[i].flow&&!dis[to=a[i].to]){
                dis[to]=dis[x]+1,Q[++t]=to;
                if(to==ed)return 1;
            }
    }
    return 0;
}
inline int dfs(Re x,Re flow){//flow为剩下可用的流量
    if(!flow||x==ed)return flow;//发现没有流了或者到达终点即可返回
    Re tmp=0,to,f;
    for(Re i=cur[x];i;i=a[i].next){
        cur[x]=i;//当前弧优化cur=i
        if(dis[to=a[i].to]==dis[x]+1&&(f=dfs(to,min(flow-tmp,a[i].flow)))){
//若边权为0,不满足增广路性质,或者跑下去无法到达汇点,dfs返回值f都为0,不必执行下面了
            a[i].flow-=f,a[i^1].flow+=f;
            tmp+=f;//记录终点已经从x这里获得了多少流
            if(!(flow-tmp))break;
//1. 从st出来流到x的所有流被榨干。后面的边都不用管了,break掉。
//而此时边i很可能还没有被榨干,所以cur[x]即为i。
//2. 下面儿子的容量先被榨干。不会break,但边i成了废边。
//于是开始榨x的下一条边i',同时cur[x]被更新成下一条边i'
//直至榨干从x上面送下来的水流结束(即情况1)。
        }
    }
    return tmp;
}
inline void Dinic(Re st,Re ed){
    Re flow=0;
    while(bfs(st,ed))maxflow+=dfs(st,inf);
}
int main(){
    in(n),in(m),in(st),in(ed);
    while(m--)in(x),in(y),in(z),add(x,y,z),add(y,x,0);
    Dinic(st,ed);
    printf("%lld",maxflow);
}

4.【ISAP】

\(To\) \(be\) \(continued...\)


5.【HLLP】

神奇的预流推进。。。

\(To\) \(be\) \(continued...\)


4.【算法效率测试】

因为网络流算法的时间复杂度都不太好分析,所以用实际的题目来感受一下。

【测试一】

题目:最大流 \([Loj101]\)

参测算法:

\((1).EK:\)
nKlmeU.png

\((2).Dinic\) \(+\) 多路增广(喵?喵?喵?居然卡 \(Dinic\)!)\(:\)
nKHh5t.png

\((3).Dinic\) \(+\) 多路增广 \(+\) 当前弧优化 \(:\)
nKHqbj.png

【测试二】

题目:【模板】二分图匹配 \([P3386]\)

参测算法:

\((1).EK:\)
nMqUPI.pngnMqJVH.png

\((2).Dinic\) \(+\) 多路增广 \(+\) 当前弧优化 \(:\)
nMqrqg.pngnMq6aj.png

\((3).\) 匈牙利算法\(QAQ\) 好像混入了奇怪的东西)\(:\)
nMqWR0.pngnMq6aj.png

\(To\) \(be\) \(continued...\)


5.【例题】


\[ QAQ \]


三:【有上下界的最大流】

\(To\) \(be\) \(continued...\)


\[ QAQ \]


四:【最小割】

1.【概念补充】

  • 网络的割集\((Network\) \(Cut\) \(Set)\) 把一个源点\(S\)汇点\(T\)网络中的所有点划分成两个点集 \(s\)\(t\)\(S \in s,T \in t\),由 \(x \in s\) 连向 \(y \in t\) 的边的集合称为割集。可简单理解为:对于一个源点\(S\)汇点\(T\)网络,若删除一个边集 \(E’ \subseteq E\) 后可以使 \(S\)\(T\) 不连通,则成 \(E’\) 为该网络的一个割集
    (有坏人不想让小区通水,用锯子割掉了一些边)

  • 最小割 \((Minimum\) \(Cut)\) 在一个网络中,使得边容量之和最小的割集
    (水管越大越难割,坏人想要最节省力气的方案)

  • 最大流最小割定理:\((Maximum\) \(Flow,Minimum\) \(Cut\) \(Theorem)\) 任意一个网络中的最大流等于最小割【证明】
    (可以感性理解为:最大流网络中一定是找出了所有的可行路径,将每条路径上都割掉一条边就能保证 \(S,T\) 一定不连通,在此前提下每条路径上都割最小的边,其等价于最大流)


2.【最大权闭合子图】

\(To\) \(be\) \(continued...\)


3.【例题】


\[ QAQ \]


六:【费用流】

1.【概念补充】

  • 单位流量的费用 \((Cost)\) 简称单位费用。顾名思义,一条边的费用 \(=\) 流量 \(\times\) 单位费用。表示为 \(w(x,y)\)
    (每根水管运一份水的花费。与\(“\)残留容量\(”\)的简化类似,通常直接称\(“\)费用\(”\)

  • 最小费用最大流:最大流网络中,使得总费用最小。
    (在运最多水的前提下,花钱最少)


2.【EK】

【算法流程】

只需将最大流 \(EK\) 算法中的流程 \((1)\) \(“\) \(bfs\) 找到任意一条最短增广路 \(”\) 改为 \(“\) \(Spfa\) 找到任意一条单位费用之和最小的增广路 \(”\),即可得到最小费用最大流

特别的,为了提供反悔机会,原图中 \(\forall (x,y) \in E\) 的反向边单位费用应为 \(-w(x,y)\) 。(为什么不用 \(dijkstra\)?原因就在这里啊!)

【Code】
#include<algorithm>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register int
using namespace std;
const int N=5003,M=5e4+3,inf=2e9;
int x,y,z,w,o=1,n,m,h,t,st,ed,cyf[N],pan[N],pre[N],dis[N],head[N];LL mincost,maxflow; 
struct QAQ{int w,to,next,flow;}a[M<<1];queue<int>Q;
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x,Re y,Re z,Re w){a[++o].flow=z,a[o].w=w,a[o].to=y,a[o].next=head[x],head[x]=o;}
inline void add_(Re a,Re b,Re flow,Re w){add(a,b,flow,w),add(b,a,0,-w);}
inline int SPFA(Re st,Re ed){
    for(Re i=0;i<=ed;++i)dis[i]=inf,pan[i]=0;
    Q.push(st),pan[st]=1,dis[st]=0,cyf[st]=inf;
    while(!Q.empty()){
        Re x=Q.front();Q.pop();pan[x]=0;
        for(Re i=head[x],to;i;i=a[i].next)
            if(a[i].flow&&dis[to=a[i].to]>dis[x]+a[i].w){
                dis[to]=dis[x]+a[i].w,pre[to]=i;
                cyf[to]=min(cyf[x],a[i].flow);
                if(!pan[to])pan[to]=1,Q.push(to);
            }
    }
    return dis[ed]!=inf;
}
inline void EK(Re st,Re ed){
    while(SPFA(st,ed)){
        Re x=ed;maxflow+=cyf[ed],mincost+=(LL)cyf[ed]*dis[ed];
        while(x!=st){//和最大流一样的更新
            Re i=pre[x];
            a[i].flow-=cyf[ed];
            a[i^1].flow+=cyf[ed];
            x=a[i^1].to;
        }
    }
}
int main(){
    in(n),in(m),in(st),in(ed);
    while(m--)in(x),in(y),in(z),in(w),add_(x,y,z,w);
    EK(st,ed);
    printf("%lld %lld",maxflow,mincost);
}

3.【Primal-Dual】

\(To\) \(be\) \(continued...\)


4.【ZKW 算法】

\(To\) \(be\) \(continued...\)


5.【算法效率测试】

\(To\) \(be\) \(continued...\)


6.【例题】


\[ QAQ \]


七:【常见问题模型】

\(To\) \(be\) \(continued...\)


\[ QAQ \]


八:【参考文献】

转载于:https://www.cnblogs.com/Xing-Ling/p/11487554.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《java面试800题(包括java,数据库,前台等,绝对全面)》 Q0027 哪些SQL语句在执行时是自动提交的? 数据定义语言DDL是自动提交的。 Q0028 索引对数据库的影响? 提高查询速度 Q0029 主外键有什么关系? 外键是从某个表的一个字段指向另外一个表的主健字段,两个字段的类型和精度应该一致,外键的值必须在主键中存在 Q0030 在数据库中什么代表一条记录? 主健 Q0031 如何编写效率高的SQL语句? "1.根据查询条件建立合适的index 2.因为SQL是从右向左解析,多表查询时,记录数少的表放在右边 3.多个条件时,收敛快的条件放在右边。 4.避免使用复杂的集合函数,象not in等。 5.避免在条件中对字段进行函数操作 6.尽量避免使用select *,应该写出需要查询的字段 7.在java中尽量使用preparestatement执行sql,从而共享执行计划" Q0032 Oracle的集合操作函数,如sum(),avg(),max(),min(),与select,where,grouby,having的先后顺序,使用方法 Oracle集合查询基本知识,只有进行分组的列,才可以取在集合查询SQL语句中取字段,先Group By,再Having作为集合查询的条件 Q0033 在Oracle数据库中,给定一个表,其中一列有索引,现在用这个列作为查询条件,因为用到了索引,速度一定会快吗? 答案是否定的,比如在这个列中使用‘%sdfd%’来进行模糊查询 Q0034 给定了一些创建数据库试图的SQL语句问什么条件下才可以对试图执行修改,增加,删除操作 特别强调了WITH CHECK OPTION这个约束的含义,使用,产生的不同结果。参考Oracle 视图的基本知识,单个表上的视图,多个表的联合试图,更新视图与表之间的关系.http://www.gzu521.com/it/oracle/zonghe/200904/20748_2.htm Q0035 是不是表或者其他对象不存在,就一定不能在Oracle中创建视图? 否,可通过FORCE选项执行强制生成视图,好处是在表不存在的时候,先创建视图 Q0036 如何创建oracle函数索引 "SQL>create index non_fbi on sale_contacts (surname); SQL>analyze index non_fbi compute statistics; SQL>:analyze table sale_contacts compute statistics; SQL>SELECT count(*) FROM sale_contacts WHERE UPPER(surname) = 'ELLISON'; Execution Plan ---------------------------------------------------------- 0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=17) 1 0 SORT (AGGREGATE) 2 1 TABLE ACCESS (FULL) OF 'SALES_CONTACTS' (Cost=3 Card=16 Bytes=272) " Q0037 "ORACLE锁的管理 " "ORACLE里锁有以下几种模式: 0:none 1:null 空 2:Row-S 行共享(RS):共享表锁 3:Row-X 行专用(RX):用于行的修改 4:Share 共享锁(S):阻止其他DML操作 5:S/Row-X 共享行专用(SRX):阻止其他事务操作 6:exclusive 专用(X):独立访问使用 数字越大锁级别越高, 影响的操作越多。" Q0038 创建XML文件的格式? " …" Q0039 java接口与抽象类的区别 "1.接口可以多重继承 ,抽象类不可以 2.接口定义方法,不给实现;而抽象类可以实现部分方法 3.接口中基本数据类型的数据成员,都默认为static和final,抽象类则不是 如果事先知道某种东西会成为基础类, 那么第一个选择就是把它变成一个接口。 只有在必须使用方法定义或者成员变量的时候,才应考虑采用抽象类。" Q0040 Java关键字 "51个:abstract, boolean, break, byte, case, catch, char, class, const, continue, default, do, double, else, extends, final, finally, float, for, goto, if, implements, import, instanceof, int, interface, long, native, new, package, private, protected, public, return, short, static, strictfp, super, switch, synchronized, this, throw, throws, transient, try, void, volatile, while. " Q0041 Java保留字 11个:byValue, cast, false, future, generic, inner, operator, outer, rest, true, var. Q0042 Java的值传递的规则? Java基本类型的都是值传递,对象使用的都是引用传递 Q0043 java相关概念 "static:静态,无需实例化,可直接引用,全局只有一份copy,修饰变量和方法 final:最终的,不可继承、不可修改,修饰变量、方法、类 volatile:volatile变量表示保证它必须是与主内存保持一致,它实际是""变量的同步"", 也就是说对于volatile变量的操作是原子型的,如用在long 或 double变量前,一般用于多线程编程。 abstract:抽象,必须重载,修饰类和方法 native:把java代码和其他语言的代码集成起来 synchronized:控制多个并发线程对共享数据的访问 throwsException:异常处理" Q0044 this&super的异同 "this :引用当前对象 super:引用当前对象的父类 使用情况: (1) super.variable //用来访问父类被隐藏的成员变量 (2) super.Method([paramlist]) //用来调用父类中被重载的方法 (3) super.([paramlist]) //调用父类中的构造函数 在类方法中(static),不能使用this或super修饰符 " Q0045 Java中是怎样捕获异常的? "try { //statement01 } catch(Exception e) { //statement02 } finally { //statement03 }" Q0046 一个文件中是否可以有多个public类? 不可以 Q0047 子类是否可以访问父类的私有成员? 不可以 Q0048 NULL是否是Java的关键字? 不是。null,false,true是保留字 Q0049 一个有序数组和一个无序数组,从无序数组中取出每条记录与有序数组比较,如果符合条件,把无序数组中的值加入到有序数组中,问这是什么排序? 插入排序法 Q0050 程序与进程的区别? 程序是为了完成某种任务而设计的软件,比如OpenOffice是程序。什么是进程呢?进程就是 运行中的程序。 一个运行着的程序,可能有多个进程。 Q0051 设计模式主要几种 "创建模式 factory工厂模式、prototype原始模型模式、singleton单例模式、builder建造模式 结构模式 facade门面模式、proxy代理模式、adapter适配器(变压器)模式、composite合成模式、decorator装饰模式、bridge桥梁模式、flyweight享元模式 行为模式 template模板方法模式、memento备忘录模式、observer观察者模式、command命令模式、state状态模式、strategy策略模式、mediator调停者模式、interpreter解释器模式、visitor访问者模式、chain of responsibility责任链模式" Q0052 构造函数的相关知识? "构造函数(constructor )在对象创建时初始化。 构造函数是和类同名的函数,没有返回类型,构造函数不能在普通的程序里面调用,只有当这个类被应用new实例化的时候才会被运行。构造函数没有返回类型,实际上,构造函数返回的就是这个class本身。 类初始化时构造函数调用顺序: (1)初始化对象的存储空间为零或null值; (2)调用父类构造函数; (3)按顺序分别调用类成员变量和实例成员变量的初始化表达式; (4)调用本身构造函数。" Q0053 "Public class Servlet extends HttpServlet{ int i; doget(){ i++; out.print(i); } } 每次访问时i是否变化?" 会 Q0054 类的加载过程? "类的初始化过程 当创建一个对象时,对象的各个变量根据其类型被设置为相应的默认初始值,然后调用构造方法,而每次调用构造方法都是要执行三个阶段: 1.调用超类的构造方法; 2.由初始化语句对给变量进行初始化; 3.执行构造方法的体。" Q0055 系统运行时的最小单位是什么? 线程 Q0056 Java的编码规范? Q0057 Java的命名规范? Q0058 一个Java抽象类声明了一个方法并会抛出一个异常,问继承这个抽象类的子类,实现了这个方法,这个方法声明是不是一定要抛出一模一样的异常,可不可以不抛,或者抛出的异常比抽象类的异常范围大,或者小? 可以不抛,或者比抽象类的小,但绝对不能抛出的异常比抽象类的大 Q0059 找出weblogic-ejb-jar.xml文件中的错误。 "正确的文档 Catalog WebLogic_CMP_RDBMS 7.0 META-INF/weblogic-cmp-rdbms-jar.xml com.ejb.CatalogHome " Q0060 JDBC批量更新的作用和用法 "提高执行效率。减少执行时间。 Statement sm = cn.createStatement(); sm.addBatch(sql1); sm.addBatch(sql2); ... sm.executeBatch() 或者 PreparedStatement ps = cn.preparedStatement(sql); { ps.setXXX(1,xxx); ... ps.addBatch(); } ps.executeBatch();" Q0061 事务的特性是什么? "事务有四种特性:ACID Atomicity(原子性) 事务中的操作或者全部完成,或者全部不完成。 Consistency(一致性) 事务执行的结果是从一个一致性状态转移到另一个一致性状态。 Isolation(隔离性) 一个事务的执行不能被其它事务干扰,即并发事务间内部数据是隔离的。 Durability(持久性) 事务开始执行后,它对系统中数据的改变应该是恒定的,不应受其它操作或故障的影响。 " Q0062 事务有几种属性?分别是什么? "事务的属性有6种 1.Required:当处于事务范围内的客户端应用调用组件商务方法时,组件商务方法执行在原有的客户端事务范围内; 2.RequiredNew:当处于事务范围内的客户端应用调用组件商务方法时,EJB容器启动一个新的事务过程,组件商务方法执行在新事务过程范围内; 3.Mandatory:如果调用EJB组件商务方法的客户端应用不处于事务范围内,则EJB容器抛出TransactionRequiredException异常,强制客户端启动事务过程; 4.NotSupported:EJB组件的商务方法不需要运行在事务过程中。如果调用EJB组件方法的客户端应用处于事务过程中,则调用组件商务方法时原有事务过程挂起,直至组件方法运行结束; 5.Supports:组件方法必须处于事务范围内。如果调用组件商务方法的客户端不处于事务过程中,则EJB容器启动新的事务过程;6.Never:组件方法不需要运行在事务过程中。如果调用组件商务方法的客户端应用处于事务范围内,则EJB容器抛出RemoteException异常。 "

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值