算法設計:合並排序與自底向上合並排序


在我們之前的算法設計課程中,我們學習了合並排序與自底向上合並排序算法,今天我們就來分析一下這個算法

合並算法

無論是合並排序還是自底向上合並排序,他的實現都基於一個重要的算法:合並算法(merge算法)。Merge算法實現的功能是將兩個數組合並成為一個數組,我們可以定義一個結果數組b,再分別定義兩個索引p1、p2,分別指向兩個數組的頭,將p1、p2指向的兩個數進行比較,並將較小的那一個放入數組b

Merge算法的偽碼如下:

merge(p, q, r, a[]):

  1. s←p; t←q+1; k←p
  2. while s≤q and t≤r
  3.     if a[s] ≤ a[t] then
  4.         b[k] ← a[s]
  5.           s ←s+1
  6. 6.           else
  7.           b[k]←a[t]
  8.           t←t+1
  9. 9.           end if
  10.     k←k+1
  11. 11.   end while
  12. if s=q+1 then b[k…r]←a[t…r]
  13. else b[k…r]←a[s…q]
  14. 14.   end if
  15. a[p…r]←b[p…r]

 

自底向上合並排序算法

自底向上合並算法顧名思義,就是從最底部開始,將數組元素兩兩合並,再將合並后的數組兩兩合並,直到重新合並成一個完整的數組。對於數組a = {9,4,5,2,1,7,4,6}的合並過程可以用如下圖來表示:

自底向上合並排序算法偽碼如下:

BottomSort(a[]):

  1. t←1
  2. while t<n
  3.     s←t; t←2s; i←0
  4.     while i+t≤n
  5.           merge(i+1, i+s, i+t, a)
  6.           i←i+t
  7. 7.           end while
  8.     if i+s<n then merge(i+1, i+s, n)
  9. 9.       end while

合並排序算法

合並排序算法與自底向上合並排序十分相似(廢話!),只不過與自底向上合並排序不同的是,合並排序是一個自頂向下的過程。我們可以將一整個數組拆分成兩個數組,將其中的一個數組再進行拆分,直到拆分成兩個單個元素,再將他們合並…重復此過程直到整個數組都重新合並完畢。

對於數組a[]={9,4,5,2,1,7,4,6}的合並排序可以用如下圖示表示:

其中頂端數組表示其獲得的輸入,底端數組表示其合並后的輸出

合並排序算法偽碼如下:

mergesort(low, high, a[]):

  1. if low<high then
  2.     mid←(low + high)/2
  3.     mergesort(low, mid, a)
  4.     mergesort(mid+1, high, a)
  5.     merge(low, mid, high, a)
  6. 6.       end if

兩個算法的完整代碼

自底向上合並排序(java):

 1 //自底向上合並排序
 2 public class BottomUpSort {
 3     public static void main(String args[])
 4     {
 5         int a[] = {9,4,5,2,1,7,4,6};
 6         bottomUpSort(a);
 7         for(int i=0;i<a.length;i++)
 8             System.out.print(a[i] + " ");
 9         System.out.println();
10     }
11     
12     public static void bottomUpSort(int a[])
13     {
14         int i, s, t = 1;
15         while(t < a.length-1)
16         {
17             s = t;
18             t = 2*s;
19             i = 0;
20             for(;i+t < a.length;i+=t)
21                 merge(i, i+s-1, i+t-1, a);    //自底向上進行排序
22             if(i+s-1 < a.length-1)    //判斷是否有落單元素
23                 merge(i, i+s-1, a.length-1, a);
24             
25         }
26     }
27     
28     public static void merge(int low, int mid, int high, int a[])
29     {
30         int b[] = new int[a.length];    //    建立轉存數組
31         int f = low, s = mid+1, p = low;
32         //f為第一個數組索引,s為第二個數組索引,p為b數組索引
33         while(f<=mid && s<=high)
34         {
35             //在兩個數組元素中值小的一方放入b數組
36             if(a[f] <= a[s])
37             {
38                 b[p] = a[f];
39                 f++;
40             }
41             else
42             {
43                 b[p] = a[s];
44                 s++;
45             }
46             p++;
47         }
48         
49         if(f == mid+1)    //若第一個數組中的元素全部存儲進去了,那么將第二個數組中的剩余元素全部放入b數組
50             for(;s <= high && p<=high;p++,s++)
51                 b[p] = a[s];
52         else //否則將第一個數組中的元素全部放入b數組
53             for(;f<=mid && p<=high;p++,f++)    
54                 b[p] = a[f];
55         
56         for(int i=low;i<=high;i++)
57             a[i] = b[i];
58     }
59 }

自底向上合並排序(c):

 1 #include<stdio.h>
 2 
 3 //數組合並函數
 4 void merge(int low, int mid, int high, int a[])
 5 {
 6     int b[50];    //定義轉存數組
 7     int f = low, s = mid + 1, p = low;
 8     //f表示第一個數組的索引,s表示第二個數組的索引,p表示b數組的索引
 9 
10     while (f <= mid && s <= high)
11     {
12         //將兩個數組中值小的一方存入數組b
13         if (a[f] <= a[s])
14         {
15             b[p] = a[f];
16             f++;
17         }
18         else
19         {
20             b[p] = a[s];
21             s++;
22         }
23         p++;
24     }
25     if (f == mid + 1)    //若第一個數組都存進了數組b,那么將第二個數組中的剩下元素全部存入
26         for (; s <= high; p++, s++)
27             b[p] = a[s];
28     else    //否則將第一個數組中的剩下元素全部存入
29         for (; f <= mid; p++, f++)
30             b[p] = a[f];
31 
32     for (int i = low; i <= high; i++)
33         a[i] = b[i];    //將合並后的數組轉存回a
34 }
35 
36 void BottomUpSort(int low, int high, int a[])
37 {
38     int t = 1, s, i;
39     int length = high + 1;
40     while (t < length-1)
41     {
42         s = t;
43         t = 2 * s;
44         i = 0;
45         for (; i + t <= length - 1; i+=t)    //自底向上進行合並
46             merge(i, i + s - 1, i + t - 1, a);
47         if (i + s-1 < length - 1)    //判斷是否有落單元素
48             merge(i, i + s - 1, length - 1, a);
49     }
50 }
51 
52 int main()
53 {
54     int a[] = { 9,4,5,2,1,7,4,6 };
55     int length = sizeof(a) / sizeof(a[0]);
56     for (int i = 0; i < length; i++)
57         printf("%d ", a[i]);
58     printf("\n");
59     BottomUpSort(0, length - 1, a);
60     for (int i = 0; i < length; i++)
61         printf("%d ", a[i]);
62     printf("\n");
63     return 0;
64 }

合並排序(java):

 1 //合並排序算法
 2 public class MergeSort {
 3     public static void main(String args[])
 4     {
 5         int a[] = {9,4,5,2,1,7,4,6};
 6         mergeSort(0, a.length-1, a);
 7         for(int i=0;i<a.length;i++)
 8             System.out.print(a[i] + " ");
 9         System.out.println();
10     }
11     
12     //合並排序
13     public static void mergeSort(int low, int high, int a[])
14     {
15         if(low < high)
16         {
17             int mid = (low + high)/2;
18             mergeSort(low, mid, a);
19             mergeSort(mid+1, high, a);
20             merge(low, mid, high, a);
21         }
22     }
23     
24     //合並兩個數組
25     public static void merge(int low, int mid, int high, int a[])
26     {
27         int b[] = new int[a.length];    //    建立轉存數組
28         int f = low, s = mid+1, p = low;
29         //f為第一個數組索引,s為第二個數組索引,p為b數組索引
30         while(f<=mid && s<=high)
31         {
32             //在兩個數組元素中值小的一方放入b數組
33             if(a[f] <= a[s])
34             {
35                 b[p] = a[f];
36                 f++;
37             }
38             else
39             {
40                 b[p] = a[s];
41                 s++;
42             }
43             p++;
44         }
45         
46         if(f == mid+1)    //若第一個數組中的元素全部存儲進去了,那么將第二個數組中的剩余元素全部放入b數組
47             for(;s <= high && p<=high;p++,s++)
48                 b[p] = a[s];
49         else //否則將第一個數組中的元素全部放入b數組
50             for(;f<=mid && p<=high;p++,f++)    
51                 b[p] = a[f];
52         
53         for(int i=low;i<=high;i++)
54             a[i] = b[i];
55     }
56 }

合並排序(c):

 1 #include<stdio.h>
 2 
 3 //數組合並函數
 4 void merge(int low, int mid, int high, int a[])
 5 {
 6     int b[50];    //定義轉存數組
 7     int f = low, s = mid + 1, p = low;
 8     //f表示第一個數組的索引,s表示第二個數組的索引,p表示b數組的索引
 9 
10     while (f <= mid && s <= high)
11     {
12         //將兩個數組中值小的一方存入數組b
13         if (a[f] <= a[s])
14         {
15             b[p] = a[f];
16             f++;
17         }
18         else
19         {
20             b[p] = a[s];
21             s++;
22         }
23         p++;
24     }
25     if (f == mid+1)    //若第一個數組都存進了數組b,那么將第二個數組中的剩下元素全部存入
26         for (; s <= high; p++, s++)
27             b[p] = a[s];
28     else    //否則將第一個數組中的剩下元素全部存入
29         for (; f <= mid; p++, f++)
30             b[p] = a[f];
31 
32     for (int i = low; i <= high; i++)
33         a[i] = b[i];    //將合並后的數組轉存回a
34 }
35 
36 //合並排序函數
37 void MergeSort(int low, int high, int a[])
38 {
39     if (low < high)
40     {
41         int mid = (low + high) / 2;
42         MergeSort(low, mid, a);    
43         MergeSort(mid + 1, high, a);    //從上到下合並數組
44         merge(low, mid, high, a);
45     }
46 }
47 
48 int main()
49 {
50     int a[] = { 9,4,5,2,1,7,4,6 };
51     int length = sizeof(a) / sizeof(a[0]);
52     for (int i = 0; i < length; i++)
53         printf("%d ", a[i]);
54     printf("\n");
55     MergeSort(0, length - 1, a);
56     for (int i = 0; i < length; i++)
57         printf("%d ", a[i]);
58     printf("\n");
59     return 0;
60 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM