算法学习

来源:互联网 发布:网络电视tv版哪个好 编辑:程序博客网 时间:2024/06/14 21:15

大数据取前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
原创粉丝点击