1. 程式人生 > >經典排序演算法以及負載平衡下的平行歸併排序Parallel Merge Sort with Load Balancing

經典排序演算法以及負載平衡下的平行歸併排序Parallel Merge Sort with Load Balancing

常見經典排序演算法有:氣泡排序,快速排序,插入排序,選擇排序,歸併排序、希爾排序。
氣泡排序就不介紹了,首先是快速排序QuickSort:
過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列。

如資料為  6   2   7  3  8  9
first:
furst -1
first -a:3 2 7 6 8 9(從後往前,找比6(第一個資料)小的數交換)
first -b:3 2 6 7 8 9(再從前往後(從2開始),找比6大的資料
first
...一次按first-1來先找比6小,再找比6大,直至結束。 first-result3 2 6 7 8 9 second: 以 6為界限,劃分兩部分 得 3 27 8 9 先計算 3 2參照first; 再 7 8 9,同樣操作。

插入即表示將一個新的資料插入到一個有序陣列中,並繼續保持有序。

從第二個數字開始,假設前面的已經排好序,該數為帶插入前面有序的數字中,接著第三個,插入到前面序列
好了,快排就是這樣的,下面是插入排序

5060,71,49,11,24,3,66  k=60(2)

50,6071,4911,24,66
next 插入
k=71(3)
50,6071,49
,11,24,3,66) k=49(4)(下一個) 50,60,49,71,11,24,3,69 50,49,60,71,.. 49,50,60,71,11,24,3 k=11(第五個數) ... ...

選擇排序

每次找出最小數,從i=1 to n
example 3(start) 5 1 2 7 6
i=0,從j=1 to n找最小到第一個交換
1 5(start)  3 2 7 6
1 2 3 5 7 6
....

希爾排序

```
           9 1 2 5 7 4 8 6 3 6
first組合: 9         4 (比較交換)
             1         8
               2         6
                 5         3
                   7         6
組合(9[index1]
4[index[5]),(1[2],8[6]),(2[3],6[7]),... 排好序列歸位: 4 1 2 3 6 9 8 6 5 7 再組合: 4 2 6 8 5 1 3 9 6 7 排序歸位 ...
           that's all!

歸併排序,簡單來說就是分治法,分治法被廣泛用於大資料,雲端計算中,比如hadoop的mapreduce很大一部分來源於此。14年本人看的第一篇論文就是並行歸併排序演算法,附上理解
Title:Parallel Merge Sort with Load Balancing
作者:Minsoo Jeon and Dongseung Kim
傳統的並行歸併排序介紹:
分解:將原問題分解成一系列子問題
解決:遞迴的解決各子問題
合併:將子問題的解合併成原問題的解
演算法思想:
1.將N個數據(平)分給P個處理器
2.P個處理器對每一組資料進行排序
3.把每兩個處理器排好的序列合併再排序,此時處於工作狀態的處理器數量減半
4.重複第3步,直到只剩下最後一個處理器處理所有資料,排序完畢。

begin
h :=P
1. forall 0 [ i [ P−1
     Pi sorts a list of N/P keys locally.
2. for j=0 to (log P)−1 do
        forall 0 [ i [ h−1
           if (i < h/2) then
              2.1. Pi receives N/h keys from Pi+h/2
              2.2. Pi merges two lists of N/h keys into a sorted list of 2N/h
          else
          2.3. Pi sends its list to Pi−h/2
      h :=h/2
end

/*
P:處理器數量
Pi:第i個處理器
h:處於工作狀態的處理器數量

*/

傳統平行歸併演算法演算法示意圖:

這裡寫圖片描述

for example:

原始資料:14,1,18,2,16,4,7,21
STEP1:分給兩個處理器P0和P1:
P0:14,1,18,2                             P1:16,4,7,21
     Step2:P0和P1對兩組資料做快速排序:
P0:1, 2, 14,   18                               P1:4,7,16,21
     Step3:將P0裡的最小數與P1的最小數比較,P0裡1比P1裡的4小,然後進行下一步,繼續將P0的第二個數與P1的4比較,將P1的最小數在P0裡做插入排序,P1插入到P0的2和14之間,此時有:
 P0:1,2,4,14,18                               P1:7,16,21
     Step4:將P1的7從P0的4往後插入排序,以此遞迴,最後
    P0:1,2,4,7,14,16,18,21
   排序完畢,P1為空。      

code:

/*p[i]為第i塊處理器,建議開啟多執行緒模仿或者多處理器程式設計,本人只是做了實現,程式碼提供參考*/
#include<stdlib.h>
void sort1(int n,int a[])
{int i,j,key;
for(i=0;i<n;i++)
 for(j=i+1;j<n;j++)
    if(a[i]>a[j])
    { key=a[i];
      a[i]=a[j];
      a[j]=key;
    }
}
void sort2(int m,int a[],int b[])
{int i,j=0,k,s=m;
a[4]=65535;
b[4]=65535;
for(i=0;i<m;i++)
{ while(b[i]>a[j])
 {
 j++;
 }
 {{s++;
     for(k=s-1;k>j;k--)
         a[k]=a[k-1];

 }
 a[j]=b[i];}

}
}
void main()
{
int p[8];
int p0[8];
int p1[8];
int i;
printf("please input 8 keys:\n");
for(i=0;i<8;i++)
scanf("%d",&p[i]);
for(i=0;i<4;i++)
{p0[i]=p[i];
p1[i]=p[i+4];}
sort1(4,p0);
sort1(4,p1);
printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
sort2(5,p0,p1);
printf("\nthe data sorted stores in P0:\n");
for(i=0;i<8;i++)
printf("%d ",p0[i]);

}
 平行歸併演算法在處理大量資料是非常有效,但是傳統的歸併演算法(分治法)效能很差,因為每次合併處理時,處理器就會減少一半,加重了每個處理器所處理的資料長度,合併到最後時,只有一個處理器處理所有的資料。
 相比其他快速法而言,它有利於處理大量資料,但是該傳統演算法越往後進行,就有越來越多的處理器處於閒置狀態,因此歸併排序演算法必須平行化處理,才能發揮出最大優勢,本文推薦了一種負載平衡下的並行歸併排序演算法,該演算法在整個計算過程中,所有處理器均參與計算。在每一個階段都分配資料到每一個處理器上。這樣效能就大大提高。

*下面就是介紹我們強大的負載平衡下的平行歸併演算法~~
演算法思想:
1.將N個帶排序資料(平)分給P個處理器;
2.P個處理器同時對P組資料進行排序(從小到大);
3.將每兩個相鄰處理器做比較,將第一個處理器的最大數(最右邊數)與第二個處理器的最小數(最左邊數)作比較,若第一個處理器的最大數小於第二個處理器的最小數,則這兩個處理器的資料排序完成,反之,則交換邊界數,兩處理器又再次重新排序;
4.依次做遞迴,直到這兩組資料完全排序完成;
5.這時P個處理器在使用,待排序陣列變成P/2個數組;
6.依次遞迴進行歸併,把待排序陣列歸併,處理器並行適應,每次待排序陣列減半,直到結束為止。*
這裡寫圖片描述

輸入原始資料:15,6,56,78,1,3,99,2
Step1:將資料平分給P0P1
P0:15,6,56,78                P1:1,3,99,2
Step2:P0,P1兩組處理器分別對兩組數排序,拍完後:
P0:6,15,56,78                P1:1,2,3,99
Step3:比較P0中最右邊數(最大數)與P1最左邊數(最小數),若P0最大數小於P1最小數,則排序完成,反之,交換兩邊界數
Step4:交換後
P0:6,15,56,1         P1:78,2,3,99
Step5:重複Step2,Step3,Step4,直到結束,得到
P0:1,2,3,6             P1:15,56,78,99
排序完畢,P0中數小於P1中數

Here is the code:

#include<stdlib.h>
void sort1(int n,int a[])
{int i,j,key;
for(i=0;i<n;i++)
 for(j=i+1;j<n;j++)
    if(a[i]>a[j])
    { key=a[i];
      a[i]=a[j];
      a[j]=key;
    }
}
void main()
{
int p[8];
int p0[4];
int p1[4];
int i,data1;
printf("please input 8 keys:\n");
for(i=0;i<8;i++)
scanf("%d",&p[i]);
for(i=0;i<4;i++)
{p0[i]=p[i];
p1[i]=p[i+4];}
sort1(4,p0);
sort1(4,p1);
printf("data in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
while(p0[3]>p1[0]){
   data1=p0[3];
   p0[3]=p1[0];
   p1[0]=data1;
   printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);
sort1(4,p0);
sort1(4,p1);
 printf("\ndata in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\ndata in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);


}
printf("\nthe data sorted stores in P0:\n");
for(i=0;i<4;i++)
printf("%d ",p0[i]);
printf("\nthe data sorted stores in P1:\n");
for(i=0;i<4;i++)
printf("%d ",p1[i]);

}
/*p[i]同樣是模擬第i塊處理器

*/

for example:

輸入原始資料:15,6,56,78,1,3,99,2
Step1:將資料平分給P0P1
P0:15,6,56,78                P1:1,3,99,2
Step2:P0,P1兩組處理器分別對兩組數排序,拍完後:
P0:6,15,56,78                P1:1,2,3,99
Step3:比較P0中最右邊數(最大數)與P1最左邊數(最小數),若P0最大數小於P1最小數,則排序完成,反之,交換兩邊界數
Step4:交換後
P0:6,15,56,1         P1:78,2,3,99
Step5:重複Step2,Step3,Step4,直到結束,得到
P0:1,2,3,6             P1:15,56,78,99
排序完畢,P0中數小於P1中數

該演算法經常用於分散式檔案系統‘大資料處理,並行高效能運算。