算法学习

大数据取前x个最大值方法:

    小顶堆,这是一种完全二叉树的顺序储存结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择元素。也可使用大顶堆来获取最小值。

void HeapAdjust(int data[],int nStart, int nLen)  
{  
    int pos;  
    int Temp;  
  
    while ((2*nStart+1) < nLen)  
    {  

        //比较左子树和右子树,记录小的Index  

        if ( (2*nStart+2) > nLen)  
        {  

            pos = 2*nStart+1;  //无右子树

        }  
        else
         {
            pos = data[2*nStart+1] > data[2*nStart+2] ? 2*nStart+2 : 2*nStart+1;            
         }
        //change data  
        if (data[nStart] > data[pos])  
        {  
            //交换nStart与pos的数据  
            Temp = data[nStart];  
            data[nStart] = data[pos];  
            data[pos] = Temp;  
  
            //堆被破坏,需要重新调整  
            nStart = pos;  
        }  
        else  
        {  
            //比较左右孩子均小则堆未破坏,不再需要调整  
            break;  
        }  
    }  
}
void HeapSort(int data[],int nLen)  
{  
    int i;  
    int nTemp;  
    //建立堆  
    for (i = nLen/2-1; i >= 0; i--)  
    {  
        HeapAdjust(data, i, nLen);  
    }  
    for (i = nLen-1; i > 0; i--)  
    {  
        //交换堆顶元素和最后一个元素  
        nTemp = data[0];  
        data[0] = data[i];  
        data[i] = nTemp;  
        HeapAdjust(data, 0, i);  
    }  
}

 
 

大数据排序方法:

既然是大量的数据,不可能一次将所有数据读入,只能分段读取到内存再处理。

方法一:bit位排序。

    其思想是创建一个bit数组,数组大小为实际所排序数据的大小范围,用一个bit 位来标记某个元素对应的Value ,而Key 即是该元素,然后用01表示其值存在与否。将文件遍历一遍,将相应bit位的值置1,然后将bit数组遍历一遍,打印出值为1的对应代表值(实际数据范围的值)即可完成排序。

    优点:1 byte = 8 bit , 内存使用非常小。

    缺点:01只能代表存在与否,如果实际需要是有重复数据则不能满足需求。故,可以用int数组0表示没有,1234等代表存在个数,同样的思想可解决重复问题,但内存使用会更大。

    char str[255];
    long int fir;
    long int sed;
    
    int flag[Length];
    memset(&flag, 0, sizeof(flag));
    
    for (int j1 = 0; j1 < 100; j1++) {
        temp[j1].resize(Length);
    }

 //读取的文件
    FILE *fp=fopen([path UTF8String], "r+");
    while(feof(fp)==0)
    {
        std::fgets(str, 255, fp);
        fir = atol(str)/Length;
        sed = ( atol(str) - fir*Length );
        temp[fir][sed] = temp[fir][sed] + 1;
    }
    long int readdone = gettime();
    printf("read done!%ld\n",readdone - start);
    fclose(fp);
    
//输出文件
    FILE *wt = fopen("/Users/mac/Desktop/sorttest/data-bitsoet1.txt", "w+");
    for (int i2 = 0; i2 < 100; i2++) {
        for (int j2 = 0; j2 < Length; j2++) {
            if (temp[i2][j2] > 0) {
                for (int x2 = 0; x2 < temp[i2][j2]; x2++) {
                    fprintf(wt, "%d\n",i2 * Length + j2);
                }
            }
        }
    }

方法二:外部排序后归并排序。

    外部排序实质上是一个分段排序的方法,将大数据分段,每一段排序后另存到一个文件去。待排序的文件无法一次装入内存,需要在内存和外部存储器之间进行多次数据交换,以达到排序整个文件的目的。

-(void)Filesplit:(NSString *)path
{
    char str[255];
    vector<long int>data;

    FILE *fp=fopen([path UTF8String], "r+");
    for (int i=Length;feof(fp)==0;i+=Length) {
        do{
            fgets(str, 255, fp);
            data.push_back(atol(str));
            //            Index.push_back(ftell(fp));
        }while (feof(fp)==0&&data.size()<Length);
        sort(data.begin(), data.end());
        saveFile(data,i,0);
        data.clear();
    }
}

void saveFile(std::vector<long int>a,int i,int mode){
    char filepath[255];
    sprintf(filepath, "data-%d-%d.txt",i,mode);
    FILE *fp=fopen(filepath, "w+");
    for (int j=0; j<a.size(); j++) {
        fprintf(fp, "%ld\n", a[j]);
    }
    fclose(fp);
}
   

    归并排序是将两个有序数组组合成一个有序数组,即是将外部排序产生的文件进行多次归并后集合成一个文件。

//将有序序列a[low..mid]和a[mid+1..high]归并到a[low..high]。
void Merge(int a[], int low, int mid, int high)
{
    // 归并到b[]
    int i = low;
    int j = mid+1;
    int k = 0;
    int b[high-low+1];
    while (i <= mid && j <= high)
    {
        if (a[i] <= a[j]) { b[k++] = a[i++]; }
        else  { b[k++] = a[j++]; }
    }
    // 归并剩余元素
    while (i <= mid){
        b[k++] = a[i++];
    }
    while (j <= high) {
        b[k++] = a[j++];
    }
    // 从b[]复制回a[]
    for(i = 0; i <= high-low; ++i){
        a[low+i] = b[i];
    }
}

    问题在于在最后一次归并的时候,其数组大小是等于最开始的大数据文件的大小,这对内存消耗过大。

    所以可用一个固定大小x的数组,从两个有序数组中各读x/2到数组中,对比排序后写入文件一部分(如x/2),然后再各读x/4到数组补充缺少的,如此循环直至读完两个文件。可根据实际需求改变读取的大小、写入的大小。

    多路归并,一次将n(n>2)个文件归并成一个大文件t。思想是建立一个数组a[n],用n个指针指向各个文件内最小的数,对比取出a[n]内最小的值,然后这一个值写入大文件t,相应的指针再指向对应文件的下一个值,如此循环取值对比。

    这种方法对比次数较多,文件操作也会因数据变大而变多,不如第一种方法好。



未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值