简体   繁体   中英

Multithreaded approach to concurrently traversing a Binary search Tree by “inorder” and “reverse inorder” methods, comparing element pairs

There are a few scenarios in which being able to compare the last and first elements in a Binary Search tree, element pair wise , would prove to be useful.

For example: Finding 2 elements which would sum up to a give number. (The fastest way is trying to add the smallest and the largest numbers and then advancing each end according the resulting sum when compared to the given number)

^I know this can be done by using 2 stacks to traverse the trees in an iterative way. I was just thinking if there was a way in which I could do something like this using 2 threads :

pthread_mutex_t MTree1, Mtree2;
pthread_t thread[2];
pthread_attr attr;
int data1, data2;
int tempInorder, tempRevInorder;
int requiredSUM

void mergBST(node*root)
{
    pthread_mutex_init(&Mtree1, NULL);
    pthread_mutex_init(&Mtree2, NULL);
    pthread_attr_setdetachestate(&attr,PTHREAD_CREATE_JOINABLE);

    pthread_create(&thread[0],&attr, mergeBSTImplInOrder, void*(root));
    pthread_create(&thread[1],&attr, mergeBSTImplRevInOrder, void*(root));

}

 void mergeBSTImplInOrder(void *root)
    {
        root=(node*) root;
        if(!root) return;

        mergeBSTImpl(root->left);

        tempInorder=root->data

            /*This is where there has to be conditional checks such that execution would stop right here so I can compare varables **tempInorder** **tempRevInorder** with the variable "requiredSUM"*/

        mergeBSTImpl(root->right);
    }


 void mergeBSTImplRevInOrder(void *root)
    {
        root=(node*) root;
        if(!root) return;
        mergeBSTImpl(root->right);

        tempRevInorder=root->data;
        //A similar situation as the other function.

        mergeBSTImpl(root->left);
    }

So... Is what I'm trying to do logically possible? This is my first post in stackoverflow. I hope I got the formats and things right. If not, please be kind. =)

The stack method takes atleast O(logm + logn) space . The threaded way could actually get this done with simpler code and O(1) space

Just in case, What I'm trying to get done is:

2 functions, each running it's own thread:
Fn1 (say): One, a function that recurses in an Inorder fashion.
Fn2 (say): Two, a function that recurses in a reverse Inorder fashion.

Each time either of the function reads data from the BST, it stores them in static variables, and it has to check if two elements saved from the 2 functions are there to compare. One from itself, the other from the other function. if there are 2 elements yet, then it finds the sum of the elements with requiredSUM. In case the sum of variable is bigger, it lets the other function continue till it gets the next one (which would be the second smallest element). This function stays till the other function gets its new element. Comparison takes place. If this time, the sum is smaller than requiredSUM, this function carries on and the other function waits till this function gets the next element (the 2nd smallest element). Comparison takes place and this goes on till the 2 elements summing to the required target Sum is found.

This is an algorithm to find all pairs of integers within an sorted array which sum to a specified value. EXCEPT that instead of a sorted array, we now have a BST . Just to show, I would solve the array version of the problem by the following:

#include <iostream>
#include <algorithm>

using namespace std;

void print_pairs(int * ptr, int num, int sum) 
{
    std::sort(ptr, ptr + num);
    int first = 0;
    int last = num - 1;

    while (first < last) 
    {
        int s = ptr[first] + ptr[last];
        if (s == sum) 
        {
            //cout<<ptr[first]<<“ “<< ptr[last]<<endl;
            ++first;
            --last;
        }
        else 
        {
            if (s < sum) 
                ++first; 
            else 
                --last;
        }
    }
}

int main() 
{
int test[] = {9, 3, 6, 5, 7, -1, 13, 14, -2, 12, 0};
print_pairs(test, sizeof(test) / sizeof(int), 12);
return 0;
}

My feeling is that threads are not the answer to your problem. Two cursor state or iterator-like objects that keeps the state of the traversal backward and forward will give you the same results.

Threads are a way of coordinating execution, not a way of parcelling the code. And in any case you should avoid threads as much as possible, this being a case (threads never running simultaneously) where threads are not adding value to the solution

If you insists, then what you want are condition variables.

A condition is a place where one thread will block until other thread signals it to continue. Conditions are linked to a mutex.

So on thread1 you would:

thread1stopped=false; // let this start running
while (true) {
    pthread_mutex_lock(&mutex2); // lock on the other thread mutex
    while(!thread2stopped) {
        pthread_cond_wait(&cond2, &mutex2); // wait for the signal
    }
    pthread_mutex_unlock(&mutex2); // unlock the other thread mutex

    // Now we're running:
    // ... do whatever I need to do
    // ... until I need to stop.
    pthread_mutex_lock(&mutex1); // lock my mutex
    thread1stopped=true;         // change the state
    pthread_cond_signal(&cond1); // signal to the other thread
    pthread_mutex_unlock(&mutex1); // unlock my mutex
    pthread_mutex_lock(&mutex1); // lock my mutex
    thread1stopped=false;
    pthread_mutex_unlock(&mutex1); // unlock my mutex
 }

while the other can

thread2stopped=true; // let this start stopped
while (true) {
    pthread_mutex_lock(&mutex1); // lock on the other thread mutex
    while(!thread1stopped) {
        pthread_cond_wait(&cond1, &mutex1); // wait for the signal
    }
    pthread_mutex_unlock(&mutex1); // unlock the other thread mutex

    // Now we're running:
    // ... do whatever I need to do
    // ... until I need to stop.
    pthread_mutex_lock(&mutex2); // lock my mutex
    thread2stopped=true;         // change the state
    pthread_cond_signal(&cond2); // signal to the other thread
    pthread_mutex_unlock(&mutex2); // unlock my mutex
    pthread_mutex_lock(&mutex2); // lock my mutex
    thread2stopped=false;
    pthread_mutex_unlock(&mutex2); // unlock my mutex
 }

This works:

  Thread1             Thread2
      .                   .
   --------           --------
   | exec |           | lock1| thread1stopped==false
   |      |           | wait | (wait unlocks)
   --------           |      |
      .               |      |
   --------           |      |
   |lock1 |           |      |
   |true  |           |      |
   |signal|---------->|unlock|
   --------           --------
      .                   .
   --------           --------
   | lock2|           | exec |
   | wait |           |      |
   |      |           --------
   |      |               .
   |      |           --------
   |      |           |lock2 |
   |      |           |true  |
   |unlock|<----------|signal|
   --------           --------

Haven't really tried this code, so there might be problems, dead-locks, race conditions... But I hope it would give you a starting point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM