10^n个整数(亿级)的排序

输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且n=10^7
输出:得到按从小到大升序排列的包含所有输入的整数的列表。

《编程珠玑》中提出的问题,有三种解法:

(1)磁盘合并排序

先将所有数据分成多个小文件,多个小文件采用内部排序后,再用多路合并排序完成排序输出。

        总数据为n, 内存中采用内部排序最多m。先分成n/m个小文件,再内部排序,第三部读取所有小文件,每次将最小的数输出即可。

(2)多通道

0~10^k-1

10^k~2*10^k-1

...

分成m个通道,读m次,每次读取在通道范围内的数,按顺序写到对应的输出文件,完成排序。

(3)bitmap排序

在内存中开10^7比特,均初始化为0,若出现则设置为1,输出为1的数即可。


下面详细讨论对应的解法。转自http://blog.csdn.net/v_july_v/article/details/6451990

第一节、如何给磁盘文件排序
问题描述:
输入:一个最多含有n个不重复的正整数(也就是说可能含有少于n个不重复正整数)的文件,其中每个数都小于等于n,且n=10^7
输出:得到按从小到大升序排列的包含所有输入的整数的列表。
条件:最多有大约1MB的内存空间可用,但磁盘空间足够。且要求运行时间在5分钟以下,10秒为最佳结果。

分析:下面咱们来一步一步的解决这个问题,
    1
、归并排序。你可能会想到把磁盘文件进行归并排序,但题目要求你只有1MB的内存空间可用,所以,归并排序这个方法不行。
    2
、位图方案。熟悉位图的朋友可能会想到用位图来表示这个文件集合。例如正如编程珠玑一书上所述,用一个20位长的字符串来表示一个所有元素都小于20的简单的非负整数集合,边框用如下字符串来表示集合{1,2,3,5,8,13}

0 1 1 1 0 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0

上述集合中各数对应的位置则置1,没有对应的数的位置则置0

    参考编程珠玑一书上的位图方案,针对我们的10^7个数据量的磁盘文件排序问题,我们可以这么考虑,由于每个7位十进制整数表示一个小于1000万的整数。我们可以使用一个具有1000万个位的字符串来表示这个文件,其中,当且仅当整数i在文件中存在时,第i位为1。采取这个位图的方案是因为我们面对的这个问题的特殊性:1、输入数据限制在相对较小的范围内,2、数据没有重复,3、其中的每条记录都是单一的整数,没有任何其它与之关联的数据。
   
所以,此问题用位图的方案分为以下三步进行解决:

  • 第一步,将所有的位都置为0,从而将集合初始化为空。
  • 第二步,通过读入文件中的每个整数来建立集合,将每个对应的位都置为1。
  • 第三步,检验每一位,如果该位为1,就输出对应的整数。

    经过以上三步后,产生有序的输出文件。令n为位图向量中的位数(本例中为1000 0000),程序可以用伪代码表示如下:

//磁盘文件排序位图方案的伪代码  
//copyright@ Jon Bentley  
//July、updated,2011.05.29。  
  
//第一步,将所有的位都初始化为0  
for i ={0,....n}      
   bit[i]=0;  
//第二步,通过读入文件中的每个整数来建立集合,将每个对应的位都置为1。  
for each i in the input file     
   bit[i]=1;  
  
//第三步,检验每一位,如果该位为1,就输出对应的整数。  
for i={0...n}      
  if bit[i]==1        
    write i on the output file  

    上面只是为了简单介绍下位图算法的伪代码之抽象级描述。显然,咱们面对的问题,可不是这么简单。下面,我们试着针对这个要分两趟给磁盘文件排序的具体问题编写完整代码,如下。

//copyright@ yansha  
//July、2010.05.30。  
//位图方案解决10^7个数据量的文件的排序问题  
//如果有重复的数据,那么只能显示其中一个 其他的将被忽略  
#include <iostream>  
#include <bitset>  
#include <assert.h>  
#include <time.h>  
using namespace std;  
  
const int max_each_scan = 5000000;  
  
int main()  
{  
    clock_t begin = clock();  
    bitset<max_each_scan> bit_map;  
    bit_map.reset();  
      
    // open the file with the unsorted data  
    FILE *fp_unsort_file = fopen("data.txt", "r");  
    assert(fp_unsort_file);  
    int num;  
  
    // the first time scan to sort the data between 0 - 4999999  
    while (fscanf(fp_unsort_file, "%d ", &num) != EOF)  
    {  
        if (num < max_each_scan)  
            bit_map.set(num, 1);  
    }  
      
    FILE *fp_sort_file = fopen("sort.txt", "w");  
    assert(fp_sort_file);  
    int i;  
      
    // write the sorted data into file  
    for (i = 0; i < max_each_scan; i++)  
    {  
        if (bit_map[i] == 1)  
            fprintf(fp_sort_file, "%d ", i);  
    }  
      
    // the second time scan to sort the data between 5000000 - 9999999  
    int result = fseek(fp_unsort_file, 0, SEEK_SET);  
    if (result)  
        cout << "fseek failed!" << endl;  
    else  
    {  
        bit_map.reset();  
        while (fscanf(fp_unsort_file, "%d ", &num) != EOF)  
        {  
            if (num >= max_each_scan && num < 10000000)  
            {  
                num -= max_each_scan;  
                bit_map.set(num, 1);  
            }  
        }  
        for (i = 0; i < max_each_scan; i++)  
        {  
            if (bit_map[i] == 1)  
                fprintf(fp_sort_file, "%d ", i + max_each_scan);  
        }  
    }  
      
    clock_t end = clock();  
    cout<<"用位图的方法,耗时:"<<endl;  
    cout << (end - begin) / CLK_TCK << "s" << endl;  
    fclose(fp_sort_file);  
    fclose(fp_unsort_file);  
    return 0;  
}  

 而后测试了一下上述程序的运行时间,采取

  • 1
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
快速排序法是一种常用的排序算法,其基本思想是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序的目的。 以下是将n个整数用快速排序排序的C语言代码: ```c #include <stdio.h> void quick_sort(int arr[], int left, int right) { int i, j, pivot, temp; if (left < right) { i = left; j = right; pivot = arr[left]; while (i < j) { while (i < j && arr[j] >= pivot) { j--; } if (i < j) { arr[i++] = arr[j]; } while (i < j && arr[i] < pivot) { i++; } if (i < j) { arr[j--] = arr[i]; } } arr[i] = pivot; quick_sort(arr, left, i - 1); quick_sort(arr, i + 1, right); } } int main() { int n, i; printf("Enter the number of elements: "); scanf("%d", &n); int arr[n]; printf("Enter %d elements:\n", n); for (i = 0; i < n; i++) { scanf("%d", &arr[i]); } quick_sort(arr, 0, n - 1); printf("Sorted array:\n"); for (i = 0; i < n; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } ``` 在上述代码中,`quick_sort()`函数实现了快速排序的核心算法,其中`arr[]`为待排序的数组,`left`和`right`分别为待排序部分的最左边和最右边的下标。首先取数组的第一个元素为枢轴元素`pivot`,然后将待排序部分分为两个子部分,左侧子部分的元素都小于等于枢轴元素,右侧子部分的元素都大于枢轴元素。重复以上步骤直到待排序部分的元素数量为1。最后,将所有子部分的元素合并即可得到排序后的数组。 在`main()`函数中,先读入待排序数组的元素个数`n`和元素值,然后调用`quick_sort()`函数进行排序,最后输出排序后的数组结果。 需要注意的是,在C语言中,数组的下标从0开始。因此,在`quick_sort()`函数中,对于待排序部分的最左边和最右边的下标,应该分别为0和n-1。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值