by Richard Johnsonbaugh Marcus Schaefer
4.1 对分搜索
本算法在非降序数组L[i],…,L[j]中搜索值key。如果找到key,则回送下表k,L[k]等于key。如果没有找到key,则回送-1(假定-1不是一个有效的下表)。
Input Parameters: L,i,j,key
Output Parameters: None
bsearch(L,i,j,key){
while(i<=j){ k=(i+j)/2
if(key==L[k])//找到 return k
if(key<L[k])// 查找第一部分 j= k-1 else//查找第二部分 i=k+1
}
return -1
}
对规模n的输入,bsearch的最坏情况时间为O(lgn)。
4.2 深度优先搜索
本算法在具有顶点1,…,n的图中,从顶点start开始执行深度优先搜素,并将顶点以访问先后的次序输出。
图用邻接表表示;与顶点i相邻的那些顶点用一个链接表表示,adj[i]是对连接表中第一个节点的索引。每个节点的成员包括与i相邻的顶点ver,以及对链接表中下一个节点的索引next,对链接表中最后一个节点来说,其next的值为null。
为了跟踪已访问的顶点,使用数组visit;若顶点i已访问,则置visit[i]为真,否则为假。
Input Parameters: adj,start
Output Parameters: None
dfs(adj,start){
n = adj.last
for i = 1 to n visit[i] = false
dfs_recurs(adj,start)
}
dfs_recurs(adj,start){
println(start)
visit[start] = true
trav = adj[start]
while(trav != null){ v = trav.ver if(!visit[v])
dfs_recurs(adj,v)
trav = trav.next
}
}
小结:
1.一个有m条边,n个顶点的图,dfs以时间O(m+n)运行。
2.dfs 与 图的规模成线性关系。
3.dfs检测图是否连通:任意顶点为起始顶点,运行dfs。图是连通的,当且仅当全部节点被访问到。
4.3 广度优先搜索
本算法在有顶点1,…,n的图中从顶点start开始执行广度优先搜索,并将顶点以访问先后的次序输出。
图用邻接表表示;与顶点i相邻的那些顶点用一个链接表表示,adj[i]是对连接表中第一个节点的索引。每个节点的成员包括与i相邻的顶点ver,以及对链接表中下一个节点的索引next,对链接表中最后一个节点来说,其next的值为null。
数组visit跟踪访问过的顶点,队列q存放待处理的当前顶点。q.enqueue(val) 将val加入q;q.front会送q队列首部的值,但不删除;q.dequeue删除q队列首部的项;q.empty(),若q唯恐返回真,否则为假。
Input Parameters: adj,start
Output Parameters: None
bfs(adj,start){
n = adj.last
for i = 1 to n
visit[i] = false
visit[start] = true
println(start)
//q是一个初始为空的队列
q.enqueue(start)
while(!q.empty()){
current = q.front()
q.dequeue()
trav = adj[current]
while(trav!=null){
v = trav.ver
if(!visit[v]){
visit[v]=true
println(v)
q.euqueue(v)
}
trav.trav.next
}
}
}
小结:
1. 一个有m条边,n个顶点的图,bfs以时间O(m+n)运行。
2. 使用广度优先搜索寻找最短路径长度。
4.4 拓扑排序
本算法计算一个有顶点1,…,n的有向非循环的拓扑排序。拓扑排序中的顶点存放于数组ts。
图用邻接表表示;与顶点i相邻的那些顶点用一个链接表表示,adj[i]是对连接表中第一个节点的索引。每个节点的成员包括与i相邻的顶点ver,以及对链接表中下一个节点的索引next,对链接表中最后一个节点来说,其next的值为null。数组vist跟踪访问过的节点。
Input Parameters: adj
Output Parameters: ts
top_sort(adj,ts){
n=adj.last //k是ts中的下标,拓扑排序中的下一个顶点存放在ts。
//假定k在top_sort_recurs中可见
k=n for i = 1 to n
visit[i] = false
for i = 1 to n
if(!visit[i])
top_sort_recurs(adj,i,ts)
}
top_sort_recurs(adj,start,ts){
visit[start] = true
trav = adj[start]
while(trav != null){
v = trav.ver
if(!visit[v])
top_sort_recurs(adj,v,ts)
trav = trav.next
}
ts[k] = start
k = k-1
}
1. 可以利用深度有限速锁构建一个有向非循环拓扑排序。假定从G的任意一个起始顶点v1开始运行深度优先搜索。深度优先搜索先访问v1,然后从v1访问一个未访问顶点v2,等。最后dfs达到一个顶点vk,这个顶点没有(vk,v')的边,其中v'未被访问过。因为如果有这样一条边,v'就会被访问,而图就会包含一个有向环路。
这个事实可以用来确定任意一个有向图是否是有向非循环图。
2. 一个有m条边,n个顶点的图是拓扑排序的输入,调用总时间为O(m+n)。
4.5 回溯法
涉及 n王后问题和哈密尔顿环路问题
回溯算法的形式:
假定回溯算法解一个问题,其解有形式 x[1],…,x[n],在假定x[i]的值是在集S里,回溯算法的一般形式为:
backtrack(n){
rbacktrack(1,n)
}
rbacktrack(k,n){
for each x[k]∈S
if(bound(k))
if( k==n ){
//输出一个结果。若只要一个结果,则停止
for i = 1 to n
print(x[i]+" "
println()
}
else
rbacktrack(k+1,n)
}
函数bound(k)假定x[1],…,x[k-1]是部分解,并且x[k]已经赋予一个值。于是,如果x[1],…,x[k]是一个部分解,则回送真,否则回送假。
编写一个的高效的界定函数,它可以从搜索树中消除不少可能的节点。