归并排序:
简单介绍一下:“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表,它的实现方式大家早都已经熟悉了,无论是顺序存储结构还是链表存储结构,都可以在O(有序表的长度之和)时间内实现,利用归并的思想容易实现排序,假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到 n/2 个长度为2或者为1的有序子序列,在两两归并 一直重复 直到得到一个长度为n的有序序列为止,这种排序方法简称2-路归并排序,
初始的无序表:【49】【38】[65] [97] [76] [13] [27]
一趟归并之后:【38 49】【65 97】【13 76】【27】
二趟归并之后:【38 49 65 97】【13 27 76】
三趟归并之后:【13 27 38 49 65 76 97】
有序表的比较就比较好比了
例如 二趟归并的前后两个有序序列
【38 49 65 97】【13 27 76】
第一个有序序列的 索引开始处与 第二个有序序列的 索引开始处比较,将较小者优先放到排序数组存储
然后将指针向后移动 依次比较直到两个有序序列之一完全使用完毕
将剩余有序序列依次将元素放到排序数组中 组成新的也就是两个有序子序列排序后组合成新的数组
下面是使用java实现的一个简单的讲一个顺序存储的无序序列 归并排序变为一个有序的序列
/** * 简单介绍一下:“归并”的含义是将两个或两个以上的有序表组合成一个新的有序表,它的实现方式大家早都已经熟悉了, * 无论是顺序存储结构还是链表存储结构,都可以在O(有序表的长度之和)时间内实现所以也就四线性时间,利用归并的思想容易实现排序, * 假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并, * 得到 n/2 个长度为2或者为1的有序子序列,在两两归并 一直重复 直到得到一个长度为n的有序序列为止, * 这种排序方法简称2-路归并排序, * <p> * 初始的无序表:【49】【38】[65] [97] [76] [13] [27] * <p> * 一趟归并之后:【38 49】【65 97】【13 76】【27】 * <p> * 二趟归并之后:【38 49 65 97】【13 27 76】 * <p> * 三趟归并之后:【13 27 38 49 65 76 97】 * <p> * 有序表的比较就比较好比了 * <p> * 例如 二趟归并的前后两个有序序列 * <p> * 【38 49 65 97】【13 27 76】 * <p> * 第一个有序序列的 索引开始处与 第二个有序序列的 索引开始处比较,将较小者优先放到排序数组存储 * <p> * 然后将指针向后移动 依次比较直到两个有序序列之一完全使用完毕 * <p> * 将剩余有序序列依次将元素放到排序数组中 组成新的也就是两个有序子序列排序后组合成新的数组 * <p> * 分段处理 * * @param a * @param b * @param left * @param right */ public static void mergeSotr(String[] a, String[] b, int left, int right) { if (left < right) { //只要当前(right-left+1)数组个数大于2个 就将数组拆成两半 int midIndex = (left + right) / 2; // 在将拆成两段的前一段在继续拆 mergeSotr(a, b, left, midIndex); // 在将拆成两段的后一段在继续拆 mergeSotr(a, b, midIndex + 1, right); //将拆过的两段 进行排序之后并合并 merge(a, b, left, midIndex + 1, right); } } /** * @param a 原数组 * @param b 存贮某段排序后的数组 * @param leftPos * @param rightPos * @param rightEnd */ public static void merge(String[] a, String[] b, int leftPos, int rightPos, int rightEnd) { int leftEnd = rightPos - 1; int tmpPos = leftPos; int numElements = rightEnd - leftPos + 1; //先确定 两个输出表都没有使用完 while (leftPos <= leftEnd && rightPos <= rightEnd) //将两个输出表中 对应a[leftPos] 与 a【rightPos】较小者 放进 b数组中 if (comPareTo(a[leftPos], a[rightPos]) <= 0) b[tmpPos++] = a[leftPos++]; else b[tmpPos++] = a[rightPos++]; /** *程序执行到这里 一定是两个输出表其中的一个 被使用完了。请看上面循环 * 先判断下是不是 左边的输出表被用完了 */ while (leftPos <= leftEnd) /** * 上面判断 左边的输出表还没有使用完,那肯定是右边的输出表用完了 * 当右边边的输出表使用完成后将左边的输出表剩余元素依次放进数组b中 */ b[tmpPos++] = a[leftPos++]; /** * 程序执行到这里 一定是两个输出表其中的一个 被使用完了。请看上面第一个循环 * 先判断下是不是 右边的输出表被用完了 * */ while (rightPos <= rightEnd) /** * 上面判断 右边的输出表还没有使用完,那肯定是左边的输出表用完了 * 当左边的输出表使用完成后将右边的输出表剩余元素依次放进数组b中 */ b[tmpPos++] = a[rightPos++]; for (int i = 0; i < numElements; i++, rightEnd--) //将排好序的b a[rightEnd] = b[rightEnd]; }
*/ public static int comPareTo(String b1, String b2) { BigDecimal bd1 = new BigDecimal(b1); BigDecimal bd2 = new BigDecimal(b2); return bd1.compareTo(bd2); }
@Test
//测试用的代码 public void testtiii() { /* String[] a = {"24", "13", "26", "0.00", "43", "24", "13", "0", "1", "2", "27", "15", "38"}; */ String[] a = {"19", "0", "0", "12"}; int a2Size = 0; String[] a2 = new String[a.length]; for (int i = 0; i < a.length; i++) { if (!(new BigDecimal(a[i]).setScale(0, BigDecimal.ROUND_DOWN).compareTo(new BigDecimal("0")) == 0)) a2[a2Size++ ] = a[i]; } String[] a3 = new String[a2Size],a4 = new String[a2Size]; if (a2Size==0) return; System.arraycopy(a2,0,a3,0,a2Size); String[] c = {"1", "13", "0", "15"}; String[] b = new String[a.length]; AdtUtil.mergeSotr(a3, a4,0, a3.length - 1); for (String s : a3) { System.out.println(s); } for(int i =0,j=0; i<a.length&&j<a3.length;i++){ if("0".equals(a[i])) continue; if (a[i]!=a3[j]){ throw new RuntimeException("Index:"+i); } j++; } }