合并排序与分治法

来源:互联网 发布:java防止反编译 编辑:程序博客网 时间:2024/06/05 04:47

合并排序

 

考虑两个有序的数组,我们如何将它合并成第三个有序的数组?

 

比如:

a=[1, 3, 5, 7]

 

b=[2,4,4 ]

 

 

分用左手和右手从a,b数组中拿出元素,如果左手的小,就放第三个有序数组中去,反之,就把右手的放到第三个数组中,然后用空着的手取下一个:

------------

1357

↓取a1

1

244

------------

   357

1 2

   ↑取b2

   244

---------

    357

    ↓取a2

123

    44

--------

      57

1234

      ↑取b2 

      44

----------

       57

12344

       ↑ 取b3

       4

----------

        5  7

         ↓  ↓取a3a4

123445 7

 

 

这样,就可以将两个有序数组合成一个有序数组。

 

让我考虑更多的情况:

 

A1:考虑 1个元素的数组,本身为已序。

A2:两个元素的数组,可以看为将两个分别含有1个元素的数组合并成第三个已序的数组。

A3:可以归结为A2+A1的过程,然后再合并一次。

A4:归结为A2+A2的过程,然后再合并一次。

。。。

 

对于An,我们可以将它看作两个分别是两个A(n/2)合并一次的过程。

 

 

这就是我们所说的合并排序。

 

合并排序是所说的分治法,分治法一般要3步:

1,分解,将问题n分解为 两个 n/2 直到我们能直接解决的数。

2,解决问题。

3,合并,将分解以后的问题。

 

 

看图演示一个合并排序过程:

 

 

 

 

 代码就是明显的递归模式了。


import random
def merge(a, left, right , end):
        ''' merge two sorted sequence
        left right end of merge(Not include)
        a[left:right]
        a[right:end]
        '''
        llen=right - left
        rlen=end - right
        al=a[left:right]
        al.append(None)
        ar=a[right:end]
        ar.append(None)
        l=0
        r=0
        #print '<',left,right,end
        #print 'lr', al,ar
        #print a
        for i in range(end - left):
                if al[l] != None and ar[r] != None and (al[l] <= ar[r]):
                        a[left+i] = al[l]
                        l=l+1
                elif al[l] != None and ar[r] != None :
                        a[left+i] = ar[r]
                        r=r+1
                elif   ar[r] == None and al[l] != None:#right array is empty
                        a[left+i:end] = al[l:right-left]
                        break
                elif al[l] == None and ar[r] != None:
                        a[left+i:end] = ar[r:end-right]
                        break
        return a


def merge_sort(a,s,e):
        '''
        array
        [s:e+1]python slice [)
        '''
        if s < e:
                m=(s+e)/2
                merge_sort(a, s, m ) #a[s:m+1]python slice [)
                merge_sort(a, m+1 , e)#a[m+1:e][m+1:e+1] python slice [)
                merge(a, s,m+1,e+1)
        return a

for x in range(10000):
        a=[]
        b=list()
        n=random.randint(100,1130)
        for  i in range(1000):
                b.append(i)
        for i in range(n):
                #choose 9  random numbers in (1...1000) as a sort list
                a.append( random.choice(b))
        b= merge_sort(a,0,n-1)
        if b!= sorted(a):
                print 'err',n, x
                print a
                print b
                print sorted(a)

#a=[0, 177, 911, 453, 566, 985]
#print merge_sort(a,0,5)
#print merge(a,0,3,6)
#print a

 

画图使用gravpviz的dot,源代码如下:

 digraph merge{
        charset="utf-8";
        node [shape=plaintext, fontsize=16];
        "寮€濮?quot;->"鍒嗚В"->"鎺掑簭"->"鍚堝苟";
                
        node [shape=box ,rotate=90 ];

        node [ width=3 ];
        {rank =same;"5 2 4 7 1 3 6 2"; "寮€濮?quot;;}
        node [ width=1.5 ];
        "5 2 4 7 1 3 6 2"->"5 2 4 7";
        "5 2 4 7 1 3 6 2"->"1 3 6 2";
        {rank  = same;"5 2 4 7";"1 3 6 2"; }

        node [ width=.75 ];
        {rank = sname;"5  2"; "4  7";"1  3"; "6  2";}  
        "5 2 4 7"  -> "5  2";
        "5 2 4 7"  -> "4  7";
        "1 3 6 2" ->"1  3"; 
        "1 3 6 2" ->"6  2";    

        
        { rank = same; "5";"2";"4";"7";"1";"3";"6";"2 ";"鍒嗚В";}
        
         "5  2"->5;
         "5  2"->2;
         "4  7"->4;
         "4  7"->7;
        "1  3"->1; 
        "1  3"->3; 
        "6  2"->"6";  
        "6  2"->"2 ";  
        { rank = same; "2 5";"4 7";"1 3"; "2 6";"鎺掑簭";}
        5->"2 5";
        2->"2 5";
        4->"4 7";
        7->"4 7";
        1->"1 3";
        3->"1 3";
        "6"-> "2 6";
        "2 "-> "2 6";
        node [ width=1.5 ];
        {rank = same; "2 4 5 7"; "1 2 3 6";}
        "2 5"->"2 4 5 7";
        "4 7"->"2 4 5 7";
        "1 3"->        "1 2 3 6";
         "2 6"->"1 2 3 6";
        node [ width=3 ];
        "2 4 5 7" -> "1 2 2 3 4 5 6 7";
        "1 2 3 6" -> "1 2 2 3 4 5 6 7";
        {rank=same;"1 2 2 3 4 5 6 7";"鍚堝苟";}
        }

分治法使用递归,递归的讨论放到一篇里讨论。