位圖排序算法的一個實踐

適應場景:
1,輸入的數據限制在相對較小的範圍內;2,數據沒有重複;3,對於每條記錄而言,除了單一整數外,沒有任何其他相關聯的數據。

2,要求
輸入:一個最多包含n個正整數的文件F1,每個數小於n(n=1000000),而且整數沒有重複;
輸出:包含按升序排列的整數列表的文件F2;
約束:不超過1M的內存空間,運行時間10秒以內。

3,實現概要
可以用一個20位長度的0,1字符串來表示所有元素小於20的非負整數的集合。比如可以用下面的字符串來標示集合{1,2,3,5,8,13}:
S={0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 }
即S[1],S[2],S[3],S[5],S[8],S[13]都是1,其他的都是0.

利用上面的思想,可以用一個長度爲n的字符串來表示文件F1裏面的整數集合,然後遍歷這個字符串,如果爲1則輸出下標的文件F2.
僞代碼:
//初始化
for i=[0,n)
  bit[i]=0;
//掃描輸入文件
for each i in F1
   bit[i]=1;
//輸出
for each i=[0,n)
  if bit[i]==1
     write i to F2

我用java做了這個算法的實踐,bit 數組採用的是JDK裏面的BitSet,代碼如下:


	public static void main(String[] args) throws IOException {
		int n = 10000000;
		int k = 1000000;
		String srcFile = "/tmp/in.dat";
		String destFile = "/tmp/out.dat";
		long start = System.currentTimeMillis();
		genRandomNumbers2File(srcFile, n, k);
		sortAndSave2File(srcFile, destFile, n);
		long end = System.currentTimeMillis();
		System.out.println("Done in " + (end - start) + " ms");
	}

	/**
	 * 在文件fileName中生成一個所有元素互異且位於[0,n)之間的隨機排列的整數序列,序列長度爲k
	 * 
	 * @param fileName
	 * @param n
	 * @param k
	 * @throws IOException
	 */
	public static void genRandomNumbers2File(String fileName, int n, int k)
			throws IOException {
		File f = new File(fileName);
		if (!f.exists()) {
			f.createNewFile();
		}
		BufferedOutputStream bos = null;
		try {
			bos = new BufferedOutputStream(new FileOutputStream(f));
			int[] array = new int[n];// 定義初始數組
			for (int i = 0; i < n; i++)
				array[i] = i;
			Random random = new Random();
			for (int j = 0; j < k; j++) {
				int index = j + random.nextInt(n - j);// 生成一個[j,n)之間的隨機數,作爲數組下標
				// 交換array[j]和array[index],那麼array[0..j]爲已經獲取到的隨機數
				int temp = array[index];
				array[index] = array[j];
				array[j] = temp;
				// 把此次獲取到的隨機數存到rets裏面
				bos.write(temp);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (bos != null) {
				bos.close();
			}
		}
	}
	//從文件srcFile讀取整數序列然後排序,並寫到的destFile中
	public static void sortAndSave2File(String srcFile, String destFile, int n)
			throws IOException {
		File fsrc = new File(srcFile);
		File fdest = new File(destFile);
		if (!fdest.exists()) {
			fdest.createNewFile();
		}
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(fsrc));
			BitSet bs = new BitSet(n);
			int read = 0;
			while ((read = bis.read()) != -1) {
				bs.set(read);
			}
			//
			bos = new BufferedOutputStream(new FileOutputStream(fdest));
			for (int i = 0; i < n; i++) {
				if (bs.get(i)) {
					// System.out.println(i);
					bos.write(i);
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (bos != null) {
				bos.close();
			}
			if (bis != null) {
				bis.close();
			}
		}
	}


此博客的算法思想來源於《編程珠璣(第二版)》第一章


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章