分治_合并算法实现数组排序(非递减)(Java实现)
分治_合并算法的思想就是 先将大的问题分为规模相近的两个小的问题,递归地将其再分为两个小问题,直至不可再分。然后将其合并,在合并过程中通过比较等方法将问题解决,将小的问题逐个解决后,再将它们合并起来,即可得到大问题的解。
下面以一道题目为例子介绍合并算法
给定一个包含n个元素的一维线性序列 ,对这n个元素按照非递减顺序排序。设 a[0:7] = {23,5,9,16,30,25,17,18},采用基于分治策略的合并排序算法解决该问题。
按照思想,我们需要将这个数组递归地分成两个数组,直至数组不可再分; 然后再通过比较,将数组合并,通过比较之后合并的数组都是有序的,所以最终得到的数组是有序的。
(图是自己画的,还不是很熟练,所以有点丑,以后多练习一下)
下面附上解题代码:
package com.gduf.exer1;
/*
* 给定一个包含n个元素的一维线性序列 ,对这n个元素按照非递减顺序排序。
* 设 a[0:7] = {23,5,9,16,30,25,17,18},采用基于分治策略的合并排序算法解决该问题。
*/
public class DivideAndMerge {
public static void MergeSort(int[] arr, int left, int right) {
//left为起始位置,right为结束位置
if (left < right) {
int mid = (left + right) / 2; //mid为二分位置
MergeSort(arr, left, mid); //前半部分
MergeSort(arr, mid + 1, right); //后半部分
Merge(arr, left, mid, right); //将数组合并
}
}
/**
* @param: section1: 左边数组第一个元素的下标
* @param: section2: 左边数组最后一个元素,将section2+1可得右边数组第一个元素的下标
* @param: last: 右边数组的最后一个元素
*/
public static void Merge(int[] arr, int section1, int section2, int last) {
int[] temp = new int[last - section1 + 1]; //声明一个临时数组,长度为要归并的数组的长度
int i = section1; //记住左边数组第一个元素的下标
int j = section2 + 1; //记住右边数组第一个元素的下标
int k = 0; //k用于记录临时数组下标
while ((i <= section2) && (j <= last)) {
//左边数组元素和右边数组元素比较,把小的元素赋给临时数组
//每一次将数组的值赋给临时数组后都+1,临时数组获取值后也+1
if (arr[i] <= arr[j]) {
temp[k++] = arr[i++];
} else {
temp[k++] = arr[j++];
}
}
/*
* 若左侧或右侧在执行完上述代码后(即不满足while循环条件后)仍然还有数组未复制到
* 临时数组中,则执行下面的两个while语句,确保所有数组都会被复制到临时数组中,
* 并通过这样的过程,保证合并后的数组有序。
*/
//把左边剩余的数组元素赋给临时数组
while (i <= section2) {
temp[k++] = arr[i++];
}
//把右边剩余的数组元素赋给临时数组
while (j <= last) {
temp[k++] = arr[j++];
}
//用临时数组元素覆盖原数组元素
for (int count = 0; count < temp.length; count++) {
arr[count + section1] = temp[count];
}
}
public static void main(String[] args) {
//原数组
int[] arr = {23,5,9,16,30,25,17,18};
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
MergeSort(arr, 0, arr.length - 1);// 从数组arr的0位到arr.length-1位排序
//排序后
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}