Thread: Problem implementing priority queue using array

  1. #1
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53

    Problem implementing priority queue using array

    Hi,

    I am trying to implement a priority queue of unsigned ints(timestamps) using array.

    Here is what my code looks like.

    The GetCurrTime returns time in microseconds

    Code:
    unsigned int GetCurrTime()
    {
        struct timeval tv;
        struct timezone tz;
        struct tm *tm;
        gettimeofday(&tv, &tz);
        tm=localtime(&tv.tv_sec);
        unsigned int myTimestamp = ((unsigned int)(tv.tv_usec + tv.tv_sec*1000000)); 
        printf( "Tstp = %u \n", myTimestamp );
        return myTimestamp;
    }

    The addToQueue function adds timestamps to a global array msgArray which is implemented as a priority queue. The smallest value comes first in the array.

    Code:
    void addToQueue( unsigned int num )
    {
    	int pos = 0;
    	int move = 0;
    
    	if(rear<MAX)
    	{
    		/*find position to insert*/
    		for (pos=0; num>=msgArray[pos]&& pos<=rear  && msgArray[pos]!=0 ; pos++)
    		{
    		
    		}
    		
    		/*shift cells*/
    		for (move=rear; move>=pos; move--)
    		{
    			msgArray[move+1]=msgArray[move];
    		}
    		
    		/*copy new int*/
    		msgArray[pos]=num;
    		rear++;
    
    	}
    	else
    	{
    		printx("\nNo more room to add data", "");
    	}
    }

    In my main function, I do something like

    Code:
    int main()
    {
    	unsigned int time1;
    	unsigned int time2;
    	unsigned int time3;
    	unsigned int time4;
    	unsigned int time5;
    	unsigned int time6;
    	unsigned int time7;
    	unsigned int time8;
    	unsigned int time9;
    	unsigned int time10;
    	unsigned int time11;
    	unsigned int time12;
    	unsigned int time13;
    	unsigned int time14;
    	unsigned int time15;
    	
    	time1 = GetCurrTime();
    	time2 = GetCurrTime();
    	time3 = GetCurrTime();
    	time4 = GetCurrTime();
    	time5 = GetCurrTime();
    	time6 = GetCurrTime();
    	time7 = GetCurrTime();
    	time8 = GetCurrTime();
    	time9 = GetCurrTime();
    	time10 = GetCurrTime();
    	time11 = GetCurrTime();
    	time12 = GetCurrTime();
    	time13 = GetCurrTime();
    	time14 = GetCurrTime();
    	time15 = GetCurrTime();
    
    	addToQueue(time2);
    	addToQueue(time3);
    	addToQueue(time5);
    	addToQueue(time1);
    	addToQueue(time4);
    	addToQueue(time7);
    	addToQueue(time6);
    	addToQueue(time13);
    	addToQueue(time9);
    	addToQueue(time4);
    	addToQueue(time8);
    	addToQueue(time11);
    	addToQueue(time10);
    	addToQueue(time15);
    	addToQueue(time14);
    	addToQueue(time12);
    
    	for(j<0;j<20;j++)
    		printf("\nTimestamp = ", msgArray[j]);
    }
    The output I get is something like

    Code:
    Timestamp = 3668331519
    Timestamp = 3668331955
    Timestamp = 3668332013
    Timestamp = 3668332071
    Timestamp = 3668332071
    Timestamp = 3668332129
    Timestamp = 3668332186
    Timestamp = 3668332244
    Timestamp = 3668332301
    Timestamp = 3668336836
    Timestamp = 3668336900
    Timestamp = 3668336958
    Timestamp = 3668337016
    Timestamp = 3668337073
    Timestamp = 3668337131
    Timestamp = 3668337188
    Timestamp = 0000000000
    Timestamp = 0000000000
    Timestamp = 0000000000
    Timestamp = 0000000000
    As you can see the 3rd and the 4th value repeat.But i'm not sure why this is happening. Can someone please help me figure out a problem with my implementation.

    Thanks.

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    First off, why don't you do this*:
    Code:
    unsigned int time[13], i;
    for (i=0; i<13; i++) {
        time[i] = GetCurrTime();
    }
    As for your problem, well, if this is just a couple of (randomly placed) identical values
    1. print out the values in time[] before you feed them to the array, because they were probably identical to start with
    2. add sleep(1) into the for loop I suggested to guarantee all the values are different


    Your processor can perform tens of billions of operations per second. Of course, the whole routine GetCurrentTime() includes way more than one op, and the processor is also responsible for other things. But the point is, it is easily possible to fit lots of operations into one microsecond.

    As is, you can see the differences differ by a factor of ten (sometimes it is <50 usec, sometimes it is >500 usec), and you only have 13 samples. If you did this 10000 times, you might get some idea of the general window -- but that is still a guarantee of nothing, since chances are if processor priorities permit, GetCurrentTime() will execute more than once in a microsecond (conversely, it may have to wait a while). You must use a gap. If 1 second is too long for you to wait, you are already using the high res timer, so:
    Code:
    void gap (int secs, int hundredths) {
            struct timespec interval;
            interval.tv_sec=secs;
            interval.tv_nsec=hundredths*10000;
            nanosleep(&interval,NULL);
    }
    Usage is gap(0,1) to "sleep" 1/100th of a second.

    * in fact, you can do this:
    Code:
    for (i=0; i<13; i++) {
        addToQueue(GetCurrTime());
        gap(0,1);
    }
    to use the return value of one function as a parameter for another.
    Last edited by MK27; 11-23-2009 at 12:03 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    It's quite possible to get the same timestamp in two successive calls. Processors are FAST.

    If you want to preserve the SEQUENCE of events in the queue, so that they at least get processed in the order they were inserted even though they all have the same timestamp, then just make a minor change to your queue insert function so that events are always inserted AFTER any event with the same timestamp.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  4. #4
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    Quote Originally Posted by MK27 View Post
    First off, why don't you do this*:
    Code:
    unsigned int time[15], i;
    for (i=0; i<15; i++) {
        addToQueue(GetCurrTime());
    }
    I am just trying to test my addToQueue function by passing time values in random order.

    I agree that I can get the same timestamp in two successive calls and will have to handle it. Thanks for the gap function.

    However, I think there is another problem with my code. I ran the code again and printed out the timestamp values inside the GetCurrTime function and they were all unique. However, the output still showed the same array indexes 3 and 4 as duplicates.

    Also you can see from my output that though I have generated 15 timestamps, my output array has 16 values. So there is an extra value being written to my output array which is a duplicate.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    I didn't test your code but here is my guess.

    Code:
    for (move=rear; move>=pos; move--)
    		{
    			msgArray[move+1]=msgArray[move];
    		}
    Now, that means that even if a number is higher than all the other numbers, so pos == rear, this loop will occur once, copying the second highest number into it's position. More importantly, this will also happen the first time, which throws a wrench into this set of conditions:

    num>=msgArray[pos]&& pos<=rear && msgArray[pos]!=0

    msgArray[rear] is no longer 0, and pos could == rear. So right away you end up with an extra number (notice there's 16 of them at the end). This error will be "corrected" whenever a new low number is added, pushing the whole list down. But that does not happen after you insert the fourth highest value -- 1, 2, and 3 are already there. So now you have 1, 2, 3, and 4, and four is there twice, then you add 5*. This portion of the array is never modified again.

    The reason this problem doesn't repeat has to do with the order the numbers are inserted in -- they continue to bump one another down in sets. Basically, this is a complex version of the classic "off by one error".

    * oops! that's not true. You add five first -- anyway, it seems to me this is the nature of the problem. A little hard to get straight just by thinking about it why it occurs where it does, maybe I will come back in a minute if I can get it exactly I would start by fixing that for loop. Remember, presuming "rear" was initially 0, it will always refer to the number after the last number in the array.
    Last edited by MK27; 11-23-2009 at 02:44 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    Turns out there was no problem with the code. I was doing addToQueue(time4) twice hence the problem :|

    Sorry MK27 my stupid goof up wasted your time.

  7. #7
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by lazyme View Post
    Turns out there was no problem with the code.
    Well, I assume that you will not come back to read this then, but if you do, take into account what I pointed out -- the end result is okay, but that method is still flawed IMO. Which is not an A-train way to program*

    And if I didn't want to waste my time, I should've spotted that mix up first. Except, like I said, there is CLEARLY an issue with that for loop anyway. If you add the highest number last, it will show up, methinks.

    * judging one set of results as proof "there is nothing wrong with the code".
    Last edited by MK27; 11-24-2009 at 10:07 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  8. #8
    Apprentice
    Join Date
    Oct 2006
    Location
    LA
    Posts
    53
    Ok.

    What do you suggest me to change? Is my for loop flawed?
    This is the best way I could think of implementing it.

  9. #9
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by lazyme View Post
    Ok.

    What do you suggest me to change? Is my for loop flawed?
    This is the best way I could think of implementing it.
    Well, at least read that post and see if you see what I see.

    Then gimme a moment to test this, since I'm the one making a fuss, and I could be wrong...
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Okay, I was right, and wrong. It does "unnecessarily" push the numbers down, eg, even when you insert the highest number, it bumps the zeros down.

    But this does not lead to the complications I hypothesized, so it is not really a bug.

    You could eliminate it anyway by enclosing in a condition:
    Code:
    if (pos != rear) {
          [the for loop]
    }
    Also -- I presume you are aware of this -- if one of the numbers added to the queue is zero, the algorithm falls apart (try it). That doesn't matter if it is intended for time stamps or values guaranteed to be greater than zero.

    If you are curious, here's the code I used to test. Notice a "!" is printed inside the for loop, indicating when it occurs. It occurs the first time, even though there are no numbers to push down (etc).

    Code:
    #include <stdio.h>
    
    #define MAX 10
    
    unsigned int msgArray[10] = {0};
    int rear = 0;
    
    void addToQueue( unsigned int num )
    {
    	int pos = 0;
    	int move = 0;
    
    	printf("add: %d\n",num);
    
    	if(rear<MAX)
    	{
    		/*find position to insert*/
    		for (pos=0; num>=msgArray[pos]&& pos<=rear  && msgArray[pos]!=0 ; pos++)
    		{
    		
    		}
    		
    		/*shift cells*/
    		for (move=rear; move>=pos; move--)
    		{
    			printf("!"); fflush(stdout);
    			msgArray[move+1]=msgArray[move];
    		}
    		
    		/*copy new int*/
    		msgArray[pos]=num;
    		rear++;
    
    	}
    	else
    	{
    		printf("\nNo more room to add data", "");
    	}
    }
    
    int main(int argc, char *argv[]) {
    	unsigned int testdata[10] = { 1234, 3, 345, 999999, 89231, 890, 666, 1, 8765, 10 };
    	int i,j;
    	
    	for (j=0; j<10; j++) {
    		addToQueue(testdata[j]);
    		for (i=0; i<10; i++) printf("%d\n", msgArray[i]);
    		getchar();
    	}
    
    	return 0;
    }
    ps. you don't have to use empty brackets with the insertion loop, you can just write:
    Code:
    for (pos=0; num>=msgArray[pos]&& pos<=rear  && msgArray[pos]!=0 ; pos++);
    Last edited by MK27; 11-24-2009 at 10:51 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Incidentally, have you considered using the array to implement a heap, then using the heap to implement a priority queue?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Lockless Threaded Queue
    By fguy817817 in forum C Programming
    Replies: 27
    Last Post: 11-18-2009, 03:25 PM
  2. Newbie Question: sizeof() problem in function
    By Xeyide in forum C Programming
    Replies: 3
    Last Post: 09-04-2009, 12:05 AM
  3. Fixing my program
    By Mcwaffle in forum C Programming
    Replies: 5
    Last Post: 11-05-2008, 03:55 AM
  4. Replies: 2
    Last Post: 07-11-2008, 07:39 AM
  5. queue help
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 10-29-2001, 09:38 AM