gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Sorting Algorithm Question (A* Related)

#35945 - Celeryface - Sun Feb 13, 2005 1:44 pm

Hi there,

I'm trying to decide on an algorithm to use for the sorting portion my A* implementation (Sorting the nodes to have the highest F value at the top of the heap). I will be using C, for reference.

I have implemented A* using C++ and the priority queue (heap sort) from STL on the PC, but I want to use C for the GBA implementation.

Can anyone recommend which sorting algorithm I should use in C that will be fast on the GBA to sort the nodes?

Thanks in advance. :)

#35946 - sasq - Sun Feb 13, 2005 2:02 pm

qsort()

part of the standard c-library and pretty fast for general cases.

#35948 - Celeryface - Sun Feb 13, 2005 2:34 pm

sasq wrote:
qsort()

part of the standard c-library and pretty fast for general cases.


For qsort(), can you specify a comparison function so that it can compare a certain value within a structure?

#35952 - ymalik - Sun Feb 13, 2005 3:48 pm

Yes.

#35953 - Celeryface - Sun Feb 13, 2005 3:50 pm

ymalik wrote:
Yes.


Thanks!

#35990 - DiscoStew - Sun Feb 13, 2005 10:15 pm

To use qsort() on the GBA, what is needed (like what files and such need to be included)? Also, how much memory would such a function take up, and could it be implemented into IWRAM? I'm currently using my own sorting algorithm that I think runs pretty well, but I'm open to anything faster.
_________________
DS - It's all about DiscoStew

#35992 - Miked0801 - Sun Feb 13, 2005 10:18 pm

Howe many nodes are you sorting?

#36003 - Celeryface - Mon Feb 14, 2005 12:23 am

Miked0801 wrote:
Howe many nodes are you sorting?


The node grid array would be 32x32 max.

#36029 - sasq - Mon Feb 14, 2005 11:09 am

qsort sorts "in place" and does not take any extra memory. That's also it's weekness since it uses memcpy to move things around which is a overhead you may not want when you can just sort pointers and read/write them without the function-call overhead.

A good way is to use the source of qsort() directly, make it work as it is and then maybe eliminate the memcpy() if necessary.

#36051 - tepples - Mon Feb 14, 2005 5:58 pm

sasq wrote:
qsort sorts "in place" and does not take any extra memory.

Not necessarily, for two reasons:
  • qsort() implemented as Quicksort uses a data-size-dependent amount of stack space. On the other hand, Metrowerks CodeWarrior for Mac implemented qsort as Heapsort, a true in-place sort that takes constant extra memory.
    Learn more about sorting algorithms
  • Your comparison function could be written such that qsort() does in fact sort pointers as you suggest. This would involve dereferencing each pointer inside the comparison function.


Quote:
That's also it's weekness since it uses memcpy to move things around which is a overhead you may not want when you can just sort pointers and read/write them without the function-call overhead.

If you can fit your comparison function into five registers, the function-call overhead on ARM isn't nearly as bad as it is on x86.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#36054 - sasq - Mon Feb 14, 2005 6:19 pm

This is what I use in pogoshell; it's only slightly modified from something I found on the net. It does need enough stack for recursive calls to partition() so you're right about it needing more memory.



Code:

static char *tmp_item;
static int item_size;
static int (*cmp_func)(void *a, void *b);

static int partition(char *a, int low, int high)
{
   int left, right, pivot;
   char *pivot_item;

   pivot_item = &a[low * item_size];
   pivot = left = low;
   right = high;

   while(left < right)
   {
      // Move left while item < pivot
      while(cmp_func(&a[left * item_size], pivot_item) <= 0) left++;
      // Move right while item > pivot
      while(cmp_func(&a[right * item_size], pivot_item) > 0) right--;
      if(left < right)
      {
         // Swap elements
         memcpy(tmp_item, &a[left * item_size], item_size);
         memcpy(&a[left * item_size], &a[right * item_size], item_size);
         memcpy(&a[right * item_size], tmp_item, item_size);
      }
   }
   // right is final position for the pivot
   memcpy(tmp_item, pivot_item, item_size);
   memcpy(&a[low * item_size], &a[right * item_size], item_size);
   memcpy(&a[right * item_size], tmp_item, item_size);

   // low -> right-1 AND right+1 -> high

   if((right-1) > low)
      partition(a, low, right-1);

   if(high > (right+1))
      partition(a, right+1, high);

   return right;
}

void qsort(void *array, int count, int size, int cf(void *a, void *b))
{
   cmp_func = cf;
   item_size = size;
   tmp_item = malloc(size);
   partition((char *)array, 0, count-1);
   free(tmp_item);
}

#36077 - Celeryface - Mon Feb 14, 2005 9:46 pm

Would a heapsort work well on the GBA?

http://en.wikipedia.org/wiki/Heapsort

#36080 - tepples - Mon Feb 14, 2005 10:06 pm

Yes. In theory, best-first search algorithms such as A* just need a selection, not a sort, so you could use heapsort to sort the elements at first and then later, as an optimization, use the binary heap code you already have as a priority queue.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#36081 - Celeryface - Mon Feb 14, 2005 10:10 pm

tepples wrote:
Yes. In theory, best-first search algorithms such as A* just need a selection, not a sort, so you could use heapsort to sort the elements at first and then later, as an optimization, use the binary heap code you already have as a priority queue.


Have you seen any implementations in C for the binary heap?

#36106 - Miked0801 - Tue Feb 15, 2005 2:09 am

Shell sort is my current favorite - but only because I wrote a fast ARM friendly version :)