17、的函数如下:
void deleteEdge(int *a,int i ,int j){
if(a[i-1][j-1]==0) return;
a[i-1][j-1] = 0;
return;
}
代码的时间复杂性为Θ(1)
5.实现图的D-搜索算法,要求用SPARKS语言写出算法的伪代码,或者用一种计算机高级语言写出程序。
解:D搜索算法的基本思想是,用栈代替BFS中的队列,先将起始顶点存入栈中,搜索时,取出栈顶的元素,遍历搜索其相邻接点,若其邻接点还未搜索,则存入栈中并标记,遍历所有邻接点后,取出此时栈顶的元素转入下一轮遍历搜索,直至
18、栈变为空栈。
Proc DBFS (v) //从顶点v开始,数组visited标示顶点被访问的顺序;
PushS(v , S); //首先访问v,将S初始化为只含有一个元素v的栈
count :=count +1; visited[v] := count;
While S 非空 do
u :=PullHead(S); count :=count +1; visited[w] := count; //区别队列先进先出,此先进后出
for 邻接于u的所有顶点w do
if s[w] = 0 then
PushS(w,S); //将w存入
19、栈S
s[w]:= 1;
end{if}
end{for}
end{while}
end{DBFS}
注:PushS(w,S)将w存入栈S; PullHead(S)为取出栈最上面的元素,并从栈中删除
Proc DBFT(G,m) //m为不连通分支数
count:=0 ;计数器,标示已经被访问的顶点个数
for i to n do
s[i]:=0; //数组s用来标示各顶点是否曾被搜索,是则标记为1,否则标记为0;
end{for}
for i to m do //遍历
20、不连通分支的情况
if s[i]=0 then
DBFS (i);
end{if}
end{for}
end{DBFT}
6.下面的无向图以邻接链表存储,而且在关于每个顶点的链表中与该顶点相邻的顶点是按照字母顺序排列的。试以此图为例描述讲义中算法DFNL的执行过程。
一个无向图 G
A
B
E
D
G
C
F
1
1
2
3
4
7
5
6
1
1
1
5
5
4
邻接链表
A->B->E|0
B->A->C|0
C->B->D->E|0
D->C|0
E->A-
21、>C->F->G|0
F->E->G|0
G->E->F|0
解:初始化 数组DFN:=0, num=1;
A为树的根节点,对A计算DFNL(A,null),
DFN(A):=num=1; L(A):=num=1; num:=1+1=2。
从邻接链表查到A的邻接点B,
因为DFN(B)=0,对B计算DFNL(B,A)
DFN(B):= num=2; L(B):=num=2; num:=2+1=3。
查邻接链表得到B的邻接点A,因为DFN(A)=1¹0, 但A=A,即是B的父节点,无操作。
接着查找邻接链表得到B的邻接点C,
因为DFN(C)=0,对C计算D
22、FNL(C,B)
DFN(C):= num=3; L(C):=num=3; num:=3+1=4。
查找C的邻接点B,因为DFN(B)=1¹0, 但B=B,即是C的父节点,无操作。
接着查找邻接链表得到C的邻接点D,
因为DFN(D)=0,对D计算 DFNL(D,C),
DFN(D):= num=4; L(D):=num=4; num:=4+1=5。
查找得D邻接点C,而DFN(C)=3≠0,但C=C,为D的父节点, L(D)保持不变。
D的邻接链表结束,DFNL(D,C)的计算结束。
返回到D的父节点C,查找邻接链表得到C的邻接点E,
因为DFN(
23、E)=0,对E计算DFNL(E,C),
DFN(E):=num=5; L(E):=num=5; num:5+1=6;
查找得E邻接点A,因DFN(A)=1≠0,又A≠C,变换L(E)=min(L(E),DFN(A))=1。
查找得E邻接点C,因DFN(C)=3≠0,但C=C,无操作。
查找得E邻接点F,因DFN(F)=0,
对F计算 DFNL(F,E),
DFN(F):=num=6; L(F):=num=6; num:=6+1=7;
查找得F邻接点E,因DFN(E)=5≠0,但E=E,无操作。
查找得F邻
24、接点G,因DFN(G)=0,
对G计算 DFNL(G,F),
DFN(G):=num=7; L(G):=num=7; num=7+1=8;
查找G邻接点E,因DFN(E)=5≠0,又E≠F,L(G)=min(L(G),DFN(E))=5
查找得G邻接点F,因DFN(F)=6≠0,但F=F,无操作。
G的邻接链表结束,DFNL(G,F)的计算结束。
L(F):=min(L(F),L(G))=min(6,5)=5
F的邻接链表结束,DFNL(
25、F,E)的计算结束。
L(E):=min(L(E),L(F))=min(1,5)=1
E邻接链表结束, DFNL(E,C)计算结束。
L(C):=min(L(C),L(E))=min(3,1)=1
C的邻接链表结束,DFNL(C,B)计算结束。
L(B):=min(L(B),L(C))=min(2,1)=1
查找B的邻接链表结束,DFNL(B,A)计算结束。
L(A):=min(L(A),L(B))=1
查找得A的邻接点E,因DFN(E)=0,又E≠null,则L(A)=min(L(A),DFN(E))=1
查找A
26、的邻接链表结束,DFNL(A,null)计算结束。
最终结果为:深索数DFN,与最低深索数L如下
DFN(A)=1,DFN(B)=2,DFN(C)=3,DFN(D)=4,DFN(E)=5,DFN(F)=6,DFN(G)=7
L(A)=1; L(B)=1; L(C)=1; L(D)=4; L(E)=1; L(F)=5;L(G)=5.
序
节点
DFN
L
栈顶—栈底
2-连通
割点
1
A
1
(1,0,0,0,0,0,0)
(A,B)
2
B
2
(1,2,0,0,0,0,0)
(B,C),(A,B)
3
C
3
(1,2,3
27、0,0,0,0)
(C,D),(B,C),(A,B)
4
D
4
(1,2,3,4,0,0,0)
(B,C),(A,B)
{(C,D)};
C
5
E
5
(1,1,1,4,1,0,0)
(E,F),(E,A),(B,C),(A,B)
6
F
6
(1,1,1,4,1,6,0)
(F,G), (E,F),(E,A),(B,C),(A,B)
7
G
7
(1,1,1,4,1,5,5)
(E,A),(B,C),(A,B)
{(G,E),(F,G), (E,F)}
E
8
(1,1,1,4,1,5,5)
{
28、E,A),(B,C),(A,B)}
附课本讲义程序2-3-1对图2-3-5的执行过程
开始 DFNL(A,*)
DFN(A):=1; L(A):=1; num:=2;
A
B
B
B A
C B
B
C B A
D C B
B
C B A
E C B
B
C B A
F C B
B
F C B A
A F C B
B
∵ DFN(B)=0, ∴ DFNL(B,A)
DFN(B):=2; L(B):=2; num:=3;
∵ DFN(A)=1¹0, 但A=A,
29、 ∴不做任何事情
∵ DFN(C)=0, ∴ DFNL(C,B)
DFN(C):=3; L(C):=3; num:=4;
∵ DFN(B)=2¹0, 但B=B, ∴不做任何事情
∵ DFN(D)=0, ∴ DFNL(D,C)
DFN(D):=4; L(D):=4 > DFN( C); num:=5; 弹出(C,D)边
∵ DFN(C)=3¹0, 但C=C, ∴不做任何事情
∵ DFN(E)=0, ∴ DFN
30、L(E,C)
DFN(E):=5; L(E):=5 > DFN( C); num:=6; 弹出(C,E)边
∵ DFN(C)=3¹0, 但C=C,
∵ DFN(F)=0, ∴ DFNL(F,C)
DFN(F):=6; L(F):=6; num:=7;
∵ DFN(A)=1¹0, A¹C, ∴ L(F):=min{6,1}=1;
∵ DFN(C)=3¹0, 但C=C,
F F C B A
G A F C
31、 B
B
G F F C B A
H G A F C B
B
G F F C B A
I G A F C B
B
I G F F C B A
F I G A F C B
B
I I G F F C B A
J F I G A F C B
B
J I I G F F C B A
F J F I G A F C B
B
J J I I G F F C B A
G F J F I G A
32、 F C B
B
∵ DFN(G)=0, ∴ DFNL(G,F)
DFN(G):=7; L(G):=7; num:=8;
∵ DFN(F)=6¹0, 但F=F,
∵ DFN(H)=0, ∴ DFNL(H,G)
DFN(H):=8; L(H):=8 > DFN(G); num:=9; 弹出(G,H)边
∵ DFN(G)=7¹0, 但G=G,
33、 ∵ DFN(I)=0, ∴ DFNL(I,G)
DFN(I):=9; L(I):=9; num:=10;
∵ DFN(F)=6¹0, F¹G, ∴ L(I):=min{9,6}=6;
∵ DFN(G)=7¹0, 但G=G,
∵ DFN(J)=0, ∴ DFNL(J,I)
DFN(J):=10; L(J):=10; num:=11;
∵ DFN
34、F)=6¹0, F¹I, ∴ L(J):=min{10,6}=6;
∵ DFN(G)=7¹0, G¹I, ∴ L(J):=min{6,7}=6;
∵ DFN(I)=9¹0, 但I=I,
L(I):=min{6,6}=6;
L(G):=min{7,6}=6 ³ DFN(F) 弹出(J,G), (J,F), (I,J), (I,F), (G
35、I), (F,G) 边
L(F):=min{1,6}=1;
L(C ):=min{3,1}=1;
L(B):=min{2,1}=1 ³ DFN(A) 弹出(F,A), (C,F), (B,C), (A,B) 边
7 对图的另一种检索方法是 D-Search。该方法与 BFS 的不同之处在于将队列换成栈,即下一个要检测的结点是最新加到未检测结点表的那个结点。
1)写一个D-Search算法;
2)证明由结点v开始的D-Search能够访问v可到达的所有结点;
3)你的算法的时、空复杂度是
36、什么?
解:1)同第5题,
proc DBFS(v) //宽度优先搜索G,从顶点v开始执行,数组visited标示各
//顶点被访问的序数;数组s将用来标示各顶点是否曾被放进待检查队
//列,是则过标记为1,否则标记为0;计数器count计数到目前为止已
//经被访问的顶点个数,其初始化为在v之前已经被访问的顶点个数
PushS(v , S);// 将S初始化为只含有一个元素v的栈
while S非空 do
u:= PullHead(S); count:=count+1; visited[u]:=count;
for 邻接于u的所有顶点w do
if s[w]=
37、0 then
PushS(w , S); //将w压入栈中
s[w]:=1;
end{if}
end{for}
end{while}
end{DBFS}
图的D—搜索算法伪代码:
proc DBFT(G, ν) //count、s同DBFS中的说明,branch是统计图G的连通分支数
count:=0; branch:=0;
for i to n do
s[i]:=0; //将所有的顶点标记为未被访问
end{for}
for i to ν do
if s[i]=0 then
DBFS(i); branch:=branch+1;
e
38、nd{if}
end{for}
end{DBFT}
2)证明:除结点v外,只有当结点w满足s[w]=0时才被压入栈中,因此每个结点至多有一次被压入栈中,搜索不会出现重叠和死循环现象,对于每一个v可到达的节点,要么直接被访问,要么被压入栈中,只有栈内节点全部弹出被访问后,搜索才会结束,所以由结点v开始的D-Search能够访问v可到达的所有结点。
3):除结点v外,只有当结点w满足s[w]=0时才被压入栈中,因此每个结点至多有一次被压入栈中。需要的栈 空间至多是ν-1;visited数组变量所需要的空间为ν;其余变量所用的空间为O(1),所以s(ν,ε)=Θ (ν)。
如果使用邻
39、接链表, for循环要做d(u)次,而while循环需要做ν次,又visited、s和count的赋值都需要ν次操作,因而t(ν, ε)=Θ (ν+ ε)。
如果采用邻接矩阵,则while循环总共需要做ν2次操作,visited、s和count的赋值都需要ν次操作,因而t(ν, ε)=Θ (ν2)。
8.考虑下面这棵假想的对策树:
解:
20
6
4
20
5
4
8
15
6
20
30
5
50
8
4
15
20
5
10
30
5
9
20
50
18
6
15
10
5
5
20
1)使用最大最小方法(2
40、4-2)式获取各结点的值
max
max
max
min
min
2)2)弈者A为获胜应该什么棋着?
20
6
4
20
5
4
8
15
6
20
30
5
50
8
4
15
20
5
10
30
5
9
20
50
18
6
15
10
5
5
20
X
X1
X2
X3
X4
X1.1
X1.2
X2.1
X2.2
X3.1
X3.2
X4.1
X4.2
X1.1.1
X1.1.2
X1.1.3
X1.2.1
X2.1.1
X2.2.1
X3.1.1
X3.1.2
41、
X1.1.1.1
X3.1.2.1
X3.2.1
X3.2.2
X3.2.3
X4.1.1
X4.2.1
X4.4.2
X4.2.3
X4.2.4
第三章 分治算法习题
1、编写程序实现归并算法和快速排序算法
参见后附程序
2、用长为100、200、300、400、500、600、700、800、900、1000的10个数组的排列来统计这两种算法的时间复杂性。
有些同学用的微秒us
用s可能需要把上面的长度改为10000,……,100000,都可以
大部分的结果是快速排序算法要比归并算法快一些。
3、讨论归并排序算法
42、的空间复杂性。
解析:归并排序由分解与合并两部分组成,如果用表示归并排序所用的空间。
则由
MergeSort(low, mid) //将第一子数组排序
MergeSort(mid+1, high) //将第二子数组排序
Merge(low, mid, high) //归并两个已经排序的子数组
则
递归推导得
又由存储数组长度为 ,则有
因此,空间复杂度为。
4、说明算法PartSelect的时间复杂性为
证明:提示:假定数组中的元素各不相同,且第一次划分时划分元素是第小元素的概率为。因为Partition中的cas
43、e语句所要求的时间都是,所以,存在常数,使得算法PartSelect的平均时间复杂度可以表示为
令取试证明。
证明:令表示n个元素的数组A中寻找第k小元素的平均时间复杂度,因的时间复杂度是,故存在常数c,使得算法PartSelect的平均时间复杂度可以表示为
令且不妨设等式在时成立,则满足
以下用第二数学归纳法证明。取
当时,取cC/4,则
当时,成立。
对于一般的n,设对所有小于n的自然数成立,则
得证。
证明:(1)当时,假设数组A中元素互不相同。由于每个具有7个元素的数组的中间值u是该数组中的第4小元素,因此数组中至少有4个元素不大于u,个中间值中至
44、少有个不大于这些中间值的中间值v。因此,在数组A中至少有
个元素不大于v。换句话说,A中至多有
个元素大于v。同理,至多有个元素小于v。这样,以v为划分元素,产生的新数组至多有个元素。当时,。
另一方面,在整个执行过程中,递归调用Select函数一次,涉及规模为,而下一次循环Loop涉及的数组规模为。程序中其他执行步的时间复杂度至多是n的倍数,用表示算法在数组长度为n的时间复杂度,则当时,有递归关系
用数学归纳法可以证明,。所以时间复杂度是。
(2)当时,使用上述方法进行分析,可知在进行划分后数组A中有至多个元素。而递归关系为。若通过归纳法证明出有
的形式,用数
45、学归纳法可以证明,。所以时间复杂度是。
归并排序的 C++语言描述
#include
templatevoid MergeSort(T a[],int left,int right);
templatevoid Merge(T c[],T d[], int l,int m,int r);
templatevoid Copy(T a[],T b[],int l,int r);
void main()
{
int const n(5);
int a[n];
46、
cout<<"Input "<>a[i];
//for(int j=0;j47、cout<
void MergeSort(T a[],int left,int right) //
{
if(left48、ft,i,right);
Copy(a,b,left,right);
}
template
void Merge(T c[],T d[],int l,int m,int r)
{
int i=l;
int j=m+1;
int k=l;
while((i<=m)&&(j<=r))
{
if(c[i]<=c[j])d[k++]=c[i++];
else d[k++
49、]=c[j++];
}
if(i>m)
{
for(int q=j;q<=r;q++)
d[k++]=c[q];
}
else
for(int q=i;q<=m;q++)
d[k++]=c[q];
}
template
void Copy(T a[],T b[], int l,int r)
{
50、 for(int i=l;i<=r;i++)
a[i]=b[i];
}
快速排序的 C++语言描述
#include
templatevoid QuickSort(T a[],int p,int r);
templateint Partition(T a[],int p,int r);
void main()
{
int const n(5);
int a[n];
cout<<"Input "<