經典算法應用之一----歸并排序(微軟筆試題)

首先來看看原題

微軟2010年筆試題
在一個排列中,如果一對數的前后位置與大小順序相反,即前面的數大于后面的數,那么它們就稱為一個逆序數對。一個排列中逆序的總數就稱為這個排列的逆序數。如{2,4,3,1}中,2和1,4和3,4和1,3和1是逆序數對,因此整個數組的逆序數對個數為4,現在給定一數組,要求統計出該數組的逆序數對個數。

計算數列的逆序數對個數最簡單的方便就最從前向后依次統計每個數字與它后面的數字是否能組成逆序數對。代碼如下:

#include <stdio.h>  
int main()  
{      
    const int MAXN = 8;  
    int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3};  
      
    int nCount = 0;  
    int i, j;  
    for (i = 0; i < MAXN; i++)  
        for (j = i + 1; j < MAXN; j++)  
            if (a[i] > a[j])  
                nCount++;  
  
    printf("逆序數對為: %d\n", nCount);  
}  

運行結果如下:

這種方法用到了雙循環,時間復雜度為O(N^2),是一個不太優雅的方法。因此我們嘗試用其它方法來解決。

在《經典算法系列之五歸并排序的實現》中觀察歸并排序——合并數列(1,3,5)與(2,4)的時候:
1.先取出前面數列中的1。
2.然后取出后面數列中的2,明顯!這個2和前面的3,5都可以組成逆序數對即3和2,5和2都是逆序數對。
3.然后取出前面數列中的3。
4.然后取出后面數列中的4,同理,可知這個4和前面數列中的5可以組成一個逆序數對。
這樣就完成了逆序數對的統計,歸并排序的時間復雜度是O(N * LogN),因此這種從歸并排序到數列的逆序數對的解法的時間復雜度同樣是O(N * LogN),下面給出代碼:

//從歸并排序到數列的逆序數對  
#include <stdio.h> 
int g_nCount;  
void mergearray(int a[], int first, int mid, int last, int temp[])  
{  
    int i = first, j = mid + 1;  
    int m = mid,   n = last;  
    int k = 0;  
  
    while (i <= m && j <= n) //a[i] 前面的數  a[j] 后面的數  
    {  
        if (a[i] < a[j])  
            temp[k++] = a[i++];  
        else  
        {  
            temp[k++] = a[j++];  
            //a[j]和前面每一個數都能組成逆序數對  
            g_nCount += m - i + 1;  
        }  
    }  
  
    while (i <= m)  
        temp[k++] = a[i++];  
  
    while (j <= n)  
        temp[k++] = a[j++];  
  
    for (i = 0; i < k; i++)  
        a[first + i] = temp[i];  
}  
void mergesort(int a[], int first, int last, int temp[])  
{  
    if (first < last)  
    {  
        int mid = (first + last) / 2;  
        mergesort(a, first, mid, temp);    //左邊有序  
        mergesort(a, mid + 1, last, temp); //右邊有序  
        mergearray(a, first, mid, last, temp); //再將二個有序數列合并  
    }  
}  
  
bool MergeSort(int a[], int n)  
{  
    int *p = new int[n];  
    if (p == NULL)  
        return false;  
    mergesort(a, 0, n - 1, p);  
    return true;  
}  
  
int main()  
{  
    printf("     從歸并排序到數列的逆序數對 \n");          
  
    const int MAXN = 8;  
    int a[MAXN] = {1, 7, 2, 9, 6, 4, 5, 3};  
  
    g_nCount = 0;  
    MergeSort(a, MAXN);  
    printf("逆序數對為: %d\n", g_nCount);  
    return 0;  
}  

運行結果:


推薦閱讀:
經典算法應用之一----歸并排序(微軟筆試題)
經典算法應用之二----基數排序(google筆試題)
經典算法應用之三----應用二中題目的升華
經典算法應用之四(上)---基本位操作之算法篇
經典算法應用之四(中)---基本位操作之算法篇
經典算法應用之四(下)---百度面試題
經典算法應用之五---隨機生成和為S的N個正整數
經典算法應用之六---過橋問題和過河問題
經典算法應用之七----10億數據中取最大的100個數據

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一. 寫在前面 要學習算法,“排序”是一個回避不了的重要話題,在分析完并查集算法和常用數據結構之后,今天我們終于可...
    Leesper閱讀 2,555評論 0 40
  • 本文主要整理了九種經典的內部排序算法。 1.冒泡排序 原理: 冒泡排序是一種簡單的排序算法。它重復地走訪過要排序的...
    愛聽故事的人想會講故事閱讀 1,208評論 0 2
  • Ba la la la ~ 讀者朋友們,你們好啊,又到了冷鋒時間,話不多說,發車! 1.冒泡排序(Bub...
    王飽飽閱讀 1,816評論 0 7
  • 昨夜下起了一場瓢潑大雨,雨幕被風吹得不斷改變傾注方向,忽而如矢撲來使躲閃不及的路人衣衫盡濕,引起男生宿舍樓的一陣陣...
    邀月成三閱讀 437評論 0 0
  • 本周的主題有點讓人振奮。之前根本就沒有這個方面的思考,那怕是去了解都沒有過。很多事情它就是客觀的存在在某個地方,你...
    RexsonXie閱讀 226評論 0 0