您的位置:首页 > 编程语言 > Java开发

Java实现2路合并次序最小比较次数

2016-12-02 09:27 351 查看

题目



分析

该题目属于贪心算法,一直寻找最小的两个序列的Si以及Sj进行合并,因为总的合并次数不变的,k个序列,一共需要k-1次的合并。

因为题目已经给出默认2路归并排序需要m+n-1次比较(这个是最坏的情况),然后需要k-1次合并,所以就是把m+n-1中-1提出来,那么就剩下m+n,因为m+n表示序列长度,那么使得该值最小,就要尽可能使m+n最小,所以一直寻找最小的两个序列即可。

代码

package chapter2;

import java.util.Arrays;
/**
* 总体的思路为贪心算法,总是选择当前最小的两个长度的数据进行合并,但是难点在于数据的存储,而不是计算次数
*
* */
public class GreedyMerge {

//合并的比较次数统计
private static int count = 0;
//数据最大为多少
private final static int DATA_MAX_VALUE = 100;
//所有的序列个数
private final static int ARRAY_NUM = 5;
//每个序列的大小
private static int [] len_array = {4,5,6,8,7};
//数据
private static int [] [] data = null;
//辅助数组
private static int [] copy = null;

private static int l , r;

//辅助数组2,用于对基础排序放置数据被000冲掉
private static int [] temp = null;

/**
* 产生数组数据data,要控制,用于初始化;缺点在于浪费存储空间,后面尽量优化,采用两个辅助数组去优化
*
* */
private static void init(){
//辅助 数据的大小统计
int len = 0;
int max = 0;

for(int i = 0 ; i < ARRAY_NUM ; i ++){
len += len_array[i];
if(max < len_array[i]){
max = len_array[i];
max = i;
}
}

//初始化data数组
data = new int[ARRAY_NUM][len];

//产生数据
for(int i = 0 ; i < ARRAY_NUM ; i ++)
for(int j = 0 ; j < len_array[i] ; j ++)
data[i][j] = (int) ( Math.random() * DATA_MAX_VALUE);

//辅助数组的大小
copy = new int[len];
temp = new int[max];

}

/**
* 调用系统的排序进行排序,因为这个题目重点不在于排序
*
* */
private static void simpleSort(int [] [] data){
//引入temp的原因是因为对data[]排序的时候回将默认赋值的000全部排序到前面
for(int i = 0 ; i < data.length ;i ++){
temp = Arrays.copyOfRange(data[i], 0, len_array[i]);
Arrays.sort(temp);
for(int j = 0 ; j < temp.length ; j ++)
data[i][j] = temp[j];
}
}

/**
* 用于测试输出所要排序的数据
*
* */
private static void showData(int [][] data){
for (int i = 0 ; i < len_array.length ; i ++) {
for(int j = 0 ; j < len_array[i]; j ++)
System.out.print(data[i][j]+" ");
System.out.println();
}
}

//找出最小的两个数组下标
private static void findMin(){
System.out.println("-------------------------------------------------------------------------------------------------");
for (int i : len_array) {
System.out.print(i+"  ");
}
System.out.println("\n-------------------------------------------------------------------------------------------------");
int min = Integer.MAX_VALUE;
//别把len_array设置为长度1的数组
for(int  i = 0 ; i < len_array.length ; i ++){
if(len_array[i] == -1)
continue;
if(len_array[i] < min){
min = len_array[i];
l = i;
}
}
int min2 = Integer.MAX_VALUE;
for(int  i = 0 ; i < len_array.length ; i ++){
if(len_array[i] == -1)
continue;
if(i == l)
continue;
if(len_array[i] < min2){
min2 = len_array[i];
r = i;
}
}

}

/**
* 合并数据并且对比较的次数进行统计
*
* */
private static void merge(){
findMin();
merge(l, r);
//已经完成合并,就返回
if(check() == 1){
return ;
}
//未完成继续合并
merge();

}

/**
* 检测是否已经合并完成
* @return 如果返回的数字为1,则表示已经合并完成,大于等于2表示还需要继续合并
*
* */
private static int check(){
int c = 0;
for (int i : len_array) {
if(i != -1)
c++;
}
return c;
}

/**
* 合并给出的两个下标的数组
* */
private static void merge(int left , int right){
System.out.println("合并"+left+"—"+right+"-->"+left);
count += len_array[left] + len_array[right] - 1 ;
int i = 0,j = 0;
int k = 0;
while(i < len_array[left] || j < len_array[right]){
if(i == len_array[left] ){
copy[k++] = data[right][j++];
continue;
}
if(j == len_array[right]){
copy[k ++] = data[left][i++];
continue;
}

int min = data[left][i];
if(data[right][j] < min){
copy[k ++] = data[right][j++];
}else{
copy[k ++] = data[left][i++];
}
}
int _length = len_array[left] + len_array[right] ;

//赋值给left所在的数组
for(int m = 0 ; m < _length ; m++){
data[left][m] = copy[m] ;
}

//将left的长度为新的组合之后的长度,right改为-1就是遍历的时候跳过改组
len_array[left] = _length ;
len_array[right] = -1;

}

public static void main(String[] args) {
init();
//遍历每个数组,查看数据
System.out.println("------------------------------------before-------------------------------------------------------");
showData(data);
//调用排序
simpleSort(data);
System.out.println("---------------------------------after sort---------------------------------------------------");
showData(data);
//开始合并
merge();

//已经合并好了
int index = 0;
for(int i = 0 ; i < len_array.length ; i ++){
if(len_array[i] != -1)
index = i;
}

System.out.println("-------------------------------------after merge----------------------------------------------");
System.out.println("一共合并的次数为:"+count+"\nps:这个合并次数不为实际合并次数,而是最坏的情况下的合并次数,合并后的数组如下:\n");
for (int d : data[index]) {
System.out.print(" "+d);
}
}

}


运行结果:



Before表示随机生成的数据,after则是排序过后的满足题目条件的序列S1到S5然后后续的表示序列的长度(已经排序过的废弃的序列下标设置为-1,到时候遍历的时候跳过)after merge表示合并之后的数据排序,一共合并次数不为实际合并次数,最坏情况。

如有错误,请指出。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: