外排序

适用环境:文件过大,内存限制为一次只能读取部分数据

本例是个简单的外排序,相对排序效率过低,10000条数据排序时间在1000ms左右,仅作学习理解用

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * <p>
 * 外排序算法 适用环境:文件过大,内存一次性不能装下
 * </p>
 * 
 * @author Administrator
 * 
 */
public class OutSort {
	public static void main(String[] args) throws Exception {
		File f = new File("src/input.data");
		File tempFile = new File("src/temp.data");
		if (!tempFile.exists()) {
			tempFile.createNewFile();
		}
		File destFile = new File("src/dest.data");
		if (!destFile.exists()) {
			destFile.createNewFile();
		}
		outSort(f, tempFile, destFile, 50 , 25);
	}

	/**
	 * <p>
	 * 外排序,源文件中一行为个排序对象 读取指定行数的文件,放入数组/集合中进行排序,然后输出到临时文件中
	 * </p>
	 * 
	 * @param sourceFile
	 *            源文件
	 * @param tempFile
	 *            临时文件
	 * @param destFile
	 *            结果文件
	 * @param pageSize
	 *            读取页面大小(可以理解成把原始文件分成若干个子文件)
	 * @param num
	 * 			  从临时子文件中加载的对象个数	           
	 * @throws Exception
	 */
	public static void outSort(File sourceFile, File tempFile, File destFile,
			int pageSize,int num) throws Exception {
		BufferedReader bufferedReader = new BufferedReader(new FileReader(
				sourceFile));
		// 将原文件分段排序后将记录每个分段信息的数据保存下来
		List<OutSort.SortFile> sortfiles = new ArrayList<OutSort.SortFile>();
		List<String> list = new ArrayList<String>();
		BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(
				tempFile));
		// 已经读取的记录行数
		long size = 0;
		// 已经读取的总行数
		long hasedReadLine = 0;
		// 已经读取的总字节数
		long bytesize = 0;
		// 第几个分段文件
		int fileNum = 0;
		// 要跳过的字节数
		long skipByte = 0;
		while (bufferedReader.ready()) {
			// 读取一行
			String s = bufferedReader.readLine();
			list.add(s);
			size++;
			hasedReadLine++;
			if (size == pageSize) {
				// 生成分段对象,并保存分段信息
				SortFile file = new SortFile(fileNum * pageSize + 1,
						hasedReadLine, skipByte, num);
				sortfiles.add(file);
				fileNum++;
				// 排序
				Collections.sort(list);
				for (String str : list) {
					str = str + "\n";
					bytesize += str.getBytes().length;
					bufferedWriter.write(str);
				}
				// 要跳过的字节数
				skipByte = bytesize;
				// 下入文件
				bufferedWriter.flush();
				size = 0;
				// 清除分段内容,以便下一个分段使用
				list.clear();
			}
		}
		// 余下不满一页的分段数据
		if (size < pageSize && size > 0) {
			SortFile file = new SortFile(fileNum * pageSize + 1, hasedReadLine,
					skipByte, num);
			sortfiles.add(file);
			Collections.sort(list);
			for (String str : list) {
				bufferedWriter.write(str + "\n");
			}
			bufferedWriter.flush();
		}
		bufferedWriter.close();

		// 从分开子文件对象中分别取出1个进行排序,将最小的写入结果文件,并在指定文件再读取一条记录
		BufferedWriter writer = new BufferedWriter(new FileWriter(destFile));
		for (SortFile sort : sortfiles) {
			// 初始化读到内存中的数据
			sort.readLine(tempFile);
		}
		// 初始化排序中间集合
		List<SortObject> resultSort = new ArrayList<SortObject>();
		for (SortFile sort : sortfiles) {
			resultSort.add(sort.removeElement(tempFile));
		}
		long begin = System.currentTimeMillis();
		System.out.println(begin);
		// 排序并写入目标文件
		while (hasedReadLine > 0) {
			// 排序
			Collections.sort(resultSort);
			// 写入第一个元素
			SortObject sortObject = resultSort.remove(0);
			writer.write(sortObject.getValue() + "\n");
			hasedReadLine--;
			if (hasedReadLine % 1000 == 0) {
				writer.flush();
			}
			// 移除子文件对象中对应数据
			sortObject = sortObject.getKey().removeElement(tempFile);
			if (sortObject != null) {
				resultSort.add(sortObject);
			}
		}
		writer.flush();
		writer.close();
		long end = System.currentTimeMillis();
		System.out.println(end - begin);
	}

	private static class SortObject implements Comparable<SortObject> {
		// 值
		private final String value;
		// 键
		private final SortFile key;

		public SortObject(SortFile key, String value) {
			this.key = key;
			this.value = value;
		}

		public SortFile getKey() {
			return key;
		}

		public String getValue() {
			return value;
		}

		public int compareTo(SortObject o) {
			return value.compareTo(o.getValue());
		}
	}

	private static class SortFile {
		// 开始读取位置指针
		private long startCursor;
		// 结束位置指针
		private final long endCursor;
		// 要跳过的字节数
		private long byteSize;
		// 每次读取到内存中的元素个数
		private final int num;
		// 读取到内存中元素的集合
		private final List<SortObject> sortObjects;

		/**
		 * @param startCursor
		 *            开始指针位置
		 * @param endCursor
		 *            结束指针位置
		 * @param byteSize
		 *            要跳过的字节数
		 * @param num
		 *            每次读取到内存中的元素个数
		 */
		public SortFile(long startCursor, long endCursor, long byteSize, int num) {
			this.endCursor = endCursor;
			this.startCursor = startCursor;
			this.byteSize = byteSize;
			this.num = num;
			sortObjects = new ArrayList<OutSort.SortObject>();
		}

		/**
		 * 移除元素,如果是最后一个,则填充
		 * 
		 * @throws Exception
		 */
		public SortObject removeElement(File tempFile) throws Exception {
			SortObject object = null;
			if (sortObjects.size()>0 && sortObjects.get(0) != null) {
				object = sortObjects.remove(0);
				if (sortObjects.size() == 0) {
					readLine(tempFile);
				}
			}
			return object;
		}

		// 读取下一行数据
		public List<SortObject> readLine(File tempFile) throws Exception {
			if (startCursor > endCursor) {
				return null;
			}
			BufferedReader reader = new BufferedReader(new FileReader(tempFile));
			// 清空读取到内存中的数据,理论上已经清空了
			sortObjects.clear();
			// 跳过指定的字节数
			reader.skip(byteSize);
			for (int i = 0; i < num; i++) {
				if (startCursor <= endCursor) {
					String str = reader.readLine();
					SortObject object = new SortObject(this, str);
					sortObjects.add(object);
					byteSize += (str + "\n").getBytes().length;
					++startCursor;
				}
			}
			return sortObjects;
		}

	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
牙科就诊管理系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的Mysql数据库进行程序开发。实现了用户在线查看数据。管理员管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等功能。牙科就诊管理系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 管理员在后台主要管理病例管理、字典管理、公告管理、药单管理、药品管理、药品收藏管理、药品评价管理、药品订单管理、牙医管理、牙医收藏管理、牙医评价管理、牙医挂号管理、用户管理、管理员管理等。 牙医列表页面,此页面提供给管理员的功能有:查看牙医、新增牙医、修改牙医、删除牙医等。公告信息管理页面提供的功能操作有:新增公告,修改公告,删除公告操作。公告类型管理页面显示所有公告类型,在此页面既可以让管理员添加新的公告信息类型,也能对已有的公告类型信息执行编辑更新,失效的公告类型信息也能让管理员快速删除。药品管理页面,此页面提供给管理员的功能有:新增药品,修改药品,删除药品。药品类型管理页面,此页面提供给管理员的功能有:新增药品类型,修改药品类型,删除药品类型。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值