乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      歸并排序

       waston 2019-02-12
      歸并排序介紹

      將兩個(gè)的有序數(shù)列合并成一個(gè)有序數(shù)列,我們稱之為"歸并"。歸并排序(Merge Sort)就是利用歸并思想對(duì)數(shù)列進(jìn)行排序。根據(jù)具體的實(shí)現(xiàn),歸并排序包括"從上往下"和"從下往上"2種方式。


      1. 從下往上的歸并排序:將待排序的數(shù)列分成若干個(gè)長度為1的子數(shù)列,然后將這些數(shù)列兩兩合并;得到若干個(gè)長度為2的有序數(shù)列,再將這些數(shù)列兩兩合并;得到若干個(gè)長度為4的有序數(shù)列,再將它們兩兩合并;直接合并成一個(gè)數(shù)列為止。這樣就得到了我們想要的排序結(jié)果。(參考下面的圖片)

      2. 從上往下的歸并排序:它與"從下往上"在排序上是反方向的。它基本包括3步:
      ① 分解 -- 將當(dāng)前區(qū)間一分為二,即求分裂點(diǎn) mid = (low + high)/2;
      ② 求解 -- 遞歸地對(duì)兩個(gè)子區(qū)間a[low...mid] 和 a[mid+1...high]進(jìn)行歸并排序。遞歸的終結(jié)條件是子區(qū)間長度為1。
      ③ 合并 -- 將已排序的兩個(gè)子區(qū)間a[low...mid]和 a[mid+1...high]歸并為一個(gè)有序的區(qū)間a[low...high]。

       

      下面的圖片很清晰的反映了"從下往上"和"從上往下"的歸并排序的區(qū)別。

       

      歸并排序圖文說明

      歸并排序(從上往下)代碼

      /*
       * 將一個(gè)數(shù)組中的兩個(gè)相鄰有序區(qū)間合并成一個(gè)
       *
       * 參數(shù)說明:
       *     a -- 包含兩個(gè)有序區(qū)間的數(shù)組
       *     start -- 第1個(gè)有序區(qū)間的起始地址。
       *     mid   -- 第1個(gè)有序區(qū)間的結(jié)束地址。也是第2個(gè)有序區(qū)間的起始地址。
       *     end   -- 第2個(gè)有序區(qū)間的結(jié)束地址。
       */
      void merge(int a[], int start, int mid, int end)
      {
          int *tmp = (int *)malloc((end-start+1)*sizeof(int));    // tmp是匯總2個(gè)有序區(qū)的臨時(shí)區(qū)域
          int i = start;            // 第1個(gè)有序區(qū)的索引
          int j = mid + 1;        // 第2個(gè)有序區(qū)的索引
          int k = 0;                // 臨時(shí)區(qū)域的索引
      
          while(i <= mid && j <= end)
          {
              if (a[i] <= a[j])
                  tmp[k++] = a[i++];
              else
                  tmp[k++] = a[j++];
          }
      
          while(i <= mid)
              tmp[k++] = a[i++];
      
          while(j <= end)
              tmp[k++] = a[j++];
      
          // 將排序后的元素,全部都整合到數(shù)組a中。
          for (i = 0; i < k; i++)
              a[start + i] = tmp[i];
      
          free(tmp);
      }
      
      /*
       * 歸并排序(從上往下)
       *
       * 參數(shù)說明:
       *     a -- 待排序的數(shù)組
       *     start -- 數(shù)組的起始地址
       *     endi -- 數(shù)組的結(jié)束地址
       */
      void merge_sort_up2down(int a[], int start, int end)
      {
          if(a==NULL || start >= end)
              return ;
      
          int mid = (end + start)/2;
          merge_sort_up2down(a, start, mid); // 遞歸排序a[start...mid]
          merge_sort_up2down(a, mid+1, end); // 遞歸排序a[mid+1...end]
      
          // a[start...mid] 和 a[mid...end]是兩個(gè)有序空間,
          // 將它們排序成一個(gè)有序空間a[start...end]
          merge(a, start, mid, end);
      }


      從上往下的歸并排序采用了遞歸的方式實(shí)現(xiàn)。它的原理非常簡單,如下圖:

      通過"從上往下的歸并排序"來對(duì)數(shù)組{80,30,60,40,20,10,50,70}進(jìn)行排序時(shí):
      1. 將數(shù)組{80,30,60,40,20,10,50,70}看作由兩個(gè)有序的子數(shù)組{80,30,60,40}和{20,10,50,70}組成。對(duì)兩個(gè)有序子樹組進(jìn)行排序即可。
      2. 將子數(shù)組{80,30,60,40}看作由兩個(gè)有序的子數(shù)組{80,30}和{60,40}組成。
          將子數(shù)組{20,10,50,70}看作由兩個(gè)有序的子數(shù)組{20,10}和{50,70}組成。
      3. 將子數(shù)組{80,30}看作由兩個(gè)有序的子數(shù)組{80}和{30}組成。
          將子數(shù)組{60,40}看作由兩個(gè)有序的子數(shù)組{60}和{40}組成。
          將子數(shù)組{20,10}看作由兩個(gè)有序的子數(shù)組{20}和{10}組成。
          將子數(shù)組{50,70}看作由兩個(gè)有序的子數(shù)組{50}和{70}組成。

       

      歸并排序(從下往上)代碼

      /*
       * 對(duì)數(shù)組a做若干次合并:數(shù)組a的總長度為len,將它分為若干個(gè)長度為gap的子數(shù)組;
       *             將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
       *
       * 參數(shù)說明:
       *     a -- 待排序的數(shù)組
       *     len -- 數(shù)組的長度
       *     gap -- 子數(shù)組的長度
       */
      void merge_groups(int a[], int len, int gap)
      {
          int i;
          int twolen = 2 * gap;    // 兩個(gè)相鄰的子數(shù)組的長度
      
          // 將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
          for(i = 0; i+2*gap-1 < len; i+=(2*gap))
          {
              merge(a, i, i+gap-1, i+2*gap-1);
          }
      
          // 若 i+gap-1 < len-1,則剩余一個(gè)子數(shù)組沒有配對(duì)。
          // 將該子數(shù)組合并到已排序的數(shù)組中。
          if ( i+gap-1 < len-1)
          {
              merge(a, i, i + gap - 1, len - 1);
          }
      }
      
      /*
       * 歸并排序(從下往上)
       *
       * 參數(shù)說明:
       *     a -- 待排序的數(shù)組
       *     len -- 數(shù)組的長度
       */
      void merge_sort_down2up(int a[], int len)
      {
          int n;
      
          if (a==NULL || len<=0)
              return ;
      
          for(n = 1; n < len; n*=2)
              merge_groups(a, len, n);
      }

      從下往上的歸并排序的思想正好與"從下往上的歸并排序"相反。如下圖:

      通過"從下往上的歸并排序"來對(duì)數(shù)組{80,30,60,40,20,10,50,70}進(jìn)行排序時(shí):
      1. 將數(shù)組{80,30,60,40,20,10,50,70}看作由8個(gè)有序的子數(shù)組{80},{30},{60},{40},{20},{10},{50}和{70}組成。
      2. 將這8個(gè)有序的子數(shù)列兩兩合并。得到4個(gè)有序的子樹列{30,80},{40,60},{10,20}和{50,70}。
      3. 將這4個(gè)有序的子數(shù)列兩兩合并。得到2個(gè)有序的子樹列{30,40,60,80}和{10,20,50,70}。
      4. 將這2個(gè)有序的子數(shù)列兩兩合并。得到1個(gè)有序的子樹列{10,20,30,40,50,60,70,80}。

       

      歸并排序的時(shí)間復(fù)雜度和穩(wěn)定性

      歸并排序時(shí)間復(fù)雜度
      歸并排序的時(shí)間復(fù)雜度是O(N*lgN)。
      假設(shè)被排序的數(shù)列中有N個(gè)數(shù)。遍歷一趟的時(shí)間復(fù)雜度是O(N),需要遍歷多少次呢?
      歸并排序的形式就是一棵二叉樹,它需要遍歷的次數(shù)就是二叉樹的深度,而根據(jù)完全二叉樹的可以得出它的時(shí)間復(fù)雜度是O(N*lgN)。

      歸并排序穩(wěn)定性
      歸并排序是穩(wěn)定的算法,它滿足穩(wěn)定算法的定義。
      算法穩(wěn)定性 -- 假設(shè)在數(shù)列中存在a[i]=a[j],若在排序之前,a[i]在a[j]前面;并且排序之后,a[i]仍然在a[j]前面。則這個(gè)排序算法是穩(wěn)定的!

       

      歸并排序?qū)崿F(xiàn)

      下面給出歸并排序的三種實(shí)現(xiàn):C、C++和Java。這三種實(shí)現(xiàn)的原理和輸出結(jié)果都是一樣的,每一種實(shí)現(xiàn)中都包括了"從上往下的歸并排序"和"從下往上的歸并排序"這2種形式。
      歸并排序C實(shí)現(xiàn)
      實(shí)現(xiàn)代碼(merge_sort.c)

        1 /**
        2  * 歸并排序:C 語言
        3  *
        4  * @author skywang
        5  * @date 2014/03/12
        6  */
        7 
        8 #include 
        9 #include 
       10 
       11 // 數(shù)組長度
       12 #define LENGTH(array) ( (sizeof(array)) / (sizeof(array[0])) )
       13 
       14 /*
       15  * 將一個(gè)數(shù)組中的兩個(gè)相鄰有序區(qū)間合并成一個(gè)
       16  *
       17  * 參數(shù)說明:
       18  *     a -- 包含兩個(gè)有序區(qū)間的數(shù)組
       19  *     start -- 第1個(gè)有序區(qū)間的起始地址。
       20  *     mid   -- 第1個(gè)有序區(qū)間的結(jié)束地址。也是第2個(gè)有序區(qū)間的起始地址。
       21  *     end   -- 第2個(gè)有序區(qū)間的結(jié)束地址。
       22  */
       23 void merge(int a[], int start, int mid, int end)
       24 {
       25     int *tmp = (int *)malloc((end-start+1)*sizeof(int));    // tmp是匯總2個(gè)有序區(qū)的臨時(shí)區(qū)域
       26     int i = start;            // 第1個(gè)有序區(qū)的索引
       27     int j = mid + 1;        // 第2個(gè)有序區(qū)的索引
       28     int k = 0;                // 臨時(shí)區(qū)域的索引
       29 
       30     while(i <= mid && j <= end)
       31     {
       32         if (a[i] <= a[j])
       33             tmp[k++] = a[i++];
       34         else
       35             tmp[k++] = a[j++];
       36     }
       37 
       38     while(i <= mid)
       39         tmp[k++] = a[i++];
       40 
       41     while(j <= end)
       42         tmp[k++] = a[j++];
       43 
       44     // 將排序后的元素,全部都整合到數(shù)組a中。
       45     for (i = 0; i < k; i++)
       46         a[start + i] = tmp[i];
       47 
       48     free(tmp);
       49 }
       50 
       51 /*
       52  * 歸并排序(從上往下)
       53  *
       54  * 參數(shù)說明:
       55  *     a -- 待排序的數(shù)組
       56  *     start -- 數(shù)組的起始地址
       57  *     endi -- 數(shù)組的結(jié)束地址
       58  */
       59 void merge_sort_up2down(int a[], int start, int end)
       60 {
       61     if(a==NULL || start >= end)
       62         return ;
       63 
       64     int mid = (end + start)/2;
       65     merge_sort_up2down(a, start, mid); // 遞歸排序a[start...mid]
       66     merge_sort_up2down(a, mid+1, end); // 遞歸排序a[mid+1...end]
       67 
       68     // a[start...mid] 和 a[mid...end]是兩個(gè)有序空間,
       69     // 將它們排序成一個(gè)有序空間a[start...end]
       70     merge(a, start, mid, end);
       71 }
       72 
       73 
       74 /*
       75  * 對(duì)數(shù)組a做若干次合并:數(shù)組a的總長度為len,將它分為若干個(gè)長度為gap的子數(shù)組;
       76  *             將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
       77  *
       78  * 參數(shù)說明:
       79  *     a -- 待排序的數(shù)組
       80  *     len -- 數(shù)組的長度
       81  *     gap -- 子數(shù)組的長度
       82  */
       83 void merge_groups(int a[], int len, int gap)
       84 {
       85     int i;
       86     int twolen = 2 * gap;    // 兩個(gè)相鄰的子數(shù)組的長度
       87 
       88     // 將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
       89     for(i = 0; i+2*gap-1 < len; i+=(2*gap))
       90     {
       91         merge(a, i, i+gap-1, i+2*gap-1);
       92     }
       93 
       94     // 若 i+gap-1 < len-1,則剩余一個(gè)子數(shù)組沒有配對(duì)。
       95     // 將該子數(shù)組合并到已排序的數(shù)組中。
       96     if ( i+gap-1 < len-1)
       97     {
       98         merge(a, i, i + gap - 1, len - 1);
       99     }
      100 }
      101 
      102 /*
      103  * 歸并排序(從下往上)
      104  *
      105  * 參數(shù)說明:
      106  *     a -- 待排序的數(shù)組
      107  *     len -- 數(shù)組的長度
      108  */
      109 void merge_sort_down2up(int a[], int len)
      110 {
      111     int n;
      112 
      113     if (a==NULL || len<=0)
      114         return ;
      115 
      116     for(n = 1; n < len; n*=2)
      117         merge_groups(a, len, n);
      118 }
      119 
      120 void main()
      121 {
      122     int i;
      123     int a[] = {80,30,60,40,20,10,50,70};
      124     int ilen = LENGTH(a);
      125 
      126     printf("before sort:");
      127     for (i=0; i)
      128         printf("%d ", a[i]);
      129     printf("\n");
      130 
      131     merge_sort_up2down(a, 0, ilen-1);        // 歸并排序(從上往下)
      132     //merge_sort_down2up(a, ilen);            // 歸并排序(從下往上)
      133 
      134     printf("after  sort:");
      135     for (i=0; i)
      136         printf("%d ", a[i]);
      137     printf("\n");
      138 }

      歸并排序C++實(shí)現(xiàn)
      實(shí)現(xiàn)代碼(MergeSort.cpp)

        1 /**
        2  * 歸并排序:C++
        3  *
        4  * @author skywang
        5  * @date 2014/03/12
        6  */
        7 
        8 #include 
        9 using namespace std;
       10 
       11 /*
       12  * 將一個(gè)數(shù)組中的兩個(gè)相鄰有序區(qū)間合并成一個(gè)
       13  *
       14  * 參數(shù)說明:
       15  *     a -- 包含兩個(gè)有序區(qū)間的數(shù)組
       16  *     start -- 第1個(gè)有序區(qū)間的起始地址。
       17  *     mid   -- 第1個(gè)有序區(qū)間的結(jié)束地址。也是第2個(gè)有序區(qū)間的起始地址。
       18  *     end   -- 第2個(gè)有序區(qū)間的結(jié)束地址。
       19  */
       20 void merge(int* a, int start, int mid, int end)
       21 {
       22     int *tmp = new int[end-start+1];    // tmp是匯總2個(gè)有序區(qū)的臨時(shí)區(qū)域
       23     int i = start;            // 第1個(gè)有序區(qū)的索引
       24     int j = mid + 1;        // 第2個(gè)有序區(qū)的索引
       25     int k = 0;                // 臨時(shí)區(qū)域的索引
       26 
       27     while(i <= mid && j <= end)
       28     {
       29         if (a[i] <= a[j])
       30             tmp[k++] = a[i++];
       31         else
       32             tmp[k++] = a[j++];
       33     }
       34 
       35     while(i <= mid)
       36         tmp[k++] = a[i++];
       37 
       38     while(j <= end)
       39         tmp[k++] = a[j++];
       40 
       41     // 將排序后的元素,全部都整合到數(shù)組a中。
       42     for (i = 0; i < k; i++)
       43         a[start + i] = tmp[i];
       44 
       45     delete[] tmp;
       46 }
       47 
       48 /*
       49  * 歸并排序(從上往下)
       50  *
       51  * 參數(shù)說明:
       52  *     a -- 待排序的數(shù)組
       53  *     start -- 數(shù)組的起始地址
       54  *     endi -- 數(shù)組的結(jié)束地址
       55  */
       56 void mergeSortUp2Down(int* a, int start, int end)
       57 {
       58     if(a==NULL || start >= end)
       59         return ;
       60 
       61     int mid = (end + start)/2;
       62     mergeSortUp2Down(a, start, mid); // 遞歸排序a[start...mid]
       63     mergeSortUp2Down(a, mid+1, end); // 遞歸排序a[mid+1...end]
       64 
       65     // a[start...mid] 和 a[mid...end]是兩個(gè)有序空間,
       66     // 將它們排序成一個(gè)有序空間a[start...end]
       67     merge(a, start, mid, end);
       68 }
       69 
       70 
       71 /*
       72  * 對(duì)數(shù)組a做若干次合并:數(shù)組a的總長度為len,將它分為若干個(gè)長度為gap的子數(shù)組;
       73  *             將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
       74  *
       75  * 參數(shù)說明:
       76  *     a -- 待排序的數(shù)組
       77  *     len -- 數(shù)組的長度
       78  *     gap -- 子數(shù)組的長度
       79  */
       80 void mergeGroups(int* a, int len, int gap)
       81 {
       82     int i;
       83     int twolen = 2 * gap;    // 兩個(gè)相鄰的子數(shù)組的長度
       84 
       85     // 將"每2個(gè)相鄰的子數(shù)組" 進(jìn)行合并排序。
       86     for(i = 0; i+2*gap-1 < len; i+=(2*gap))
       87     {
       88         merge(a, i, i+gap-1, i+2*gap-1);
       89     }
       90 
       91     // 若 i+gap-1 < len-1,則剩余一個(gè)子數(shù)組沒有配對(duì)。
       92     // 將該子數(shù)組合并到已排序的數(shù)組中。
       93     if ( i+gap-1 < len-1)
       94     {
       95         merge(a, i, i + gap - 1, len - 1);
       96     }
       97 }
       98 
       99 /*
      100  * 歸并排序(從下往上)
      101  *
      102  * 參數(shù)說明:
      103  *     a -- 待排序的數(shù)組
      104  *     len -- 數(shù)組的長度
      105  */
      106 void mergeSortDown2Up(int* a, int len)
      107 {
      108     int n;
      109 
      110     if (a==NULL || len<=0)
      111         return ;
      112 
      113     for(n = 1; n < len; n*=2)
      114         mergeGroups(a, len, n);
      115 }
      116 
      117 int main()
      118 {
      119     int i;
      120     int a[] = {80,30,60,40,20,10,50,70};
      121     int ilen = (sizeof(a)) / (sizeof(a[0]));
      122 
      123     cout << "before sort:";
      124     for (i=0; i)
      125         cout << a[i] << " ";
      126     cout << endl;
      127 
      128     mergeSortUp2Down(a, 0, ilen-1);        // 歸并排序(從上往下)
      129     //mergeSortDown2Up(a, ilen);            // 歸并排序(從下往上)
      130 
      131     cout << "after  sort:";
      132     for (i=0; i)
      133         cout << a[i] << " ";
      134     cout << endl;
      135 
      136     return 0;
      137 }

      上面3種實(shí)現(xiàn)的原理和輸出結(jié)果都是一樣的。下面是它們的輸出結(jié)果:

      before sort:80 30 60 40 20 10 50 70 
      after  sort:10 20 30 40 50 60 70 80 

       

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多