求出一列數中的“逆序對”

求出一列數中的“逆序對”的個數;所謂“逆序對”就是指數的大小與其在序列中的順序相反的一對數;例 如:<3,4,2,1,3>中“逆序對”有<3,2>,<3,1>,<4,2>,<4,1>,<4,3>這5個;要求時間複雜度爲O(nlogn);

#include <stdio.h>

void PrintTheRel(int i, int j);
void Sort(int Array[100], int end);
void GetTheRel(int Front[50],int len1, int Back[50], int len2);
void GetResult(int bundary, int source[100], int low, int high);

void main()
{
 int Source[100];
 int temp, length, times;
 
 printf("Please enter the length:");
 scanf("%d", &length);
 printf("/nPlease enter the elements:");
 for (temp=0; temp < length; temp++)
  scanf("%d", &Source[temp]);
 
 times = (int)(length/2);// 求界限

 GetResult(times, Source, 0, length-1);
}


///////////////////////////////////////////////////////////////////////
//
// 函數名       : GetResult
// 功能描述     : 通過遞歸算法實現數列逆序列的求解
// 參數         : int bundary 二分法中涉及的分界點
// 參數         : int source[100] 一個待求序列
// 參數         : int low 序列的開始座標
// 參數         : int high 序列的最後座標
// 返回值       : void
//
///////////////////////////////////////////////////////////////////////
void GetResult(int bundary, int source[100], int low, int high)
{
 int i,k=0;
 int Front[50], Back[50];
 
 if(high-low < 1) /*假如只有一個數就彈出遞歸堆棧                  */
  return;
 else
 {
  for(i=low; i < bundary; i++)
   Front[k++] = source[i];/*得到一個前一段的臨時的數組      */
  k=0;
  for(i=bundary; i <= high; i++)
   Back[k++] = source[i]; /*得到一個後一段的臨時的數組      */
  Sort(Front, bundary-1-low);/*對前一段進行排序                */
  Sort(Back, high-bundary);  /*對後一段進行排序                */
  
  // 得到一組逆序對,這是求已經分好界的兩邊界的逆序對關係
  GetTheRel(Front, bundary-low, Back, high - bundary + 1);
  // 遞歸求左半部分
  GetResult((int)((bundary-low +1) / 2)+low, source, low, bundary-1);
  // 遞歸求右半部分
  GetResult((int)((high-bundary+1) / 2)+bundary, source, bundary, high);  
 }
}


///////////////////////////////////////////////////////////////////////
//
// 函數名       : GetTheRel
// 功能描述     : 得到已經分成兩半時的逆序對
// 參數         : int Front[50] 前一部分的己排序序列
// 參數         : int len1 前一個序列的長度
// 參數         : int Back[50]  後一部分的已排序序列
// 參數         : int len2 後一個序列的長度
// 返回值       : void
//
///////////////////////////////////////////////////////////////////////
void GetTheRel(int Front[50], int len1, int Back[50], int len2)
{
 int i=0, j=0, k;
 // 通過一次掃描可以將兩個部分的逆序對全找出來
 while ((i<len1) && (j <len2))
 {
  while (Front[i] > Back[j] && (i<len1) && (j <len2))
  {
   // 因爲己經按遞增排好序的所以將前半部分i下面的全部輸出
   for(k=i; k<len1;k++)
    PrintTheRel(Front[k], Back[j]);
   j++;/*當輸出之後,後半部分指針加一                       */
  }
  i++; /*前半部分沒有比當前後半部分的值大將加一             */
 }
}

///////////////////////////////////////////////////////////////////////
//
// 函數名       : Sort
// 功能描述     : 現在只是爲了方便採用的是冒泡排序,可以採用O(nlogn)的算法。
// 參數         : int Array[100] 需要排序的數組
// 參數         : int end 數組默認從0開始,到end結束
// 返回值       : void
//
///////////////////////////////////////////////////////////////////////
void Sort(int Array[100], int end)
{
 int i, j, temp;

 // 自己認爲這樣的冒泡寫法最清晰
 for (i=end; i >0; i--)
  for (j=0; j < i; j++)
              if (Array[j] > Array[j+1])
     {
                  temp       = Array[j];
                  Array[j]   = Array[j+1];
                  Array[j+1] = temp;
     }
}


///////////////////////////////////////////////////////////////////////
//
// 函數名       : PrintTheRel
// 功能描述     : 格式打印
// 參數         : int i 參數1
// 參數         : int j 參數2
// 返回值       : void
//
///////////////////////////////////////////////////////////////////////
void PrintTheRel(int i, int j)
{
 printf("<%d, %d>/n", i, j);
}

輸入輸出舉例:

Please enter the length:10

Please enter the elements:9 8 7 6 5 4 3 2 1 0
<5, 0>
<6, 0>
<7, 0>
<8, 0>
<9, 0>
<5, 1>
<6, 1>
<7, 1>
<8, 1>
<9, 1>
<5, 2>
<6, 2>
<7, 2>
<8, 2>
<9, 2>
<5, 3>
<6, 3>
<7, 3>
<8, 3>
<9, 3>
<5, 4>
<6, 4>
<7, 4>
<8, 4>
<9, 4>
<7, 5>
<8, 5>
<9, 5>
<7, 6>
<8, 6>
<9, 6>
<8, 7>
<9, 7>
<9, 8>
<6, 5>
<3, 0>
<4, 0>
<3, 1>
<4, 1>
<3, 2>
<4, 2>
<4, 3>
<2, 0>
<2, 1>
<1, 0>
Press any key to continue

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章