java将一乱序数组排序,排序算法——分治思想与归并排序

1、分治法思想

分治思想主要通过递归来实现,每层递归中主要包括三个步骤:

分解:即将原问题划分为若干子问题,子问题的形式要保证和原问题一致,但规模更小。

解决:当划分子问题的规模足够小时,停止递归,求解子问题,获取子问题的解决结果并返回给上一层。

合并:将子问题的解决结果进行合并,得到原问题的解。

也就是说,分治思想就是将一个大问题用过递归层层分解为无数个子问题,这些子问题要保证与与原问题是一个类型,只不过规模更小更加容易求解,但求解过程相同。

2、归并排序算法思想

1、思考:如果给了我们两个已经做好排序的数组(相同排序规则)A和B,我们该如何将其合并到一个有序数组C?

这个问题很简单,依次从两个数组中取元素比较然后放进C中即可。而如果A、B数组都只有一个元素时,他们都成为了一个有序数组,则可以直接进行比较放在数组C中,返回有序的数组C。

2、通过分治思想对无序数组排序问题进行划分:对于一个无序的数组array

(1)分解:通过递归将无序数组进行划分,每次从array.length/2处划分为两个数组,直到划分后的子数组规模为1。

(2)解决:当子数组规模为1时,此时的最小规模数组已经自动变为一个有序数组,递归终止返回有序数组结果。

(3)合并:接收下一层递归所返回的两个有序子数组,将这两个有序子数组的数据进行合并为一个新的有序数组,然后返回该有序数组给上一层递归。

3、排序实例:为方便理解递归划分数组,可以建立一个递归树形图(理解递归比较方便)。以数组int[] arr = {3,23,4,13,4,5,63,6,2}为例,其数组划分树形图为

beefe68b716c5d9d94da397533d57880.png

那么接下来就是将叶子节点已经排序好的数组返回给上一层递归,在上一层中处理合并一个新的有序数组再返回给上一层,重复该步骤直到根节点层就可以将原数组变为一个有序数组。

1525233026764472.png

也就是说,归并算法中递归调用的方法主要为两部分,分别是分割数组以及数组合(将两个有序数组进行合并)。伪代码如下

merge(int[] arr){

if(arr.length < 2){

return arr;//如果传入的数组长度为1那么就直接返回

}

int[] left = splitLeft(arr);//划分获取左子数组

int[] right = spliteRight(arr);//划分获取右子数组

left = merge(left);//递归调用,获得排序后的左子数组

right = merge(right);//递归调用,获得排序后的右子数组

arr = sort(left,right);//将左右有序子数组合并为一个有序数组

return arr;//返回

}

具体代码实现(个人写的依据算法逻辑思想写的一个示例,划分左右子数组都是新创建数组进行赋值,空间复杂度很高,而且提高了时间复杂度,但是主要是便于理解)

个人实现:

/**

*

* @Description:分治算法,利用递归,将一个数组元素不断的分割为两个数组,直到数组分割到只剩下一个元素

* 然后返回给上一层,主要是保证返回给上一层中的两个数组是已经排好序的数组,在上一层中进行排序合并,然后再返回

* 就可以最终得到一个有序数组

*/

public class Sort {

public static int[] merge(int[] arr){

int left = 0;

int right = arr.length;

if (right == 1) {

int[] endArr = {arr[left]};

return endArr;

}

//数组划分

int mid = (left + right) / 2;

int[] leftArr = new int[mid-left];

int[] rightArr = new int[right - mid];

for (int i = 0; i <= mid-1; i++) {

leftArr[i] = arr[i];

}

for (int i = 0,j=mid; i < rightArr.length && j < arr.length; i++,j++) {

rightArr[i] = arr[j];

}

//递归调用,获取排序完成的左右子数组

leftArr = merge(leftArr);

rightArr = merge(rightArr);

//合并两个数组并排序

return sort(arr, leftArr, rightArr);

}

public static int[] sort(int[] arr, int[] left, int[] right){

int i = 0;

int j = 0;

for (int index = 0; index < arr.length; index++){

if (i >= left.length && j < right.length) {

arr[index] = right[j];

j++;

continue;

}

if (j >= right.length && i < left.length) {

arr[index] = left[i];

i++;

continue;

}

if (left[i] > right[j]){

arr[index] = right[j];

j++;

} else {

arr[index] = left[i];

i++;

}

}

return arr;

}

public static void main(String[] args) {

int[] arr = {3,23,4,13,4,5,63,6,2};

for(int i:merge(arr)) {

System.out.println(i);

}

}

}

较好的实现:

public class Solution {

/*

* @param A:an integer array

* @return:

*/

public voidsortIntegers2(int[] A) {

// writeyour code here

//利用归并排序对数组A进行排序

mergeSort(A,0,A.length-1);

}

//归并排序

public void mergeSort(int[] A,int start,int end){

if(start>=end) return;

int middle= (start+end)/2;

mergeSort(A,start,middle);

mergeSort(A,middle+1,end);

//归并排序需要分配的临时数组

//这是归并排序的核心

int []temp = new int[end-start+1];

inti=start;

int j =middle+1;

intindex=0;

while(i<=middle&&j<=end){

if(A[i]<=A[j]){

temp[index++] = A[i++];

}else{

temp[index++] = A[j++];

}

}

while(i<=middle){

temp[index++] =A[i++];

}

while(j<=end){

temp[index++] =A[j++];

}

i=start;

index = 0;

for(;i<=end;i++){

A[i] =temp[index++];

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值