什么玩意?快读快写浮点型数据?

本文介绍了解决POJ1064问题的一种高效算法,通过使用快速读写整数和浮点数的方法,显著提高了程序的运行效率。文章详细展示了快速输入输出的代码实现,并对比了使用标准输入输出函数与自定义快速读写函数的性能差异。

我下午花了一个小时写了一个什么玩意?居然能过poj1064 Cable master?大家都知道有整型数据快读快写.如下:

//我写的比较骚.这么写比较简单,仅限非负整数.
inline int read()
{
int x=0;char c=getchar();
for (;!isdigit(c);c=getchar();
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x;
}
//快速输出有两种写法:
void write(int x)//递归
{
if (x>9) write(x/10);
putchar(x%10+48);
}

inline void write(int x)//非递归
{
register int bit[20],i,p=0;
if (x==0) {putchar('0');return;}//特判0,递归输出不用判.这里由于相当于把它转化成10进制整数逐位输出,故需要判0
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i>0;--i) putchar(bit[i]+48);
}
//递归代码短.当然非递归也长不到哪里去.

然后就是非常滑稽的浮点型快读了.

inline void read(double &r)
{
double x=0,t=0;int s=0,f=1;char c=getchar();//x代表整数部分,t代表小数部分
for (;!isdigit(c);c=getchar()) 
  {
  if (c=='-') f=-1;//读到负号就改变之
  if (c=='.') goto readt;//看到小数点,直接读小数部分
  }
for (;isdigit(c)&&c!='.';c=getchar()) x=x*10+c-'0';//整数部分
readt:for (;c=='.';c=getchar());//跳过小数点 
for (;isdigit(c);c=getchar()) t=t*10+c-'0',++s;//读小数部分,s代表小数有几位
r=(x+t/pow(10,s))*f;//t除以10的s次方后变成小数部分
}

inline void read(int &x)//整型快读,注意这里是void有自变量
{
x=0;char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
}

inline void dwrite(ll x)//用于输出整数部分
{
if (x==0) {putchar(48);return;}
int bit[20],p=0,i;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i>0;--i) putchar(bit[i]+48);
}

inline void write(double x,int k=6)//不加位数,默认保留小数点后6位小数
{
static int n=pow(10,k);//和读入相反,这里我无法直接转化小数部分,先乘以n,就可以当做整数处理
if (x==0)//x=0,保留的k位不断输出0; 
  {
  putchar('0'),putchar('.');
  for (int i=1;i<=k;++i) putchar('0');
  return;
  }
if (x<0) putchar('-'),x=-x;//负数
ll y=(ll)(x*n)%n;x=(ll)x;//y表小数部分,x*n之后把小数部分截去再对n取余就可以得到需要保留的小数部分.
dwrite(x),putchar('.');//输出整数部分和小数点
int bit[10],p=0,i;
for (;p<k;y/=10) bit[++p]=y%10;//必须严格按照k位保留,否则就gg了
for (i=p;i>0;i--) putchar(bit[i]+48);
}

好tm有意思.以下是poj1064的题解.具体的话就是二分答案.

#include<cstdio>
#include<cctype>
#include<cmath>
using namespace std;
typedef long long ll;

inline void read(double &r)
{
double x=0,t=0;int s=0,f=1;char c=getchar();
for (;!isdigit(c);c=getchar()) 
  {
  if (c=='-') f=-1;
  if (c=='.') goto readt;
  }
for (;isdigit(c)&&c!='.';c=getchar()) x=x*10+c-'0';
readt:for (;c=='.';c=getchar()); 
for (;isdigit(c);c=getchar()) t=t*10+c-'0',++s;
r=(x+t/pow(10,s))*f;
}

inline void read(int &x)
{
x=0;char c=getchar();
for (;!isdigit(c);c=getchar());
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
}

inline void dwrite(ll x)
{
if (x==0) {putchar(48);return;}
int bit[20],p=0,i;
for (;x;x/=10) bit[++p]=x%10;
for (i=p;i>0;--i) putchar(bit[i]+48);
}

inline void write(double x,int k=6)
{
static int n=pow(10,k);
if (x==0) 
  {
  putchar('0'),putchar('.');
  for (int i=1;i<=k;++i) putchar('0');
  return;
  }
if (x<0) putchar('-'),x=-x;
ll y=(ll)(x*n)%n;x=(ll)x;
dwrite(x),putchar('.');
int bit[10],p=0,i;
for (;p<k;y/=10) bit[++p]=y%10;
for (i=p;i>0;i--) putchar(bit[i]+48);
}

int a[10000],n,k,i,l,r=1e7+1,m,s;double f;
int main()
{
read(n),read(k);
for (i=0;i<n;++i) read(f),a[i]=int((f+1e-6)*100);
for (;l!=r-1;)
  {
  m=(l+r)/2;s=0;
  for (i=0;i<n;++i) s+=a[i]/m;
  s>=k?l=m:r=m;
  }
write(1.*l/100.,2);
}
/*//虽然我的快读快输是正确的,但和原代码的时间区别并不大,可能我白打了.
#include<cstdio>
int a[10000],n,k,i,l,r=1e7+1,m,s;double f;
int main()
{
scanf("%d%d",&n,&k);
for (i=0;i<n;i++) scanf("%lf",&f),a[i]=int((f+1e-6)*100);
for (;l!=r-1;)
  {
  m=(l+r)/2;s=0;
  for (i=0;i<n;i++) s+=a[i]/m;
  s>=k?l=m:r=m;
  }
printf("%.2f",1.*l/100.);
}
*/

然而事实是我读入并输出100000个数用scanf和printf要0.5s,用快读快写只需要0.16s.可能还是我的错觉吧.

在 C++ 中,取和入文件或数据流是处理大量数据或高性能要求场景的关键需求。以下是一些常用的方法和技术,它们可以显著提升 I/O 操作的效率。 ### 1. 使用二进制模式文件 相比于文本模式,二进制模式能够避免字符转换的开销,并且可以一次性大块数据。适用于结构体、数组等复杂数据类型的高效处理。 ```cpp #include <fstream> struct Data { int id; float value; }; // 入二进制数据 std::ofstream outFile("data.bin", std::ios::binary); Data writeData = {1, 3.14f}; outFile.write(reinterpret_cast<char*>(&writeData), sizeof(Data)); outFile.close(); // 取二进制数据 std::ifstream inFile("data.bin", std::ios::binary); Data readData; inFile.read(reinterpret_cast<char*>(&readData), sizeof(Data)); inFile.close(); ``` 该方法通过 `write()` 和 `read()` 成员函数实现二进制操作,避免了格式化输入输出的性能损耗[^2]。 --- ### 2. 使用缓冲区优化 I/O 操作 频繁调用单字符或小块数据会导致性能下降。通过一次性取或入较大的数据块来减少 I/O 次数。 ```cpp const size_t bufferSize = 1024 * 1024; // 1MB 缓冲区 char buffer[bufferSize]; std::ifstream inFile("largefile.txt"); while (inFile.read(buffer, bufferSize)) { // 处理 buffer 中的数据 } inFile.close(); ``` 这种方式通过一次性取大量数据,减少磁盘访问次数,从而提高性能[^1]。 --- ### 3. 使用内存映射文件(Memory-Mapped Files) 内存映射文件是一种高级技术,它将文件内容映射到进程的地址空间,使得文件如同访问内存一样高效。C++ 标准库不直接支持内存映射,但可以通过系统 API(如 Windows 的 `CreateFileMapping` 和 Linux 的 `mmap`)实现。 示例(Linux 下使用 `mmap`): ```cpp #include <sys/mman.h> #include <fcntl.h> #include <unistd.h> int fd = open("data.bin", O_RDONLY); struct stat sb; fstat(fd, &sb); char* addr = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); // 使用 addr 指针访问文件内容 munmap(addr, sb.st_size); close(fd); ``` 内存映射特别适用于大文件的随机访问和共享内存场景。 --- ### 4. 使用 `std::ios_base::sync_with_stdio(false)` 提升标准流性能 在大量使用 `cin` 和 `cout` 的情况下,禁用与 C 标准库的同步可以显著提升性能。 ```cpp std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); ``` 此设置使 C++ 流与 C 的 `stdin`/`stdout` 解耦,减少同步带来的性能损耗。 --- ### 5. 使用 `fstream` 的 `seekg` 和 `seekp` 实现高效定位 在处理大文件时,使用 `seekg()` 和 `seekp()` 可以速定位到文件的任意位置,避免逐行扫描。 ```cpp std::ifstream inFile("data.bin", std::ios::binary); inFile.seekg(1024); // 移动指针到 1024 字节处 ``` 此方法适用于需要随机访问的数据结构,如索引文件或日志文件。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值