【算法】【sort 2.2.1】歸併排序

排序過程

[Running] g++ test_sort_guibing_2.2..1.cpp -std=c++14 -o test_sort_guibing_2.2..1.exe && ./test_sort_guibing_2.2..1.exe
 81 72 67 89 80 65 77 83 82 68 70 88
--resize--12
--b--
sort;lo 0 hi 11
sort;lo 0 hi 5
sort;lo 0 hi 2
sort;lo 0 hi 1
return;lo 0 hi 0
return;lo 1 hi 1
 merge lo 0 mid 0 hi 1
 72 81 67 89 80 65 77 83 82 68 70 88
---
return;lo 2 hi 2
 merge lo 0 mid 1 hi 2
 67 72 81 89 80 65 77 83 82 68 70 88
---
sort;lo 3 hi 5
sort;lo 3 hi 4
return;lo 3 hi 3
return;lo 4 hi 4
 merge lo 3 mid 3 hi 4
 67 72 81 80 89 65 77 83 82 68 70 88
---
return;lo 5 hi 5
 merge lo 3 mid 4 hi 5
 67 72 81 65 80 89 77 83 82 68 70 88
---
 merge lo 0 mid 2 hi 5
 65 67 72 80 81 89 77 83 82 68 70 88
---
sort;lo 6 hi 11
sort;lo 6 hi 8
sort;lo 6 hi 7
return;lo 6 hi 6
return;lo 7 hi 7
 merge lo 6 mid 6 hi 7
 65 67 72 80 81 89 77 83 82 68 70 88
---
return;lo 8 hi 8
 merge lo 6 mid 7 hi 8
 65 67 72 80 81 89 77 82 83 68 70 88
---
sort;lo 9 hi 11
sort;lo 9 hi 10
return;lo 9 hi 9
return;lo 10 hi 10
 merge lo 9 mid 9 hi 10
 65 67 72 80 81 89 77 82 83 68 70 88
---
return;lo 11 hi 11
 merge lo 9 mid 10 hi 11
 65 67 72 80 81 89 77 82 83 68 70 88
---
 merge lo 6 mid 8 hi 11
 65 67 72 80 81 89 68 70 77 82 83 88
---
 merge lo 0 mid 5 hi 11
 65 67 68 70 72 77 80 81 82 83 88 89
---
 65 67 68 70 72 77 80 81 82 83 88 89
--e--

[Done] exited with code=0 in 0.6 seconds

sort

  • 對外api
  • arr 是 原始數組
  • low = 0 ;
  • high = arr.length - 1
sort(arr, low, high )

分治

  • 先左後右
void sort(arr, lo, hi)
{
  int mid = lo + (hi - lo )/ 2; 
  //左邊
  sort(arr,lo,mid);
  //右邊
  sort(arr,mid+ 1 , hi);
  merge(arr,lo,mid,hi);
}

merge

  • 我寫的很麻煩。還調了一下
//輸入兩個有序數組,合併到第三個數組
#include <vector>
#include <string>
#include <iostream>

using Vec = std::vector<int>;

 void show(Vec &v)
{
    //for(auto &entry : v)
    int i = 0;
    int size = v.size();
    for(;i<size;i++)
    {
        std::cout <<" "<< v[i];
    }
    std::cout <<std::endl;
}
bool less(int a, int b )
{
    if(a <b )
    {
        return true;
    }
    return false;
}
bool exchange( int  *a ,int *b)
{
    if(a == nullptr || b == nullptr )
    {
        return false;
    }
    int tmp = *a;
    *a = *b;
    *b = tmp;
    return true;
}
//最多進行了n-1 比較,最後一次不需要了,直接插入
void merge(Vec &out ,Vec &in1, Vec &in2)
{
    int s1 = in1.size();
    int s2 = in2.size();

    

    int size = out.size();

    if(size < s1+s2)
    {
        std::cout <<" merge fail ,out size mismatch " <<std::endl;
        return;
    }

    int k = 0; 
    int j = 0;
    int i = 0 ;
    int p1;
    int p2;
    bool b1 = true;
    bool b2 = true;
    do
    {
       
        {
            //判斷新的i是否有效
           if(i < s1)
           {
              p1 = in1[i];
           } else
           {
               b1 = false;
           }
           
            if(j< s2){
                 p2 = in2[j];
            } 
            else
           {
              b2 = false;
            }       
        }
        if(b1 && b2 )
        {
            if(p1 <= p2)
               //in1 的小或者相等,插入in1
           {
               out[k] = p1;
               i++;   
           }else 
          {
                //in1 大,插入in2的
               out[k] = in2[j];
               j++;
          }
          k++;
        }else
        {   //i j 有一個已經完畢了,但是k 還是ok的,所以先插入,再i++/j++ 和 k++。除非都完畢了

            //注意
            //至少一個爲false了,使用上一次有效的i或者j ,插入後再遞增,k也是這樣
            if(!b1 &&  b2)
            {
                std::cout <<" insert k "<<k <<" in2 "<< in2[j] <<std::endl;
                out[k] = in2[j];
                 k++;
                 j++;

            }else
            if(b1 && !b2)
            {
              
                out[k] = in1[i];
                 std::cout <<" insert k " << k <<" in1 "<< in1[i] <<std::endl;
                 k++;
                 i++;
            }
            else if(!b1 && !b2)
            {
                 std::cout <<"both false, break i "<<i <<" j "<<j <<" k "<<k <<std::endl;
                break;
            }

        }
     
        //這個可以不加了
        if(s1 == i && s2 == j )
        {
            std::cout <<" break i "<<i <<" j "<<j <<std::endl;
           // break;
        }
        
  
    }while(i>=0 && j>=0);
}

int main()
{
    Vec v1 = {1,3,24,26};
    Vec v2 = {2,15,27,38};
    int s1 = v1.size();
    int s2 = v2.size();
    int size = s1 + s2;
   // Vec out[size]= {0};
   Vec out;
      std::cout <<"--resize--"<<size <<std::endl;
   out.resize(size);
   show(v1);
   show(v2);
   std::cout <<"--b--"<<std::endl;
   merge(out,v1,v2);
   show(out);
   std::cout <<"--e--"<<std::endl;

}

java 書寫的

  • 非常優雅
  • 轉爲c++:
//輸入兩個有序數組,合併到第三個數組,用遞歸排序+ 優雅merge
#include <vector>
#include <string>
#include <iostream>

using Vec = std::vector<int>;

 void show(Vec &v)
{
    //for(auto &entry : v)
    int i = 0;
    int size = v.size();
    for(;i<size;i++)
    {
        std::cout <<" "<< v[i];
    }
    std::cout <<std::endl;
}
bool less(int a, int b )
{
    if(a <b )
    {
        return true;
    }
    return false;
}

   Vec out;


bool exchange( int  *a ,int *b)
{
    if(a == nullptr || b == nullptr )
    {
        return false;
    }
    int tmp = *a;
    *a = *b;
    *b = tmp;
    return true;
}

//優雅merge
//輸入的是下標
void merge(Vec &aux,Vec &a, int lo ,int mid ,int hi)
{
    //歸併 a[lo,mid] 和 a[mid +1 ,hi]
    //先拷貝出來
     int k = lo ;
     for(;k<=hi;k++)
     {
        aux[k] = a[k];
     }
   // show(aux);
    k = lo;
    int i = lo;
    int j = mid + 1; 
    std::cout <<" merge lo "<< lo <<" mid "<< mid <<" hi "<<hi <<std::endl;


    //aux 歸併回a
    for ( ;k <= hi;k++)
    {
        if(i > mid ) {
            a[k] = aux[j++];
        }
        else if (j > hi )
        {
            a[k] = aux[i++];
        }else if(less(aux[j],aux[i]))
        {
            a[k] = aux[j++];
        }else {
            a[k] = aux[i++];
        }
    }
}


void  sort(Vec &a,int lo,int hi)
{
//退出遞歸
    if(lo>= hi)
    {
        std::cout <<"return;lo "<<lo <<" hi "<<hi <<std::endl;
        return ;
    }else
    {
         std::cout <<"sort;lo "<<lo <<" hi "<<hi <<std::endl;
    }
    
    int mid = lo + (hi - lo )/2 ;

    sort(a,lo,mid);
    sort(a,mid+1,hi);
    merge(out,a,lo,mid,hi);
   // std::cout <<" after merge b "<<std::endl;
    show(a);
 //   std::cout <<" ater merge e "<<std::endl;
    std::cout<<"---"<<std::endl;
}

int main()
{

     Vec v = {81 ,72, 67, 89, 80, 65, 77, 83, 82, 68, 70, 88};
  //   Vec v = {81 , 67, 89};
   // Vec out[size]= {0};
   int size =v.size();
   show(v);
      std::cout <<"--resize--"<<size <<std::endl;
   out.resize(size);

    int lo = 0;
    int hi = v.size() -1;

    // int k = lo;
    // for(;k<= hi;k++)
    // {
    //     out[k] = v[k];
    // }
   //  show(out);
    std::cout <<"--b--"<<std::endl;
    sort(v,lo,hi);
   show(v);
   std::cout <<"--e--"<<std::endl;

}
  • 優雅在於 有一邊走完了
  • 考慮 i 可能 >mid ,
  • 考慮 j 可能> hi
  • 其他情況選二者小的

我的錯誤

  • merge裏 是需要一個額外的內存區域存放要merge好的數據
  • 然後再賦值給原始數組的
  • java這裏提前分配了一個 同樣大小的數組aux
  • 拷貝的時候要用 k = lo; k<= hi: k++
  • 注意:hi 元素位置是有值的,看傳遞的參數就知道了是len -1

退出遞歸的的條件

sort 傳入的參數裏 
 lo >= hi 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章