1. 程式人生 > >基數排序及其並行化

基數排序及其並行化

temp 基於 tac require print implement 處理 lse tina

基數排序是比較適合並行化的排序算法之一,因為它不需要他的元素和數組當中的其他元素去進行一一對比來決定放的位置。另外還有比較適合並行化的就是雙調排序。

基數排序原理

以從小到大,一次排序只考慮一位為例。基數排序一般從數據的最低有效位(LSB)開始進行排序,即考察所有的數據的當前位,其當前位為0的數據放到前面,為1的放到後面,當前位具有相同值的就保持上一步的相對位置。處理好之後,處理更高的一位。如此叠代,直至處理完所有位。所有位一般即意味著當前所有數據的最大值的最高位。

基數排序的並行化

網絡上有一些典型的錯誤的並行化,或者說並不是真正高效的利用基數排序特點的並行化。比如這個,這個實現的總體思路就是把數據分段,每段分別用基數排序排好,然後在每次從所有排好序的段中取最小值來合並結果。雖然這樣的處理也確實是並行化,但是這樣的處理方式並沒有有效利用基數排序的特點,這樣的處理方式可以說把任意一種排序算法替代每段排序時用到的基數排序都是適用的。
在這個PPT中介紹了基數排序的並行化,其並行化的核心就是計算出每個線程所處理數據中,當前位為0和1的數據,其offset

分別為多少,然後基於此計算出本線程中的每個數據在本次叠代中,應該放在整個數據中的哪個位置。

技術分享圖片
技術分享圖片

SOF上較好的一個回答。在這裏有一個較好的使用pthread實現的版本,其核心函數,每個線程的處理代碼如下:

/* Individual thread part of radix sort. */
void radix_sort_thread (unsigned *val, /* Array of values. */
            unsigned *tmp,           /* Temp array. */
            int start, int n,        /* Portion of array. */
            int *nzeros, int *nones, /* Counters. */
            int thread_index,        /* My thread index. */
            int t)                   /* Number of theads. */
{
  /* THIS ROUTINE WILL REQUIRE SOME SYNCHRONIZATION. */
  /* MAYBE A CALL TO barrier() or TWO. */

  unsigned *src, *dest;
  int bit_pos;
  int index0, index1;
  int i;
  printf("###### Got in main function, thread %d\n", thread_index);

  /* Initialize source and destination. */
  src = val;
  dest = tmp;

  /* For each bit... */
  for ( bit_pos = 0; bit_pos < BITS; bit_pos++ ) {

    /* Count elements with 0 in bit_pos. */
    nzeros[thread_index] = 0;
    for ( i = start; i < start + n; i++ ) {
      if ( ((src[i] >> bit_pos) & 1) == 0 ) {
        nzeros[thread_index]++;         
      } 
    }
    nones[thread_index] = n - nzeros[thread_index];
    
    /* Ensure all threads have reached this point, and then let continue */
    pthread_barrier_wait(&barrier);

    /* Get starting indices. */
    index0 = 0;
    index1 = 0;
    for ( i = 0; i < thread_index; i++ ) {
      index0 += nzeros[i];
      index1 += nones[i];
    }
    index1 += index0;   //位為1的數據要放到位為0的數據後面
    for ( ; i < t; i++ ) {
      index1 += nzeros[i];
    }
    
    /* Ensure all threads have reached this point, and then let continue */
    pthread_barrier_wait(&barrier);

    /* Move values to correct position. */
    for ( i = start; i < start + n; i++ ) {
      if ( ((src[i] >> bit_pos) & 1) == 0 ) {
        dest[index0++] = src[i];        
      } else {
        dest[index1++] = src[i];        
      }
    }
    
    /* Ensure all threads have reached this point, and then let continue */
    pthread_barrier_wait(&barrier);
    
    /* Swap arrays. */
    tmp = src;
    src = dest;
    dest = tmp;
  }
  printf ("\n====== Printing nzeros array of thread %d\n\n", thread_index);
  print_array (nzeros, n);
  printf ("\n====== Printing nones array of thread %d\n\n", thread_index);
  print_array (nones, n);
  // printf ("\n====== Printing val array of thread %d\n\n", thread_index);
  // print_array (val, n);
  // printf ("\n====== Printing temp array of thread %d\n\n", thread_index);
  // print_array (dest, n);
}

基數排序及其並行化