04-排序【选择排序】算法学习
- 思想:每次从数组中选取最小的元素,依次加入新数组中。
- 操作:比较
- 是否稳定排序:是
- 是否原地排序:否
- 时间复杂度:O(n²)
- 最好时间复杂度:O(n²)
- 最坏时间复杂度:O(n²)
- 平均时间复杂度:O(n²)
- 空间复杂度:O(1)
总结:选择排序顾名思义,每次遍历选择一个最小的元素,思想非常简单。
实现代码略
场景:对30个日志文件,每个文件大小约1G,均是按照时间戳大小顺序排列,现机器内存为2G,如何快速将这些日志文件合并为一个日志文件,并要求合并后的日志文件也是按照时间戳大小排序。
实现代码(java)含义解释如下:
-
resume(String initDate, int fileCount)方法:用于生成所需的30个日志文件。
-
readFile(List<File> fileList)方法:合并日志文件。
-
思想:为每个日志文件建立一个引用(指针),按照归并排序的思想读取一条最小的元素,写入合并文件中。
-
注意:耗时较长,为了演示,可以修改示例代码日志大小为1M,文件数为30。
package com.cheng2839.test.$sa; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Description * @Author cheng2839 * @Date * @Version v1.0 */ public class FileHandleDemo { public static final String DIR_FILE = "E:\0test\"; public static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); public static final long RAND_MAX = 60 * 1000;
//生成fileCount个日志文件(每个日志文件为1G),起始日期为:initDate(如:2020-01-01 00:00:00.000) public static void resume(String initDate, int fileCount) throws ParseException, IOException { while (fileCount > 0) { File file = new File(DIR_FILE, fileCount + ".log"); if (!file.exists()) { file.createNewFile(); } BufferedWriter bw = new BufferedWriter(new FileWriter(file)); long initDateLong = sdf.parse(initDate).getTime(); while (file.length() < 1024 * 1024 * 1024) { initDateLong += (long) (Math.random() * RAND_MAX); bw.write(sdf.format(initDateLong)); bw.newLine(); } bw.flush(); bw.close(); fileCount--; } } public static void main(String[] args) { try { int fileCount = 30; //resume("2020-01-01 00:00:00.000", fileCount); List<File> fileList = new ArrayList<>(); for (int i = 1; i <= fileCount; i++) { fileList.add(new File(DIR_FILE, i + ".log")); } readFile(fileList); } catch (Exception e) { e.printStackTrace(); } } //按照时间戳(如:2020-01-01 00:00:00.000),将日志文件列表进行合并 public static void readFile(List<File> fileList) throws Exception { BufferedWriter writer = new BufferedWriter(new FileWriter(new File(fileList.get(0).getParent(), "result.log"))); Map<BufferedReader, String> readerMap = new HashMap(); for (File file : fileList) { BufferedReader reader = new BufferedReader(new FileReader(file)); readerMap.put(reader, reader.readLine()); } String line; while ((line = getLine(readerMap)) != null) { writer.write(line); writer.newLine(); } writer.flush(); writer.close(); for (BufferedReader reader : readerMap.keySet()) { reader.close(); } } //从文件指针集合中,读取一个最小的时间戳日志行 public static String getLine(Map<BufferedReader, String> readerMap) throws Exception { String insertLine = null; BufferedReader insertReader = null; for (BufferedReader br : readerMap.keySet()) { String tmpLine = readerMap.get(br); if (tmpLine == null) continue; if (insertLine == null) { insertLine = tmpLine; insertReader = br; } if (sdf.parse(insertLine).getTime() > sdf.parse(tmpLine).getTime()) { insertLine = tmpLine; insertReader = br; } } if (insertLine != null && insertReader != null) { readerMap.put(insertReader, insertReader.readLine()); } return insertLine; } }