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表示合并之后的数据排序,一共合并次数不为实际合并次数,最坏情况。
如有错误,请指出。
相关文章推荐
- 给定n个矩阵{A1, A2, …,An},其中,Ai与Ai+1是可乘的,计算这n个矩阵的连乘积。从中找出一种乘次数最少的计算次序(矩阵连乘最优顺序Java语言实现
- 二分查找过程、比较次数分析、java实现
- JAVA中各类CACHE机制实现的比较
- 用Java实现文件分割/合并操作
- 实现Java中对象比较的两个方法
- 最小生成树-Kruskal算法 java代码实现
- 最小生成树-Kruskal算法 java代码实现
- 用Java简单实现文件分割与合并
- W. :利用最小优先级队列实现对k个已序队列的合并排序。习题6.5-8
- JAVA 实现文件分割与合并
- 最小生成树prim java 实现
- java实现合并两个数组
- JAVA中实现比较的方法
- 用Java实现文件分割/合并操作
- Java中合并XML文档 设计与实现
- Java报表工具及报表实现方案性能比较
- JAVA中各类CACHE机制实现的比较
- Java中合并XML文档的设计与实现
- java 实现文件简单比较
- JAVA简单实现不区分大小写以及空格比较字符串