最近學習逆序對,發現竟然要學習歸併排序,於是只好學了一下(之前一直用c++ stl的sort函式),發現思想和線段樹竟然驚人的相似,先放一張圖你們就懂了:
怎麼樣,是不是發現這就是一棵線段樹!其實歸併排序利用了二分的思想,即分而治之。
歸併排序是一種穩定的方法,時間複雜度:o(nlogn),空間複雜度:o(n)
是不是很優秀啊,現在我們就來講解一下演算法的流程:
void gb_sort(int l,int r)
1.不斷二分區間,直到將他們分到只有兩個數後在返回時不斷歸併2.從底向上歸併,由此我們才可以將乙個個排序好的小區間歸併成大區間
void hb_sort(int l,int mid,int r)
else
}while(left <= mid)
while(right <= r)
while(!que.empty())
}
假如我們要合併的兩個序列為1,5,15,16和4,8,9,10。
然後將數值小的下標加一,往後移。就便成了
這裡4比5小,所以4入隊,一直重複操作
直到完成,而這時還剩下兩個,再將他們入隊
然後再將佇列裡的數拷貝回原陣列
由於我們每次要合併的區間由小到大,即從底向上合併,而且合併的區間長度大於2,也就是下圖的紅色區間:
3.這樣我們就得到了乙個有序的區間,之後的每次合併都這樣操作,每一層合併為o(n),共有logn層,所以總的時間複雜度為
o(nlogn)
先看一道題:逆序對
在本題中我們要求的是當ia[j]的個數,不難想到歸併排序,而且只需在原來的**上做一點小小的改動,
我們只需要記錄每次後半段的數入隊時,前半段有多少個數比他大,用乙個ans統計就好了。
是不是很妙蛙!
下面我們直接來看**:
#include #include #include using namespace std;
int n,ans;
int a[40005];
queueque;
void hb_sort(int l,int mid,int r)
else
}while(left <= mid)
while(right <= r)
while(!que.empty())}
void gb_sort(int l,int r)
int main()
歸併排序與逆序對
歸併問題按照分治三步法進行介紹 劃分問題 把序列分成元素個數盡量相等的兩半 遞迴求解 把兩半元素分別排序 合併問題 把兩個有序表合併成乙個 借鑑乙個部落格的圖 排序演算法 四 之歸併排序 可以看到這種結構很像一棵完全二叉樹,本文的歸併排序我們採用遞迴去實現 也可採用迭代的方式去實現 分階段可以理解為...
歸併排序與逆序對
題目描述 給定你乙個長度為n的整數數列。請你使用歸併排序對這個數列按照從小到大進行排序。並將排好序的數列按順序輸出。輸入格式 輸入共兩行,第一行包含整數 n。第二行包含 n 個整數 所有整數均在1 109範圍內 表示整個數列。輸出格式 輸出共一行,包含 n 個整數,表示排好序的數列。資料範圍 1 n...
歸併排序與逆序對
歸併排序在於把序列拆分再合併起來,使用分治法來實現,這就意味這要構造遞迴演算法 將兩個列表是s1,s2按順序融合為乙個列表s,s為原列表 j和i就相當於兩個指向的位置,i指s1,j指s2 i j 0while i j len s j len s2 時說明s2走完了,或者s1沒走完並且s1中該位置是最...