常见排序算法(一) MergeSort

算法思想灰常重要,常见的用到分治思想的算法包括快速排序,归并,二分搜搜,大整数乘法等(参考 http://blog.csdn.net/com_stu_zhang/article/details/7233761,归纳很到位)

简单用归并对一个数组排序

  思路: 简单来说对一个数组,只要他的左右两部分都是有序的,那么简单合并就ok了,那么左右两部分可以进一步划分各自的左右两部分----明显就是要递归了

       算法:归并排序

           1. 将数组一分为二,subArray1 和subArray2

           2. 归并排序subArray1

           3.归并排序subArray2

           4. 合并 subArray1 subArray2

 

从合并subArray 这样简单的步骤入手 

    //By default. Ascending sort
    public int [] mergeArray(int[] a, int []b){
        int []merge = new int[a.length+b.length];
        
        int i = 0;
        int j = 0;
        int index  = 0;
        while(i<a.length && j < b.length){
            
            if(a[i] <= b[j]){
                merge[index ++] = a [i ++];
                
            }else if(a[i] > b[j]){
                merge[index ++] = b [j ++];
            }            
        }
        
        //if  array a go to the end ,copy array b
        if(i >= a.length){
            while (j < b.length){
                merge[index ++] = b [j ++];
            }
        }        
        //else copy array a
        if( j >= b.length){
            while ( i <a.length){
                merge[index ++] = a [i ++];
            }            
        }
        
        return merge;
    }

 接下来是写归并排序本身了,明显就是有递归调用,先只考虑简单实现,不考虑效率啊什么的

/***
 * Merge Sort-----Divide and Conquer http://blog.csdn.net/com_stu_zhang/article/details/7233761
 *           -----from step2 and step 3,we can find recursive
 * Step 1://divide into subarray1 and sub array2
 * Step 2://MergeSort sub array1
 * Step 3://MergeSort sub array2
 * Step 4://Merge sub array1 and sub array2    
 * @param a
 * @param start
 * @param end 
 */
    
    //Divide---merge 
    public void divideAndMerge(int[] a){
        int mid  = a.length / 2;
        new int left[] ;//copy  0 to mid 
        new int right[];//copy mid +1 to a.length -1
        
        if( a.length == 1){
            return ;
        }else{
            divideAndMerge(left);
            divideAndMerge(right);
            mergeArray(left,right);            
        }        
    }

 

然后我们就要考虑性能的问题了,以上的代码块明显需要不断new新的子数组存储被分治出来的小数组,而new操作是比较耗性能的

考虑到java中对象都是传reference,而我们的合并操作其实只要提供数组的下标位置就可以知道是要合并哪个子数组(注意归并的一定相邻子数组,木有跳跃的情况),只需要提供起始下标就可以分成俩子数组合并,同时给一个临时数组用于排序的临时存储空间够用了,于是归并排序的参数以及合并方法的参数都有了

 1     public void mergeArrayNew(int[] a, int start_pos,int end_pos,int[] tmp){
 2         int mid_pos  = (end_pos - start_pos) /2 + start_pos;
 3         int i = start_pos;
 4         int j = mid_pos + 1;
 5         int index = start_pos;
 6         
 7         while( i <= mid_pos && j <= end_pos){
 8             if(a[i] <= a[j]){
 9                 tmp[index] = a[i];
10                 i++;
11                 index ++;
12             }else {
13                 tmp[index] = a [j];
14                 j++;
15                 index ++;
16             }
17         }
18         
19         if(j >  end_pos){
20             while(i <= mid_pos ){
21                 tmp[index] = a[i];
22                 i++;
23                 index ++;
24             }
25         }
26         if(i > mid_pos ){
27             while ( j <= end_pos){
28                 tmp[index] = a [j];
29                 j++;
30                 index ++;
31             }
32         }
33         
34         //attention!!!
35         for(int copy = start_pos;copy<=end_pos;copy++){
36             a[copy] = tmp[copy];
37         }
38         
39     }
40     
41     //Divide---merge 
42     public void divideAndMergeNew(int[] a,int start_pos,int end_pos,int[] tmp){
43         int mid_pos  = (end_pos - start_pos) /2 + start_pos;
44         
45         if( start_pos == end_pos){
46             return ;
47         }else{
48             divideAndMergeNew(a,start_pos,mid_pos,tmp);
49             divideAndMergeNew(a,mid_pos + 1,end_pos,tmp);
50             mergeArrayNew(a,start_pos,end_pos,tmp);            
51         }        
52     }

 

posted @ 2014-07-31 21:59  dijkstra-c  阅读(258)  评论(0编辑  收藏  举报