Вы находитесь на странице: 1из 22

CHAPTER 4

Searching

Algorithm 4.1.1 Binary Search


This algorithm searches for the value key in the nondecreasing array
L[i], ... , L[j]. If key is found, the algorithm returns an index k such that
L[k] equals key. If key is not found, the algorithm returns -1, which is
assumed not to be a valid index.
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]) // found
return k
if (key < L[k]) // search first part
j = k - 1
else // search second part
i = k + 1
}
return -1 // not found
}

Algorithm 4.2.2 Depth-First Search


This algorithm executes a depth-first search beginning at vertex start in a
graph with vertices 1, ... , n and outputs the vertices in the order in which
they are visited. The graph is represented using adjacency lists; adj[i] is a
reference to the first node in a linked list of nodes representing the
vertices adjacent to vertex i. Each node has members ver, the vertex
adjacent to i, and next, the next node in the linked list or null, for the last
node in the linked list. To track visited vertices, the algorithm uses an
array visit; visit[i] is set to true if vertex i has been visited or to false if
vertex i has not been visited.

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
}
}

Algorithm 4.3.2 Breadth-First Search


This algorithm executes a breadth-first search beginning at vertex start in
a graph with vertices 1, ... , n and outputs the vertices in the order in
which they are visited.
The graph is represented using adjacency lists; adj[i] is a
reference to the first node in a linked list of nodes representing the
vertices adjacent to vertex i. Each node has members ver, the vertex
adjacent to i, and next, a
reference to the next node in the linked list or null, for the last node in
the
linked list.
To track visited vertices, the algorithm uses an array visit; visit[i]
is set to true if vertex i has been visited or to false if vertex i has not
been visited. The algorithm uses an initially empty queue q to store
pending current vertices. The expression
q.enqueue(val)
adds val to q. The expression
q.front()
returns the value at the front of q but does not remove it. The expression
q.dequeue()
removes the item at the front of q. The expression

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.enqueue(start) // q is an initially empty queue
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.enqueue(v)
}
trav = trav.next
}
}
}

Algorithm 4.3.4 Finding Shortest Path


Lengths Using Breadth-First Search
This algorithm finds the length of a shortest path from the start vertex
start
to every other vertex in a graph with vertices 1, ... , n.
The graph is represented using adjacency lists; adj[i] is a
reference to the first node in a linked list of nodes representing the
vertices adjacent to vertex i. Each node has members ver, the vertex
adjacent to i, and next, a
reference to the next node in the linked list or null, for the last node in
the
linked list.
In the array length, length[i] is set to the length of a shortest
path from start to vertex i if this length has been computed or to if the
length has not been computed. If there is no path from start to i, when
the algorithm terminates, length[i] is .

Input Parameters: adj,start


Output Parameters: length
shortest_paths(adj,start,length) {
n = adj.last
for i = 1 to n
length[i] =
length[start] = 0
q.enqueue(start) // q is an initially empty queue
while (!q.empty()) {
current = q.front()
q.dequeue()
trav = adj[current]
while (trav != null) {
v = trav.ver
if (length[v] == ) {
length[v] = 1 + length[current]
q.enqueue(v)
}
trav = trav.next
}
}
}

Algorithm 4.4.1 Topological Sort


This algorithm computes a topological sort of a directed acyclic graph
with vertices 1, ... , n. The vertices in the topological sort are stored in
the array ts.
The graph is represented using adjacency lists; adj[i] is a
reference to the first node in a linked list of nodes representing the
vertices adjacent to vertex i. Each node has members ver, the vertex
adjacent to i, and next, the next node in the linked list or null, for the last
node in the linked list.
To track visited vertices, the algorithm uses an array visit; visit[i]
is set to true if vertex i has been visited or to false if vertex i has not
been visited.

Input Parameters: adj


Output Parameters: ts
top_sort(adj,ts) {
n = adj.last
// k is the index in ts where the next vertex is to be
// stored in topological sort. k is assumed to be global.
k = n
for i = 1 to n
visit[i] = false
for i = 1 to n
if (!visit[v])
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

Algorithm n-Queens, Initial Version


The n-queens problem is to place n queens on an n n board so that no
two queens are in the same row, column, or diagonal. Using
backtracking, this algorithm outputs all solutions to this problem. We
place queens successively in the columns beginning in the left column
and working from top to bottom. When it is impossible to place a queen
in a column, we return to the previous column and move its queen down.

n_queens(n) {
rn_queens(1,n)
}
rn_queens(k,n) {
for row[k] = 1 to n
if (position_ok(k,n))
if (k == n) {
for i = 1 to n
print(row[i] + )
println()
}
else
rn_queens(k + 1,n)
}
position_ok(k,n)
for i = 1 to k - 1
// abs is absolute value
if (row[k] == row[i] || abs(row[k] - row[i]) == k - i)
return false
return true
}

Algorithm 4.5.2 Solving the n-Queens


Problem Using Backtracking
The n-queens problem is to place n queens on an n n board so that no
two queens are in the same row, column, or diagonal. Using
backtracking, this algorithm outputs all solutions to this problem. We
place queens successively in the columns beginning in the left column
and working from top to bottom. When it is impossible to place a queen
in a column, we return to the previous column and move its queen down.

The value of row[k] is the row where the queen in column k is placed.
The algorithm begins when n_queens calls rn_queens(1,n). When
rn_queens(k, n)
is called, queens have been properly placed in columns 1 through k - 1,
and
rn_queens(k,n) tries to place a queen in column k. If it is successful and k
equals n, it prints a solution. If it is successful and k does not equal n, it
calls
rn_queens(k + 1,n).
If it is not successful, it backtracks by returning to its caller
rn_queens(k - 1 ,n).
The value of row_used[r] is true if a queen occupies row r and
false otherwise. The value of ddiag_used[d] is true if a queen occupies
ddiag diagonal d and false otherwise. According to the numbering system
used, the queen in column k, row r, is in ddiag diagonal n - k + r. The
value of udiag_used[d] is true if a queen occupies udiag diagonal d and
false otherwise. According to the numbering system used, the queen in
column k, row r, is in udiag k + r - 1.
The function position_ok(k,n) assumes that queens have been
placed in columns 1 through k - 1. It returns true if the queen in column k
does not conflict with the queens in columns 1 through k- 1 or false if it
does conflict.

Input Parameter: n
Output Parameters: None
n_queens(n) {
for i = 1 to n
row_used[i] = false
for i = 1 to 2 * n - 1
ddiag_used[i] = udiag_used[i] = false
rn_queens(1,n)
}
...

...
// When rn_queens(k,n) is called, queens have been
// properly placed in columns 1 through k - 1.
rn_queens(k,n) {
for row[k] = 1 to n
if (position_ok(k,n))
row_used[row[k]] = true
ddiag_used[n - k + row[k]] = true
udiag_used[k + row[k] - 1] = true
if (k == n) {
// Output a solution. Stop if only one
// solution is desired.
for i = 1 to n
print(row[i] + )
println()
}
else
rn_queens(k + 1,n)
row_used[row[k]] = false
ddiag_used[n - k + row[k]] = false
udiag_used[k + row[k] - 1] = false
}
...

...
// position_ok(k,n) returns true if the queen in column k
// does not conflict with the queens in columns 1
// through k - 1 or false if it does conflict.
position_ok(k,n)
return !(row_used[row[k]]
|| ddiag_used[n - k + row[k]]
|| udiag_used[k + row[k] - 1 ])
}

Form of Backtracking Algorithm


Suppose that we solve a problem using backtracking as in Algorithm
4.5.2 in which the solution is of the form
x[1], ... , x[n].
Suppose also that the values of x[i] are in the set S (e.g., in Algorithm
4.5.2,
S = {1, . . . , n}).
We require a function bound(k) with the following property. Whenever
x[1], ... , x[k - 1]
is a partial solution and x[k] has been assigned a value, then bound(k)
has to return true if
x[1], ... , x[k]
is a partial solution and false otherwise. The key to writing a useful backtracking algorithm is to write an efficient bound function that eliminates
many potential nodes from the search tree.

The general form of a backtracking algorithm is


backtrack(n) {
rbacktrack(1,n)
}
rbacktrack(k,n) {
for each x[k] S
if (bound(k))
if (k == n) {
// Output a solution. Stop if only
for i = 1 to n
// one solution is desired.
print(x[i] + )
println()
}
else
rbacktrack(k + 1, n)
}

Algorithm 4.5.4 Searching for a


Hamiltonian Cycle
This algorithm inputs a graph with vertices 1, ... , n. The graph is
represented as an adjacency matrix adj; adj[i][j] is true if (i,j) is an edge
or false if it is not an edge. If the graph has a Hamiltonian cycle, the
algorithm computes one such cycle
(x[1], ... , x[n], x[1]).
If the graph has no Hamiltonian cycle, the algorithm returns false and the
contents of the array x are not specified.
In the array used, used[i] is true if i has been selected as one of
the vertices in a potential Hamiltonian cycle or false if i has not been
selected.
The function path_ok(adj,k,x) assumes that (x[1], ... , x[k - 1]) is a
path from x[1] to x[k - 1] and that the vertices x[1], ... , x[k - 1] are
distinct. It then checks whether x[k] is different from each of x[1], ... , x[k
- 1] and whether (x[k - 1], x[k]) is an edge. If k = n, path_ok also checks
whether (x[n], x[1]) is an edge.

Input Parameter: adj


Output Parameter: x
hamilton(adj,x) {
n = adj.last
x[1] = 1
used[1] = true
for i = 2 to n
used[i] = false
rhamilton(adj,2,x)
}
rhamilton(adj,k,x) {
n = adj.last
for x[k] = 2 to n
if (path_ok(adj,k,x)) {
used[x[k]] = true
if (k == n || rhamilton(adj,k + 1,x))
return true
used[x[k]] = false
}
return false
}
...

...
path_ok(adj,k,x) {
n = adj.last
if (used[x[k]])
return false
if (k < n)
return adj[x[k - 1]][x[k]]
else
return adj[x[n - 1]][x[n]] && adj[x[1]][x[n]]
}

Вам также может понравиться