問題:linux
一個文件有8*106個正整數,每一個數都小於107。文件中全部整數都是惟一的。要求對這些整數排序,按升序把排序的結構輸出到磁盤上。ios
解決問題的方案有不少,下面咱們介紹幾種典型的方案。數組
一、高效的「位圖排序」函數
特殊要求:最多有大約1M的內存空間可用!測試
若是在這個限制下,快速的對這些整數進行排序,一個優秀的解決方案是使用「位圖排序」。spa
位圖排序的思想就是在內存中申請一塊連續的空間做爲位圖,初始時將位圖的每一位都置爲0。而後依次讀取待排序的整數,將整數對應的位設置爲1。最後按順序掃描位圖,若是某一位爲1,輸出到已排序文件。命令行
好比待排序的數據S={3,0,4,1,7,2,5},最大爲7,咱們能夠設置一個八位的位圖B,將位圖的每一位初始爲0。對S中的每個整數d,設置B[d]=1,即B=[1,1,1,1,1,1,0,1],最後掃描位圖,對位圖的每一位i,若是B[i]==1,則輸出i到已排序文件,排序後的S={0,1,2,3,4,5,7}。指針
整個過程只須要遍歷一遍待排序文件和位圖,時間複雜度O(n),須要的輔助空間爲(max(S)/8)字節。code
程序代碼:blog
bitmap_sort.c
#include <stdio.h> #include "data_size.h" #define SHIFT 5 #define MASK 0x1F int a[1+MAX_DATA/32]; void set(int i) { a[i>>SHIFT] |=1<<(i& MASK ); } int test(int i) { return a[i>>SHIFT] & (1<<(i& MASK )); } int main(int argc,char** argv) { int i=0; FILE *fin=NULL,*fout=NULL; for(i=0;i<1+MAX_DATA/32;i++) a[i]=0; if((fin=fopen(argv[1],"r"))==NULL) { printf("error!\n"); return 1; } while(fscanf(fin,"%d",&i)!=EOF) set(i); if((fout=fopen(argv[2],"w"))==NULL) { printf("error!\n"); return 1; } for(i=0;i<MAX_DATA;i++) if(test(i)) fprintf(fout,"%d\n",i); fclose(fin); fclose(fout); return 0; }
data_size.h
#ifndef DATA_SIZE_H_ #define DATA_SIZE_H_ #define SIZE 8000000 #define MAX_DATA 10000000 #endif
生產待排序文件數據的程序見附錄。
測試(用time命令統計運行時間):(2次)
編譯以後的可執行程序:bitmapsort 待排序文件:data.txt 輸出文件:data2.txt
注:linux的time統計程序的運行時間,其統計結果包含如下數據:
1)實際時間(real time): 從command命令行開始執行到運行終止的消逝時間;
2)用戶CPU時間(user CPU time): 命令執行完成花費的用戶CPU時間,即命令在用戶態中執行時間總和;
3)系統CPU時間(system CPU time): 命令執行完成花費的系統CPU時間,即命令在覈心態中執行時間總和
二、linux排序命令
$ time sort -n -o data3.txt data.txt
使用linux的sort命令進行排序。
-n :使用「純數字」進行排序(默認是以文字型態來排序的);
-o : 把排序結果輸出到文件,而不是控制檯
測試:(2次測試)
待排序文件:data.txt 輸出文件:data3.txt
三、C標準庫的qsort()函數
qsort包含在<stdlib.h>頭文件中,此函數根據你給的比較條件進行快速排序,經過指針移動實現排序。排序以後的結果仍然放在原數組中。使用qsort函數必須本身寫一個比較函數。
函數原型:
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
base :數組起始地址
num:數組元素個數
siz:每個元素的大小
comparator:函數指針,指向比較函數
qsort.c
#include <stdio.h> #include <stdlib.h> #include "data_size.h" int intcomp(const void *x, const void *y) { return *(int *)x-*(int *)y; } int a[SIZE]; int main(int argc, char** argv) { FILE *fin=NULL,*fout=NULL; if((fin=fopen(argv[1],"r"))==NULL) { printf("open file error!\n"); return 1; } int i=0; while(fscanf(fin,"%d",&a[i])!=EOF) i++; qsort(a,SIZE,sizeof(int),intcomp); if((fout=fopen(argv[2],"w"))==NULL) { printf("open file error!\n"); return 1; } for(i=0;i<SIZE;i++) fprintf(fout,"%d\n",a[i]); return 0; }
測試:(2次)
編譯以後的可執行程序:qsort 待排序文件:data.txt 輸出文件:data4.txt
四、C++標準庫中set容器來進行排序
由於待排序的整數都是惟一的,而且set容器內部會按照必定的順序組織內部的數據。咱們能夠用set容器來進行排序。
set_sort.cpp
#include <iostream> #include <fstream> #include <set> using namespace std; int main(int argc,char **argv) { int i=0,n=0; set<int> s; set<int>::iterator it; ifstream in(argv[1]); if(!in.is_open()) { cout<<"error"<<endl; return 1; } while(!in.eof()) { in>>n; s.insert(n); } ofstream out(argv[2]); if(!out.is_open()) { cout<<"error"<<endl; return 1; } for(it=s.begin();it!=s.end();++it) { out<<*it<<endl; } in.close(); out.close(); return 0; }
測試:
編譯以後的可執行程序:set_sort 待排序文件:data.txt 輸出文件:data5.txt
總結
上面四個程序的排序結果都正確,已用diff命令對比過。
從上面的運行時間,咱們能夠看出:
位圖排序、C標準庫qsort(排序)、系統命令排序、C++標準庫set容器排序,它們的排序運行時間依次增高。
在特殊要求「最多有大約1M的內存空間可用!」的狀況下,位圖排序是一個很是優秀的排序方法,其運行速度快且佔用內存小,可是前提是,待排序的數據都是整數,且不存在重複。
附錄:
生產包含8*106個正整數 且 每一個數都小於107的排序文件。
#include <stdio.h> #include <stdlib.h> #include <time.h> #include "data_size.h" int a[MAX_DATA]; void swap(int i,int j) { int temp=a[j]; a[j]=a[i]; a[i]=temp; } int main(int argc, char **argv) { int i=0; printf("%x\n",RAND_MAX); printf("%ld\n",time(NULL)); srand(time(NULL)); for(i=0;i<MAX_DATA;i++) { a[i]=i; } for(i=0;i<SIZE;i++) { int j=rand()%MAX_DATA; swap(i,j); } FILE * fin=NULL; if((fin=fopen(argv[1],"w"))==NULL) { printf("error!\n"); return 1; } for(i=0;i<SIZE;i++) { fprintf(fin,"%d\n",a[i]); } fclose(fin); printf("success!\n"); return 0; }