算法学习
来源:互联网 发布:网络电视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,相应的指针再指向对应文件的下一个值,如此循环取值对比。
这种方法对比次数较多,文件操作也会因数据变大而变多,不如第一种方法好。
未完待续
- 算法学习
- 算法学习
- 算法 学习
- 算法学习
- 算法学习
- 学习算法
- 算法学习
- 算法学习
- 算法 学习
- 算法学习
- 学习算法
- 算法学习
- 算法学习
- 算法学习
- 算法学习
- 算法学习
- 算法学习
- 算法学习
- PHP7扩展开发之hello word
- POJ2406 Power Strings
- css背景图片在chrome下正常,IE下不显示
- gym100818I - Olympic Parade
- 浅析匿名函数、lambda表达式、闭包(closure)区别与作用
- 算法学习
- 数组指针和指针数组 原理 及 异同
- PHP时间格式大全
- 字符串的截取
- android新手进阶之录音功能实现
- better support right-to- left layouts的警报
- 在应用程序菜单里添加软件
- Eclipse常用快捷键
- 第二章 布局技巧与列表