有10亿个浮点数,从中找出1万个最大的数。

kesaihao862 2008-02-28 02:43:57
请问:1.有10亿个浮点数,从中找出1万个最大的数。写一个高性能的算法

能说出算法和数据结构就可以了
...全文
6191 138 打赏 收藏 转发到动态 举报
写回复
用AI写文章
138 条回复
切换为时间正序
请发表友善的回复…
发表回复
ccnuliu 2011-09-21
  • 打赏
  • 举报
回复
楼主这样做,是为了减少树的高度。不错不错。

[Quote=引用 47 楼 redleaves 的回复:]

TO hxxwcc,我用的是单精度的浮点数.文件是一个400多MB的二进制文件.

另外,我又改了几行不相关的代码.VC8编译出的程序运行结果和ICL差不多了...呵呵.有时候编译器也不太可靠.

我的代码如下:
C/C++ code
#include <stdio.h>
#include <set>
#include <time.h>

int main( int argc, ch……
[/Quote]
qianzhiyong2009 2010-10-22
  • 打赏
  • 举报
回复
同意三楼
Carmack Jiang 2010-04-29
  • 打赏
  • 举报
回复

#include <set>
#include <iostream>
#include <fstream>
using namespace std;
#define N 10000

int main(int argc, char* argv[])
{
set<float> set_MAX_N;
ifstream inFile("test.txt");
float fTemp;
while(inFile >>fTemp)
{
set_MAX_N.insert(fTemp);
if(set_MAX_N.size() > N)
{
set_MAX_N.erase(set_MAX_N.begin());
}
}
for(set<int>::iterator it = set_MAX_N.begin();it != set_MAX_N.end(); it ++)
cout<< *it <<endl;
while(1);
return 0;
}
pitera 2009-05-26
  • 打赏
  • 举报
回复
念天地之悠悠!真牛!
bwangel 2008-04-03
  • 打赏
  • 举报
回复
先取出最初的10000个数进行排序,组成有序表。这个复杂度是个常数可忽略不计。
然后从第10001个数开始,依次与最小值比较,如果小则丢弃,如果大,则用对分法求得插入表的位置,把它挤进去,把最后一个数挤下来,依此类推。复杂度是O(n * log 10000) = O(n)
双杯献酒 2008-03-07
  • 打赏
  • 举报
回复
float应该比double要慢,
因为float数据范围发、更小,数据大小差不多的情况更普遍.
w_anthony 2008-03-07
  • 打赏
  • 举报
回复
T7300只在本本上用的吧?谁会把本本拆开玩跳线呢?感觉T7300和E6320性能相差不大吧?可能是编译器的关系,我是用VC7-sp1在release下编译后测试的。
wh110 2008-03-06
  • 打赏
  • 举报
回复
天书就是这样产生的。
redleaves 2008-03-06
  • 打赏
  • 举报
回复
楼上的同学的T7300超频了?要不怎么如此之快?我的E6320小超到2.24G,跑21楼的程序,改float,改随机数算法,都还要27.9s其中,生成随机数都要27.4s.而且还是用gcc优化...要用vc9要40s以上..ICL更不济50s以上..
w_anthony 2008-03-06
  • 打赏
  • 举报
回复
用线性结构存放10000个数,不如用树形结构存放,因为树形结构的查找和插入既不涉及遍历又不涉及搬移,二叉堆就是其中一种,测试了一下129L的代码,在T7300的CPU上,耗时33秒,如果把121L的代码改为float,随机数生成算法简单地改成float(rand() * rand()),那么其耗时为24秒;相似的,将129L的代码改为double,随机数生成算法改成与121L相同,耗时则为79秒。
梦无痕123 2008-03-06
  • 打赏
  • 举报
回复
学习了
双杯献酒 2008-03-06
  • 打赏
  • 举报
回复
// VC2003
// CPU 1.51GHz
// RAM 512MB
//

#include "stdafx.h"
#include <math.h>
#include <time.h>
#include <iostream>
#include <queue>
using namespace std;

#define MAX_DATA_NUM 10000
#define DATA_COUNT 1000000000

// 统计
// 比较次数
__int64 g_iCmp;
// 移动数据量
__int64 g_iMov;

// 产生浮点数据
// 近似效果
float RandFloat()
{
return float(rand() * rand());
}

// 数据管理
class my_priority_queue
{
public:
my_priority_queue()
{
m_iNum = 0;
memset(m_data, 0, sizeof(m_data));
g_iCmp = 0;
g_iMov = 0;
}
void push(float f)
{
int iPos = FindPos(f);
if(iPos != m_iNum)
{
g_iMov += (m_iNum - iPos);
memmove(m_data + iPos + 1, m_data + iPos, (m_iNum - iPos) * sizeof(float));
}
m_data[iPos] = f;
++m_iNum;
}
float top()
{
return m_data[m_iNum-1];
};
void pop()
{
--m_iNum;
}
int size()
{
return m_iNum;
}
private:
// 查找位置
int FindPos(float f)
{
++g_iCmp;
if(m_iNum == 0)
{
return 0;
}

++g_iCmp;
if(f <= m_data[m_iNum-1])
{
return m_iNum;
}

++g_iCmp;
if(f >= m_data[0])
{
return 0;
}

int iFind0 = 0;
int iFind1 = m_iNum-1;
int iFind = (iFind0 + iFind1 + 1)/2;
while(iFind1 > iFind)
{
++g_iCmp;
if(f < m_data[iFind])
{
iFind0 = iFind;
}
else
{
iFind1 = iFind;
}
iFind = (iFind0 + iFind1 + 1)/2;

++g_iCmp;
if(f == m_data[iFind])
{
break;
}
}
return iFind;
}
private:
int m_iNum;
// 数据从大到小排列
float m_data[MAX_DATA_NUM + 1];
};


int _tmain(int argc, _TCHAR* argv[])
{
srand((unsigned)time( NULL));

// 10000数据
// priority_queue<float, vector<float>, greater<float> > data;
my_priority_queue data;

// 数据计数
unsigned int iCount = 0;

// 开始
DWORD dwT1 = ::GetTickCount();

// 10000个初始数据
while(iCount++ < MAX_DATA_NUM)
{
data.push(RandFloat());
}

// 10000~1000000000
while(iCount++ < DATA_COUNT)
{
// RandFloat();
data.push(RandFloat());
data.pop();
}

// 结束
DWORD dwT2 = ::GetTickCount();

cout << "使用时间: " << (dwT2 - dwT1)/1000.0f << " (s)" << endl;
cout << "最后保留: " << data.size() << "个数据" << endl;
cout << "平均比较 " << 1.0*g_iCmp/DATA_COUNT << " 次" << endl;
cout << "平均移动 " << 1.0*g_iMov/DATA_COUNT << " 个数" << endl;

// 输出100个结果
for(int i=0; i<100; i++)
{
cout << data.top() << endl;
data.pop();
}
cout << endl;

system("PAUSE");

return 0;
}

/*
其中一次运行的结果(Release):
使用时间: 56.922 (s)
最后保留: 10000个数据
平均比较 2.00338 次
平均移动 0.602598 个数
....
*/
benjiam 2008-03-05
  • 打赏
  • 举报
回复
10亿个浮点数

8字节 容量是7G多。 读读要几秒吧

68M/s 至少也是100多秒。 你们什么算法啊?
zhiang75 2008-03-05
  • 打赏
  • 举报
回复
[Quote=引用 114 楼 w_anthony 的回复:]
To 112楼,我发现你的一些算法思路真的很不错啊……
你的这个算法之所以快,我个人感觉不是基数排序的功劳,而是你将10亿个数据分为多个100万来提升的,相当于再多利用一些空间来赚取一些时间。
下面我再吹毛求疵一下,你的算法内存不足的问题还有可能会存在:
1、假设10亿个数据全部落在最后一个容器的,并且这10亿个数据只有101个不同的取值,并且前(大)99个取值的数据的个数均为100w,第100个的个数为100w-1,第101个…
[/Quote]
谢谢你看完了我的代码,大家相互促进,相互学习,只有更好,没有最好..认识你很高兴..^_^
chinatzbcn 2008-03-05
  • 打赏
  • 举报
回复
1.读取10亿数中的前1万个数字
2.取1万数中的最小数字,记录为min_num;
3.从一万零一个数开始遍历,每个数和min_num比较,大于min_num的时候替换该数字,并重新取得1万个数中的最小数用min_num记录.如果小于或者等于min_num.不做处理。
4.如此结束后那一个万就是10亿中的最大数.


很笨,很无耻。呵呵
双杯献酒 2008-03-05
  • 打赏
  • 举报
回复
10亿个浮点数,是
4000 000 000字节, 即4GB
对于普通PC而言,内存不够必然要存储在外存.
同意 cxfcxf8 的说法
外排序这里主要考虑文件操作,
显然,可以很轻易实现每个数据只读一次的算法.
外操作复杂度是 O(n)
程序实际执行的时间主要看你的硬盘数据传输速度.

但是我们不排除有机器内存大于4GB, 那么仍然可以按照内排序处理.
这里主要考虑选择算法.
容易想到,
先取10000个数排序
然后把剩下的数依次取来和最小的数比较,如小于等于就丢弃,
如大于则把最小的数去掉,而把新的这个数据插入正确位置.
这种算法的时间复杂度是 O(n)
现在考虑怎样提高 新的这个数据插入正确位置 的效率.
这里有两个操作: 查找正确的位置 和 插入数据
有两个备选的数据结构: 数组 和 链表
数组: 查找正确的位置快O(logN) 插入数据慢O(n), 整体复杂度O(n)
链表: 查找正确的位置慢O(n) 插入数据快O(1), 整体复杂度O(n)
鉴于现在处理的是浮点数的情况,
数组插入数据的时候,需要移动的数据可以用 memmov() 一次完成,近似复杂度O(1)
其效率非常高,这样,数组的整体复杂度就成为 O(logN)
因而用数组好.

cxfcxf8 2008-03-05
  • 打赏
  • 举报
回复
偶以为:对于大数据的文件,要减少相应的时间,就要把主要的精力放在减少硬盘读取文件的次数上。相对来说排序占的时间要少。要减少硬盘的读的次数上可以采取败者树的方法。
还有一个小问题:这是求1万个最大的数字。而不必将所有的数字都排序而找那1万个数字。
zhenghaibingood 2008-03-05
  • 打赏
  • 举报
回复
加为好友
发送私信
在线聊天
zhiang75
在忙项目呢.

=================

很崇拜,以前在群里给一学生写过排序和比较之类的,
因为数据的格式就像彩票号码一样规则,所以自己重写的比较器接口让速度翻番,很得意
你真牛,从数据格式上找速度
sknice 2008-03-05
  • 打赏
  • 举报
回复
太厉害了,学习ing
xbt746 2008-03-05
  • 打赏
  • 举报
回复
最小二叉堆
加载更多回复(118)

64,688

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧