Design and Analysis of Algorithms_Divide-and-Conquer

I collect and make up this pseudocode from the book:

<<Introduction to the Design and Analysis of Algorithms_Second Edition>> _ Anany Levitin

Note that throughout the paper, we assume that inputs to algorithms fall within their specified ranges and hence require no verfication. When implementing algorithms as programs to be used in actual applications, you should provide such verfications.

About pseudocode: For the sake of simplicity, we omit declarations of variables and use indentation to show the scope of such statements as for, if and while. As you saw later, we use an arrow <- for the assignment operation and two slashes // for comments.

Algorithm MergeSort(A[0..n-1])
    // Sorts array A[0..n-1] by recursive mergesort
    // Input: An array A[0..n-1] of orderable element
    // Output: Array A[0..n-1] sorted in nondecreasing order
    if n > 1
        copy A[0..⌊n/2⌋-1] to B[0..⌊n/2⌋-1] 
        copy A[⌊n/2⌋..n-1] to C[0..⌈n/2⌉-1] 
        MergeSort(B[0..⌊n/2⌋-1])
        MergeSort(C[0..⌈n/2⌉-1])
        Merge(B, C, A)
Algorithm Merge(B[
0..p-1], C[0..q-1], A[0..p+q-1]) // Merge two sorted arrays into one sorted array // Input: Arrays B[0..p-1] and C[0..q-1] both sorted // Output: Sorted array A[0..p+q-1] of the elements of B and C i <- 0; j <- 0; k<-0 while i < p and j < q do if B[i] ≤ C[j] A[k] <- B[i]; i <- i+1 else A[k] <- C[j]; j <- j+1 k <- k+1 if i = p copy C[j..q-1] to A[k..p+q-1] else copy B[i..p-1] to A[k..p+q-1]
Write a pseudocode for a divide-and-conquer algorithm for finding a position of the largest element in an array of n numbers.
Call Algorithm MaxIndex(A[0..n-1]) where
Algorithm MaxIndex(A[l..r])
   // Input: A portion of array A[0..n-1] between indices l and r(l ≤ r)
   // Output: The index of the largest element in A[l..r]
    if l = r return A[l]
    else
      
  temp1 <- MaxIndex(A[l..⌊(l+r)/2⌋])
        temp2 <- MaxIndex(A[⌊(l+r)/2⌋+1..r])
        if temp1 ≥ temp2
            return temp1
        else
            return temp2

The recurrence for the number of element comparisons is C(n) = n - 1. A simple standard scan through the array in question requires the same number of key comparisons but avoid the overhead associated with recurise calls.
Write a pseudocode for a divide-and-conquer algorithm for finding values of both the largest and smallest elements in an array of n numbers.
Call Algorithm MinMax(A[0..n-1], minval, maxval) where
Algorithm MinMax(A[l..r], minval, maxval)
    // Finds the values of the smallest and largest elements in a given subarray
    // Input: A portion of array A[0..n-1] between indices l and r(l ≤ r)
    // Output: The value of the smallest and largest elements in A[l..r]
    //            assigned to minval and maxval, respectively
    if l = r
        minval <- A[l]; maxval <- A[l]
    else if r-l = 1
        if A[l] ≤ A[r]
            minval <- A[l]; maxval <- A[r]
        else
            minval <- A[r]; maxval <- A[l]
    else // r-l > 1
        MinMax(A[..⌊(l+r)/2⌋)], minval, maxval)
        MinMax(A[⌊(l+r)/2⌋+1..r], minval2, maxval2)
        if minval2 < minval
            minval <- minval2
        if maxval2 > maxval
            maxval <- maxval2
The number of element comparison C(n) = (3/2)n - 2. This algorithm make about 25% fewer comparisons——1.5n compared to 2n——than the brute-force algorithm.(Note that if we didn't stop recursive calls when n = 2, we would've lost this gain.) In fact, the algorithm is optimal in terms ofthe number of comparisons made. As a practical matter, however, it might not be faster than the brute-force algorithm because of the recursion-related overhead.
Algorithm QuickSort(A[l..r])
    // Sorts a subarray by quicksort
    // Input: A subarray A[l..r] of A[0..n-1], defined by its left and right indices l and r
    // Output:Subarray A[l..r] sorted in nondecreasing order
    if l < r
        s <- Partition(A[l..r]) // s is a split position
        QuickSort(A[l..s-1])
        QuickSort(A[s+1..r])
        
Algorithm Partition(A[l..r])
    // Partitions a subarray by using its first element as a pivot
    // Input: A subarray A[l..r] of A[0..n-1], defined by its left and right indices l and r(l < r)
    // Output: A partition of A[l..r], with the split position returned as this function's value
    p <- A[l]
    i <- l; j <- r+1
    repeat 
        repeat i <- i+1 until A[i] ≥ p
        repeat j <- j-1 until A[j] ≤ p
        swap(A[i], A[j])
    until i ≥ j
    swap(A[i], A[j]) // undo last swap when i ≥ j
    swap(A[l], A[j])
    return j
Design an algorithm to rearrange elements of a given array of n real numbers so that all its negative elements precede all its positive elements. Your algorithm should be both time and space efficient.
The following algorithm uses the partition idea similar to that of quicksort, although it's implemented somewhat differently. Namely, on each iteration the algorithm maintains three section(possible empty) in a given array: all the elements in A[0..i-1] are negative, all the elements in A[i..j] are unknown, and all the elements in A[j+1..n-1] are nonnegative, on each iteration, the algorithm shrinks the size of the unknown section by one element either from the left or from the right. 
Algorithm NegBeforePos(A[0..n-1]) // Puts negative elements before position(and zeros, if any) in an array // Input: Array A[0..n-1] of real numbers // Output: Array A[0..n-1] in which all its negative elements precede nonnegative i <- 0; j <- n-1 while i ≤ j do // i < j would suffice if A[i] < 0 // shrink the unknown section from the left i <- i+1 else // shrink the unknown section from the right swap(A[i], A[j]) j <- j-1 Of cource, we can also use the under mathod, but this method lead a problem is that if all of the elements is nonnegative or nonpositive, we must use a sentinel.
Algorithm NegBeforePos(A[
0..n-1]) A[-1] <- -1; A[n] <- 1 // sentinel i <- 0; j <- n-1 while i < j do while A[i] ≤ 0 do i <- i+1 while A[j] ≥ 0 do j <- j-1 swap A[i] and A[j] swap A[i] and A[j] // undo the last swap Note: If we want all the zero elements placed after all the negative elements but before all the positive ones, the problem becomesthe Dutch flag problem, like the next Algorithm.
The Dutch flag problem is to rearrange any array of characters R, W, and B(red, white, and blue are the color of the Dutch national flag) so that all the R's come first, the W's come next, and the B's come last. Design a linear in-place algorithm for this problem.  
The follwing algorithm uses the partition idea similar to that of quick-sort. On each iteration, the algorithm maintains four sections(possibly empty) in a given array: all the elements in A[0..r-1] are filled with R's, all the elements in A[r..w-1] are filled with W's, all the elements in A[w..b] are unknown, and all the elements in A[b+1..n-1] are filled with B's. On each iteration, the algorithm shrinks the size of unknown section by one element either from the left or from the right.

Algorithm DutchFlag(A[0..n-1])
    // Sorts an array with values in a three-element set
    // Input: An array A[0..n-1] of characters from {'R', 'W', 'B'}
    // Output: Array A[0..n-1] in which all its R elements precede all its W 
    //            elements that precede all its B elements
    r <- 0; W <- 0; b <- n-1
    while w ≤ b do
        if A[w] = 'R'
            swap(A[r], A[w]); r <- r+1; w <- w+1
        else if A[w] = 'W'
            w <- w+1
        else // A[w] = 'B'
            swap(A[w], A[b]); b <- b-1    
Algorithm BinarySearch(A[0..n-1], K)
    // Implements nonrecursive binary search
    // Input: An array A[0..n-1] sorted in ascending order and a search key K
    // Output: An index of the array's element that is equal to K or -1 if there is no such element
    l <- 0; r <- n-1
    while l ≤ r do
        m <- ⌊(l+r)/2⌋
        if K = A[m] return m
        else if K < A[m] r <- m-1
        else l <- m+1
    return -1
Write a pseudocode for a recursive version of binary search.
Call BSR(A[0..n-1], K) where
Algorithm BSR(A[0..n-1], K)
    // Implements binary search recursively
    // Input: A sorted (sub)array A[l..r] and a search key K
    // Output: An index of the array's element equal to K or -1 if there is no such elements
    if l > r return -1
    else m <- ⌊(l+r)/2⌋
        if K = A[m] return m
        else if K < A[m] return BSR(A[l..m-1], K)
        else return BSR(A[m+1..r], K)
Algorithm Height(T)
    // Computes recursively the height of a binary tree
    // Input: A binary tree T
    // Output: The height of T
    if T = Ø return -1
    else return max{Height(TL), Height(TR)} + 1
The following algorithm for compute the number of leaves in a binary tree.
Algorithm LeafCounter(T)
    // Computes recursively the number of leaves in a binary tree
    // Input: A binary tree T
    // Output: The number of leaves in T
    if T = Ø return 0    // empty tree
    else if TL = Ø and TR = Ø return 1 // one-node tree
    else return LeafCounter(TL) + LeafCounter(TR) // general case    
Write a pseudocode for one of the classic traversal algorithm(preorder, inorder, and postorder) for binary trees. Assuming that your algorithm is recursive, find the number of recursive calls made.
Here is a pseudocode of the preorder traversal:

Algorithm Preorder(T)
    // Implements the preorder traversal of a binary tree
    // Input: Binary tree T(with labeled vertices)
    // Output: Node labels listed in preorder
    if T ≠ Ø
        print label of T's root
        PreOrder(TL) // TL is the root's left subtree
        PreOrder(TR) // TR is the root's right subtree

The number of calls, C(n), made by the algorithm is equal to the number of nodes, both internal and external, in the extended tree. Hence, C(n) = 2n + 1
new words:
portion: 部分 divide and conquer: 分而治之;各个击破
optimal: 最佳的 split: 分裂 pivot: 枢轴 precede: 在...之前; 优于
partition: 分区 namely: 换句话说, 也就是 shrink: 缩小
suffice: 足够 Dutch: 荷兰 undo: 撤销

 

(Terminator: XPJIANG)

转载于:https://www.cnblogs.com/xpjiang/p/4539262.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值