算法分析:自然合并排序算法 设数组中部分元素已按自然数顺序排放 JAVA实现

设数组中部分元素已按自然数顺序排放,例如,数组 a = { 4 , 9 , 2 , 6 , 1 , 5 , 7 , 3 },则初期自然排好序的子数组段显然有4段,分别为{ 4 , 9 },{ 2 , 6 },{ 1 , 5 , 7 }和{ 3 }。请充分利用上述特点设计并实现一个自然合并排序算法。

 

算法设计思路

只是分割的方法不一样,这个需检测数组前一位是否比后一位大,如果大的话就分割,逐渐划分开来,他里面是有序的。只需要用一个数组来记录分割后每段数组尾数的位置,然后将数值与这个记录数组进行连接即可。然后排序方法是与合并排序相符合的。

 

算法实现的伪代码

算法fenge(int arr[], int n, int barr[])

输入:数组、数组长度、记录位置的数组

输出:返回数组分段的段数

  1. len  1
  2. barr [ 0 ]  0
  3. for i ← 1 to n
  4. do if arr [ i ] < arr [ i - 1 ]
          1. then barr [ len ++ ] ← i
  5. return len

 

算法mergeSort(int arr[], int n, int barr[], int len , int left , int right)

输入:数组、数组长度、记录位置的数组、分段段数、记录位置数组的首位下标、记录位置数组的尾部下标

输出:排序好的数组

1. if   right – left > 0  then

2.  mid ← (left + right ) / 2

3.   mergeSort ( arr , n , barr , len , left , mid )

4.    mergeSort ( arr , n , barr , len , mid + 1 , right )

5.    int bLeft , bMid , bRight

6.   bLeft    barr  [ left ]

7.   bMid  ←  barr [ mid + 1 ] - 1  

8.           if  right + 1 < len   then

                    bRight  ← barr [ right + 1 ] -1

9.       else

                     bRight  ← n - 1

10.   merge ( arr , bLeft ,bMid , bRight )

 

算法merge (int arr[], int left , int mid , int right)

输入:待排序数组、数组的最左端下标、数组中间坐标、数组最右端下标

输出:临时排序数组

1. int lFirst ← left , rFirst ← mid + 1

2. int temp ← 0

3. int work [ right – left + 1 ]

4. while lFirst <= mid && rFirst <= right

5.        do if arr [ lFirst ] < arr[ rFirst ]

6.              work [ temp ++ ] ← arr[ lFirst ++ ]

7.        else work[ temp ++ ] ← arr[ rFirst ++ ]

8. while lFirst <=  mid

9.        do work[ temp ++ ] ← arr[ lFirst ++ ]

10. while rFirst <=right

11.    do work[ temp ++ ] ← arr[ rFirst ++ ]

12. for i ←left, j ← 0 ; i to right ; i++,j++

13.    do arr [ i ] ← work [j]

 

实现代码

public class Main {
    public static void main(String[] args) {
        int[] arr = {4, 9, 2, 6, 1, 5, 7, 3};

        int[] barr = new int[8]; //记录位置的数组
        int len = fenge(arr, 8, barr); //分段段数

        mergeSort(arr, 8, barr, len, 0, len - 1); //排序,len-1才是正确的下标
        System.out.print(arr[0]);
        for(int i = 1; i < 8; i++)
            System.out.print(" " + arr[i]);
        System.out.println();
    }

    public static int fenge(int[] arr, int n, int[] barr) {
        int len = 1;
        barr[0] = 0;
        for(int i = 1; i < n; i++) {
            if(arr[i] < arr[i - 1])   //如果后一位比前一位小,则len++,barr记录下小位数的下标+1
                barr[len++] = i;
        }
        return len; //返回段数
    }

    public static void mergeSort(int[] arr, int n, int[] barr, int len, int left, int right) {
        if(right - left > 0) { //如果大于零,证明还可以划分
            int mid = (left + right) / 2;
            mergeSort(arr, n, barr, len, left, mid); //前半段继续划分
            mergeSort(arr, n, barr, len, mid + 1, right); //后半段继续划分
            int bLeft, bMid, bRight; //用于与arr连接
            bLeft = barr[left];
            bMid = barr[mid + 1] - 1;
            if(right + 1 < len) //判断右端的数又没有超出分割长度
                bRight = barr[right + 1] - 1;
            else
                bRight = n - 1;
            merge(arr, bLeft, bMid, bRight);
        }
    }

    public static void merge(int[] arr, int left, int mid, int right) {
        int lFirst = left, rFirst = mid + 1; //lFirst 为左边首位,rFirst为右边首位
        int temp = 0;
        int[] work = new int[right - left + 1]; //临时数值存放排序数组,长度为两个之和
        while(lFirst <= mid && rFirst <= right) {
            if(arr[lFirst] < arr[rFirst])
                work[temp++] = arr[lFirst++];
            else
                work[temp++] = arr[rFirst++];
        }
        while(lFirst <= mid)
            work[temp++] = arr[lFirst++];

        while(rFirst <= right)
            work[temp++] = arr[rFirst++];

        for(int i = left, j = 0; i <= right; i++, j++) //复制临时数组到原数组中
            arr[i] = work[j];
    }
}

写得不好,多请谅解!

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值