java中mergesort函数怎么用,由mergeSort引发的一些思考
重新梳理一下歸并排序以及一些相關(guān)的東西。
對于歸并排序大家如果需要回憶下是個什么東西的話,可以點擊這個鏈接,里面有各種排序的動畫演示以及講解,比我再用文字贅述一遍要好得多,功能相當強大。
先給出歸并排序的js代碼實現(xiàn):
function mergeSort(arr, l, r) {
if (l === r) {
return;
}
let mid = Math.floor((r + l) / 2);
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
function merge(arr, l, mid, r) {
let leftIndex = l;
let rightIndex = mid + 1;
let helpArr = [];
while(leftIndex <= mid && rightIndex <= r) {
let leftItem = arr[leftIndex];
let rightItem = arr[rightIndex];
if (leftItem < rightItem) {
helpArr.push(leftItem);
leftIndex++;
} else {
helpArr.push(rightItem);
rightIndex++;
}
}
// 這倆循環(huán)只會進去一個,因為經(jīng)過上面的比較,要么左邊部分走完了,要么右邊部分走完了
while(leftIndex <= mid) {
helpArr.push(arr[leftIndex]);
leftIndex++;
}
while(rightIndex <= r) {
helpArr.push(arr[rightIndex]);
rightIndex++;
}
for (let index = 0; index < helpArr.length; index++) {
arr[l] = helpArr[index];
l++;
}
}
如何估計歸并排序的時間復(fù)雜度呢?
由于上面采用了遞歸寫法,我們使用master公式對遞歸進行時間復(fù)雜度估算,以下是公式詳情。
T(n) = a*T(n/b) + O(n^d)
(1)、log(b, a) > d => 復(fù)雜度為O(n^log(b, a))
(2)、log(b, a) = d => 復(fù)雜度為O(n^d*logn)
(3)、log(b, a) < d => 復(fù)雜度為O(n^d)
a代表遞歸的次數(shù),由于在mergeSort中調(diào)用了兩次mergeSort,所以歸并排序中a = 2。
b代表樣本量被劃分幾份,由于我們對樣本量是一分為二將數(shù)組分為left和right部分,所以歸并排序中b = 2。
O(n^d)代表其他操作的時間復(fù)雜度,所以在歸并排序中主要是merge這個函數(shù),相當于是執(zhí)行了一次數(shù)組遍歷,則為O(n)。
a = 2,b = 2,d = 1根據(jù)master公式,復(fù)雜度為nlogn。
我們知道冒泡排序、選擇排序、插入排序的時間復(fù)雜度都是O(n^2),當樣本量比較大的時候,n^2比之nlogn差了可不是一星半點。這是為什么呢?因為在其他三種排序中,會浪費元素之間的比較,比如冒泡排序冒泡比較一輪只定位了一個元素,下一輪冒泡又只定位一個元素,會浪費元素之間的相互比較;而歸并排序通過分治,由小到大進行比較合并的過程中,上一次比較合并的元素不會再次發(fā)生比較,有序的區(qū)域成規(guī)模增長,這樣就不會浪費比較,節(jié)省了時間。
由歸并排序引入數(shù)組小和問題和數(shù)組逆序?qū)栴}。
根據(jù)小和的題目要求,我們思考一下可以發(fā)現(xiàn),在歸并排序過程中,left和right部分進行比較合并的時候,其實就可以找到左邊部分比右邊部分小的數(shù),意思就是說我們可以很方便的在merge這個函數(shù)執(zhí)行過程中來計算數(shù)組的小和且會快很多,因為合并的時候左右兩遍都是有序的,如果一個數(shù)比右邊的第一個數(shù)字小,我們可以得知這個數(shù)字肯定比右邊全部的數(shù)字都小。
舉個例子,比如left = [1,2,3],right = [4,5,6],1小于4,說明右邊三個數(shù)都比1大,假如說小和等于sum,那么sum就要加1 * 3。
代碼實現(xiàn)一下小和:
function smallSum(arr) {
if (!arr || arr.length < 2) {
return 0;
}
return mergeSort(arr, 0, arr.length - 1);
}
function mergeSort(arr, l, r) {
if (l === r) {
return 0;
}
let mid = Math.floor((l + r)/2);
return mergeSort(arr, l, mid)
+ mergeSort(arr, mid + 1, r)
+ merge(arr, l, mid, r)
}
function merge(arr, l, mid, r) {
let leftIndex = l;
let rightIndex = mid + 1;
let helpArr = [];
let sum = 0;
while(leftIndex <= mid && rightIndex <= r) {
let leftItem = arr[leftIndex];
let rightItem = arr[rightIndex];
if (leftItem < rightItem) {
/**相對于歸并排序增加的部分**/
let tempSum = (r - rightIndex + 1) * leftItem
sum += tempSum;
/***************************/
helpArr.push(leftItem);
leftIndex++;
} else {
helpArr.push(rightItem);
rightIndex++;
}
}
/**這部分和歸并排序merge函數(shù)一樣**/
return sum;
}
對于小和都知道如何使用歸并排序進行求解之后,逆序?qū)ζ鋵嵑托『褪且粯拥?#xff0c;只是反過來了而已,以下直接貼出代碼。
function inversePairs(arr) {
if (!arr || arr.length < 2) {
return [];
}
return mergeSort(arr, 0, arr.length - 1);
}
function mergeSort(arr, l, r) {
if (l === r) {
return [];
}
let mid = Math.floor((l + r)/2);
return [
...mergeSort(arr, l, mid),
...mergeSort(arr, mid + 1, r),
...merge(arr, l, mid, r)
];
}
function merge(arr, l, mid, r) {
let leftIndex = l;
let rightIndex = mid + 1;
let helpArr = [];
let res = [];
while(leftIndex <= mid && rightIndex <= r) {
let leftItem = arr[leftIndex];
let rightItem = arr[rightIndex];
if (leftItem < rightItem) {
helpArr.push(leftItem);
leftIndex++;
} else {
/**相對于歸并排序增加的部分**/
res.push([leftItem, rightItem]);
/***************************/
helpArr.push(rightItem);
rightIndex++;
}
}
/**這部分和歸并排序merge函數(shù)一樣**/
return res;
}
以上是對歸并排序這部分內(nèi)容進行的一些回顧和總結(jié),希望能加深自己對它的理解,能在其他更多的地方將其運用上;如果有不正確的地方,大家可以踴躍指出,我將及時改正。
總結(jié)
以上是生活随笔為你收集整理的java中mergesort函数怎么用,由mergeSort引发的一些思考的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle -00257
- 下一篇: sql连接类型