Open In App

Preparata Algorithm

Last Updated : 22 Mar, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Preparata’s algorithm is a recursive Divide and Conquer Algorithm where the rank of each input key is computed and the keys are outputted according to their ranks.

C++

m[i, j] := M[i, j]
for 1 <= i, j <= n in parallel;
 
for
    r : = 1 to logn do
    {
    Step 1. In parallel set q[i, j, k] := m[i, j] + m[j, k] for
    1 <= i, j, k <= n.
 
    Step 2. In parallel set m[i, j] := min
    {
        q[i, l, j], q[i, 2, j], ..., q[i, n, j]
    }
     for
         1 <= i, j <= n.
    }
Put M(i)(i):=0 for all i and M(i)(j):=m[i, j] for i≠j

                    

In the above procedure O(N3) global memory is used by using the variables m[i, j] for 1 ≤ i, j ≤ N and q[i, j, k] for 1 ≤ i, j, k ≤ N.

  • Initializing m[ ] that takes O(N2) time.
  • Step 1 of the above algorithm takes O(1) time while using 3 processors.
  • In Step 2, N2 number of different m[i, j]’s are computed.

The computation of a single m[z, j] involves computing a minimum of N numbers and hence can be completed in O(1) time using N2 CRCW PRAM processors. In fact, this minimum can also be computed in O(1) time using n(1 + e) processors for any fixed e > 0.

Step 2 can be completed in O(1) time using n(3 + e) common CRCW PRAM processors. Thus, the for loop runs in O(log N) time. The final computation of M also can be done in O(1) time using N2 processors.

The correctness of the above algorithm can be proven by induction on R. It can be shown that the value of m[i, j] at the end of the rth iteration of the for loop is min, and the minimum is taken over all the sequences of elements of {1, 2, …, N} such that k < 2R. The above algorithm can be specialized to solve several problems including the transitive closure, connected components, minimum spanning tree, and so on.

Let k1, k2, …, kn be the input sequence. Preparata’s algorithm partitions the input into log N parts K1, K2, …, if log N; where there are N/log N keys in each part.
If k is any key in the input, its rank in the input is computed as follows. First, the rank Ri of k is computed for each i, 1< i < log N. Then, the total rank of k is computed as \sum_{i}^{log N} R_i      . One of the results that make the use of the above algorithm. 

The details of Preparata’s algorithm are given below.

Consider T(N) to be the run time of Preparata’s algorithm using N*log N processors. Clearly, step 1 takes T(N/log N) time and steps 2 and 3 together take O(log(log N)) time. Thus, there is

T(n) = T(N/log N) + O(log(log N))

which can be solved by repeated substitution to get T(N) = O(log N). Also, the number of processors used in each step is N*log N.

Preparata’s Sorting Algorithm

Below are the steps for the Preparata’s Sorting Algorithm:

  • If N is a small constant, sort the keys using any algorithm and quit.
  • Partition the given N keys into log N parts, with N/(log N) keys in each part.
  • Sort each part recursively and separately in parallel, assigning N processors to each part. Let S1, S2, …, Slog N be the sorted sequences.
  • Merge Si with Sj for 1< i, j < log N in parallel. This can be done by allocating N/(log N) processors to each pair(i, j). That is, using N*log N processors, this step can be accomplished in O(log(log N)) time with the algorithm. As a by-product of this merging step, the rank is computed of each key in each one of the Si‘s(1 < i < log N).
  • Allocate log N processors to compute the rank of each key in the original input. This is done in parallel for all the keys by adding the log N ranks computed (for each key) in step 2. This can be done in O(log(log N)) time using the prefix computation algorithm.
  • Finally, the keys are written in the order of their ranks.

Below is the implementation of the above approach:

C++

// C++ program to implement Preparata's
// a time-optimal parallel algorithm
 
#include <iostream>
#include <vector>
using namespace std;
 
// Class for Point
class Point {
public:
    int x, y;
 
    // Constructor
    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }
};
 
// Finds the left most index of the given
// set of points
class LeftIndex {
public:
    int leftMostIndex(Point points[], int n) {
        int min = 0;
         
          // Finding the point on plane
        // with minimum x value
        for (int i = 1; i < n; i++) {
            // Update the minimum index
            if (points[i].x < points[min].x)
                min = i;
            else if (points[i].x == points[min].x) {
                if (points[i].y > points[min].y)
                    min = i;
            }
        }
 
        // Return the minimum index
        return min;
    }
     
      // Perform the parallel process in the
    // preparata's algorithm according to
    // the value of p, q, r
    int parallel(Point p, Point q, Point r) {
        // For the three-dimensional
        int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
         
          // If val is equals to 0, then
        // the points are collinear
        if (val == 0)
            return 0;
        else if (val > 0) // Clockwise
            return 1;
        else // Anti-clockwise
            return 2;
    }
     
       // Perform the parallel process in the
    // preparata's algorithm
    void preparata(Point points[], int n) {
        // There must be at least 3 points
        if (n < 3)
            return;
 
        // Find the left most point
        int l = leftMostIndex(points, n);
        vector<Point> pre;
         
          // Start from left most point, keep
        // moving counterclockwise until reach
        // the start point again.
        int p = l, q;
        do {
            // Add current point to result
            pre.push_back(points[p]);
             
              // Search for a point 'q' such that
            // orientation(p, q, r) is counterclockwise
            // for all points 'r'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
            for (int i = 0; i < n; i++) {
               
                  // If i is more counterclockwise than
                // current q, then update q
                if (parallel(points[p], points[i], points[q]) == 2)
                    q = i;
            }
             
              // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'pre'
            p = q;
        } while (p != l);
 
        // Print Result
        for (int i = 0; i < pre.size(); i++)
            cout << "(" << pre[i].x << ", " << pre[i].y << ")" << endl;
    }
};
 
// Driver Code
int main() {
    Point points[] = {Point(0, 3), Point(2, 2), Point(1, 1), Point(2, 1), Point(3, 0), Point(0, 0), Point(3, 3)};
    int n = sizeof(points) / sizeof(points[0]);
 
    LeftIndex obj;
    obj.preparata(points, n);
 
    return 0;
}
 
//this code is contributed by bhardwajji

                    

Java

// Java program to implement Preparata's
// a time-optimal parallel algorithm
import java.util.*;
// Class for Point
class Point
{
    int x, y;
   
    // Constructor
    Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}
   
// Finds the left most index of the given
// set of points
class LeftIndex
{
    int leftMostIndex(Point points[], int n)
    {
        // Initialize the minimum index
        int min = 0;
   
        // Finding the point on plane
        // with minimum x value
        for (int i = 1; i < n; i++)
        {
            // Update the minimum index
            if (points[i].x < points[min].x)
                min = i;
            else if (points[i].x == points[min].x)
            {
                if (points[i].y > points[min].y)
                    min = i;
            }
        }
   
        // Return the minimum index
        return min;
    }
   
    // Perform the parallel process in the
    // preparata's algorithm according to
    // the value of p, q, r
    int parallel(Point p, Point q, Point r)
    {
        // For the three-dimensional
        int val = (q.y - p.y) * (r.x - q.x) -
                  (q.x - p.x) * (r.y - q.y);
   
        // If val is equals to 0, then
        // the points are collinear
        if (val == 0)
            return 0;
        else if (val > 0) // Clockwise
            return 1;
        else // Anti-clockwise
            return 2;
    }
   
    // Perform the parallel process in the
    // preparata's algorithm
    void preparata(Point points[], int n)
    {
        // There must be at least 3 points
        if (n < 3)
            return;
   
        // Find the left most point
        int l = leftMostIndex(points, n);
        List<Point> pre = new ArrayList<Point>();
   
        // Start from left most point, keep
        // moving counterclockwise until reach
        // the start point again.
        int p = l, q;
        do
        {
            // Add current point to result
            pre.add(points[p]);
   
            // Search for a point 'q' such that
            // orientation(p, q, r) is counterclockwise
            // for all points 'r'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
            for (int i = 0; i < n; i++)
            {
                // If i is more counterclockwise than
                // current q, then update q
                if (parallel(points[p], points[i],
                             points[q]) == 2)
                    q = i;
            }
   
            // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'pre'
            p = q;
        } while (p != l);
   
        // Print Result
        for (int i = 0; i < pre.size(); i++)
            System.out.println("("+ pre.get(i).x +
                               ", "+ pre.get(i).y +")");
    }
 
 
// Driver Code
public static void main(String[] args)
{
    Point points[] = new Point[7];
    points[0] = new Point(0, 3);
    points[1] = new Point(2, 2);
    points[2] = new Point(1, 1);
    points[3] = new Point(2, 1);
    points[4] = new Point(3, 0);
    points[5] = new Point(0, 0);
    points[6] = new Point(3, 3);
   
    LeftIndex obj = new LeftIndex();
    obj.preparata(points, 7);
} }

                    

Python3

# Python program to implement Preparata's
# a time-optimal parallel algorithm
 
 
class func:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
# Function to find the left index of
# the given set of points
def Left_index(points):
     
    # Finding the point on plane
    minn = 0
     
    # Traverse the given points
    for i in range(1, len(points)):
       
          # Update the value of minn
        if points[i].x < points[minn].x:
            minn = i
        elif points[i].x == points[minn].x:
            if points[i].y > points[minn].y:
                minn = i
                 
    # Return the value of min
    return minn
 
# Function to perform the parallel
# process in the preparata's algorithm
# according to the value of p, q, r
def parallel(p, q, r):
 
    # For the three-dimensional
    val = (q.y - p.y) * (r.x - q.x) - \
        (q.x - p.x) * (r.y - q.y)
 
    if val == 0:
        return 0
    elif val > 0:
        return 1
    else:
        return 2
 
# Function to perform the parallel
# process in the preparata's algorithm
def preparata(points, n):
 
    # There must be at least 3 points
    if n < 3:
        return
 
    # Find the leftmost point
    l = Left_index(points)
 
    pre = []
 
    p = l
    q = 0
    while(True):
 
        # Add current point to result
        pre.append(p)
 
        q = (p + 1) % n
 
        for i in range(n):
 
            # If i is more counterclockwise
            # than current q, then update q
            if(parallel(points[p],
                        points[i], points[q]) == 2):
                q = i
 
        p = q
 
        # While it doesn't come to first point
        if(p == l):
            break
 
    # Print Result
    for each in pre:
        print(points[each].x, points[each].y)
 
# Driver Code
 
 
algo = []
algo.append(func(0, 3))
algo.append(func(2, 2))
algo.append(func(1, 1))
algo.append(func(2, 1))
algo.append(func(3, 0))
algo.append(func(0, 0))
algo.append(func(3, 3))
 
# Function Call
preparata(algo, len(algo))

                    

C#

using System;
using System.Collections.Generic;
 
// Class for Point
public class Point
{
    public int x, y;
 
    // Constructor
    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}
 
// Finds the left most index of the given
// set of points
public class LeftIndex
{
    public int leftMostIndex(Point[] points, int n)
    {
        int min = 0;
 
        // Finding the point on plane
        // with minimum x value
        for (int i = 1; i < n; i++)
        {
            // Update the minimum index
            if (points[i].x < points[min].x)
                min = i;
            else if (points[i].x == points[min].x)
            {
                if (points[i].y > points[min].y)
                    min = i;
            }
        }
 
        // Return the minimum index
        return min;
    }
 
    // Perform the parallel process in the
    // preparata's algorithm according to
    // the value of p, q, r
    public int parallel(Point p, Point q, Point r)
    {
        // For the three-dimensional
        int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
 
        // If val is equals to 0, then
        // the points are collinear
        if (val == 0)
            return 0;
        else if (val > 0) // Clockwise
            return 1;
        else // Anti-clockwise
            return 2;
    }
 
    // Perform the parallel process in the
    // preparata's algorithm
    public void preparata(Point[] points, int n)
    {
        // There must be at least 3 points
        if (n < 3)
            return;
 
        // Find the left most point
        int l = leftMostIndex(points, n);
        List<Point> pre = new List<Point>();
 
        // Start from left most point, keep
        // moving counterclockwise until reach
        // the start point again.
        int p = l, q;
        do
        {
            // Add current point to result
            pre.Add(points[p]);
 
            // Search for a point 'q' such that
            // orientation(p, q, r) is counterclockwise
            // for all points 'r'. The idea is to keep
            // track of last visited most counterclock-
            // wise point in q. If any point 'i' is more
            // counterclock-wise than q, then update q.
            q = (p + 1) % n;
            for (int i = 0; i < n; i++)
            {
                // If i is more counterclockwise than
                // current q, then update q
                if (parallel(points[p], points[i], points[q]) == 2)
                    q = i;
            }
 
            // Now q is the most counterclockwise with
            // respect to p. Set p as q for next iteration,
            // so that q is added to result 'pre'
            p = q;
        } while (p != l);
 
        // Print Result
        for (int i = 0; i < pre.Count; i++)
            Console.WriteLine("(" + pre[i].x + ", " + pre[i].y + ")");
    }
}
 
// Driver
class Program
{
    static void Main(string[] args)
    {
        Point[] points = { new Point(0, 3), new Point(2, 2), new Point(1, 1), new Point(2, 1), new Point(3, 0), new Point(0, 0), new Point(3, 3) };
        int n = points.Length;
 
        LeftIndex obj = new LeftIndex();
        obj.preparata(points, n);
 
        Console.ReadLine();
    }
}

                    

Javascript

//JS equivalent
//Function to find the left index of
//the given set of points
function Left_index(points) {
     
    // Finding the point on plane
    let minn = 0;
     
    // Traverse the given points
    for (let i = 1; i < points.length; i++) {
       
          // Update the value of minn
        if (points[i].x < points[minn].x) {
            minn = i;
        }
        else if (points[i].x == points[minn].x) {
            if (points[i].y > points[minn].y) {
                minn = i;
            }
        }
    }
    // Return the value of min
    return minn;
}
 
// Function to perform the parallel
// process in the preparata's algorithm
// according to the value of p, q, r
function parallel(p, q, r) {
 
    // For the three-dimensional
    let val = (q.y - p.y) * (r.x - q.x) -
        (q.x - p.x) * (r.y - q.y);
 
    if (val == 0) {
        return 0;
    }
    else if (val > 0) {
        return 1;
    }
    else {
        return 2;
    }
}
 
// Function to perform the parallel
// process in the preparata's algorithm
function preparata(points, n) {
 
    // There must be at least 3 points
    if (n < 3) {
        return;
    }
 
    // Find the leftmost point
    let l = Left_index(points);
 
    let pre = [];
 
    let p = l;
    let q = 0;
    while(true) {
 
        // Add current point to result
        pre.push(p);
 
        q = (p + 1) % n;
 
        for (let i = 0; i < n; i++) {
 
            // If i is more counterclockwise
            // than current q, then update q
            if (parallel(points[p],
                        points[i], points[q]) == 2) {
                q = i;
            }
        }
        p = q;
 
        // While it doesn't come to first point
        if (p == l) {
            break;
        }
    }
    // Print Result
    for (let each of pre) {
        console.log(points[each].x, points[each].y);
    }
}
 
// Driver Code
let algo = [];
algo.push({x: 0, y: 3});
algo.push({x: 2, y: 2});
algo.push({x: 1, y: 1});
algo.push({x: 2, y: 1});
algo.push({x: 3, y: 0});
algo.push({x: 0, y: 0});
algo.push({x: 3, y: 3});
 
// Function Call
preparata(algo, algo.length);

                    

Output
0 3
0 0
3 0
3 3


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads