【问题】
对一百万个不相同的数字进行排序,要求时间复杂度O(1),空间复杂度尽可能小!
【分析】
大数据的排序问题,首选方法是“归并”,之前我也写过十亿个数的归并排序算法,且在此基础上的优化方案——大范围内归并小范围内插入排序等等,但本文有一个时间复杂度的要求,归并排序的时间复杂度是O(nlgn),因此我们尝试一种新闻排序算法——“bit排序法”。
“bit排序法”——待排序的数作为bit位的下标,当前位置的bit置为1,一轮遍历待排序数之后,打印出所有当前数值为1的数字下标。
最小的数据结构单位是byte,因此处理起来稍微麻烦了一点
【代码】
package com.hhf;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* bit排序法
* @author HHF
* 2015年11月17日17:12:37
* @version 1.0 只支持不同数据的排序
*/
public class PhoneNumSort {
private static String path = "E:/phoneNum.txt";
private static String resultPath = "E:/phoneNumResult.txt";
private int size = 1000000;
public static void main(String[] args) {
PhoneNumSort phoneNumSort = new PhoneNumSort();
//生成不相同的一百万个数
phoneNumSort.createNumber(phoneNumSort.size);
//统计排序数大小
int bitSize = phoneNumSort.countLineSize(path);
//用来保存数据--数组的下标为n,表示数据为8*(n-1)+k
byte[] byteData = new byte[bitSize/8 + 1];
phoneNumSort.setByteData(byteData);
}
/**
* 读取文件,并将文件中数值对应到byte类型的打他中去
* @param byteData
*/
private void setByteData(byte[] byteData){
int index = 0;
int n = 0;//第几行
int k = 0;//第几位
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String str = br.readLine();
while(str!=null){
index = new Integer(str);//bit中的下标
n = index/8;
k = index%8;
//设置当前位置的值为1
byteData[n] += getAddNum(k);
str = br.readLine();
}
br.close();
StringBuffer content = new StringBuffer();
for(int i=byteData.length-1; i>-1; i--){
if(byteData[i]>=128){
byteData[i] -= 128;
content.append(8*i + 8).append("\n");
}
if(byteData[i]>=64){
byteData[i] -= 64;
content.append(8*i + 7).append("\n");
}
if(byteData[i]>=32){
byteData[i] -= 32;
content.append(8*i + 6).append("\n");
}
if(byteData[i]>=16){
byteData[i] -= 16;
content.append(8*i + 5).append("\n");
}
if(byteData[i]>=8){
byteData[i] -= 8;
content.append(8*i + 4).append("\n");
}if(byteData[i]>=4){
byteData[i] -= 4;
content.append(8*i + 3).append("\n");
}
if(byteData[i]>=2){
byteData[i] -= 2;
content.append(8*i + 2).append("\n");
}
if(byteData[i]>=1){
content.append(8*i + 1).append("\n");
}
}
storeDataToFile(resultPath, content.toString().getBytes());
System.out.println(System.currentTimeMillis()+"--排序结果已经写入文件");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 获得每个位置上对应应该要加的数值
* @param pos 位置
* @return 返回该位置对应的数
*/
private int getAddNum(int pos){
if(pos>0 && pos<9){
return 1<<(pos-1);
}else{
return 0;
}
}
/**
* 读取文章的行数
* @param path 文件路径
* @return size 数据量
*/
private int countLineSize(String path){
int count = 0;
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String str = br.readLine();
while(str!=null){
count++;
str = br.readLine();
}
br.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+"--待排序的数据量是"+count);
return count;
}
/**
* 生成指定数量的数据
* @param path 文件的路径
* @param size 数据数量
*/
private void createNumber(int size){//还是需要先 定义InputStream输入流对象
if(size < 1){
return;
}
StringBuffer content = new StringBuffer();
for(int i=1; i<=size; i++){
content.append(i).append("\n");
}
storeDataToFile(path, content.toString().getBytes());
System.out.println(System.currentTimeMillis()+"--文件创建结束 共生成了数据 "+size+" 条");
}
/**
* 将数据存储到文件中
* @param path
* @param content
*/
private void storeDataToFile(String path, byte[] content){
File file = new File(path);
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
java.io.OutputStream os = new java.io.FileOutputStream(path);
java.io.BufferedOutputStream bos = new java.io.BufferedOutputStream(os);
bos.write(content);
bos.flush();// 将缓冲区中的内容强制全部写入到文件中(不管是否已经全部写入)有点类似于下面的语句
bos.close();
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
--------相关推荐文章---------
《10亿个字符串的排序问题》http://java--hhf.iteye.com/admin/blogs/2166129
《大范围归并小范围插入排序》http://java--hhf.iteye.com/admin/blogs/2163465