歸併排序演算法,想必諸位都十分熟悉。其基本思想也就是分治。整個排序過程分成兩部分--分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之。
分的過程很容易看懂,即將乙個大的陣列拆分成若干個小的陣列,減少問題規模。
public static void mergesort(int arr)
/**對arr陣列的[left...right]進行歸併排序
**/private static void sort(int arr, int left, int right, int temp)
} //將[left...mid]和[mid+1...right]進行合併
private static void merge(int arr, int left, int mid,int right, int temp) else
} //未被合併的陣列元素直接放到後面
while(i <= mid) temp[t++] = arr[i++];
while(j <= right) temp[t++] = arr[j++];
//將已經排序的temp陣列中的元素複製到arr陣列中
t = 0;
while(left <= right) arr[left++] = temp[t++];
}
劍指 offer 51. 陣列中的逆序對
那麼求逆序對和歸併排序又有什麼關係呢?關鍵就在於「歸併」當中「並」的過程。我們通過乙個例項來看看。
首先原始陣列為[2,3,5,7,1,4,6,8]
。在合併時比較i所指向的元素2以及j所指向的元素1發現 1 <2則將元素1放到第乙個位置。進而我們發現元素1
與前邊d的2,3,5,7分別構成了逆序對。逆序數為4。
然後j後移,發現2<4,此時可以直接將2放到第二個位置,此時並未構成逆序對。
i後移,發現3<4,直接將3放到第三個位置,同樣未構成逆序對。
然後i繼續後移,發現4<5,將4放到第四個位置上,並且此時4和前邊的5,7構成了逆序對。
分析到這裡我們就可以發現乙個規律,就是在合併時,當後乙個陣列索引j所指向的元素大於前乙個陣列索引i所指向的元素時,會構成逆序對,且逆序對的個數為前乙個陣列未被排序的元素個數即mid - i +1個。
重複做以上操作便可以得到下邊的結果:
/**
使用歸併排序思想來解決逆序對問題
**/class solution
/**計算num陣列[left .. right]逆序對的個數
**/private int split(int nums, int left, int right, int temp)
return 0;
}/**
計算合併nums陣列[left...mid]以及[mid+1 .. right]過程中產生的逆序對個數
**/private int merge(int nums, int left, int mid, int right, int temp) else
}while(i <= mid)
while(j <= right)
//將已經排序好的陣列元素複製到nums陣列中
t = 0;
while(left <= right)
return res;
}}
歸併排序本質上乙個分治思想的一種體現,通過將大問題進行拆分,分成若干小問題分別求解。然後將求解結果進行合併,得到乙個最終解,進而解決該問題。 用歸併排序演算法求逆序對數量
給定乙個長度為n的整數數列,請你計算數列中的逆序對的數量。逆序對的定義如下 對於數列的第 i 個和第 j 個元素,如果滿足 i j 且 a i a j 則其為乙個逆序對 否則不是。輸入格式 第一行包含整數n,表示數列的長度。第二行包含 n 個整數,表示整個數列。輸出格式 輸出乙個整數,表示逆序對的個...
歸併排序求逆序對數
參考部落格 歸併排序求逆序對數 include include include includeusing namespace std 歸併排序是借助乙個輔助陣列來進行排序 int ans 0 void merge sort int a,int l,int r,int t a是原陣列,t是輔助陣列 i...
歸併排序求解逆序對數
定義 逆序對就是對於ia j 這樣的數對在序列中的個數。求解方法 歸併排序是採用分治的思想劃分數列,然後將兩路有序的數列合併。通過劃分和合併的遞迴呼叫來完成排序。在合併的過程中,兩個數列中的元素的相對位置不會發生改變 這裡只是前後關係 而且如果後乙個數列b中某個元素b在需要先放入 優先於前乙個數列a...