免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2342 | 回复: 6
打印 上一主题 下一主题

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2004-06-07 08:38 |只看该作者 |倒序浏览
有如下两个文件:
file1:
"001", 123.01, 45.02, 783.29
"003", 22.43, 180.81, 26.70
..........
file2
"002", 1738.26, 0.32, 188.95
"001", 51.02, 77.48, 5.26
..........
现要将两个文件并为一个文件,要求是将两个文件中项目(第一列,引号中的为

项目代号)相同的按列相加,得到如下文件:
"001", 174.03, 122.50, 788.55
"002", 1738.26, 0.32, 188.95
"003", 22.43, 180.81, 26.70
请教各位高手如何实现,最简单且运行效率最高(速度最快,因为每个文件都有
几千行) (这个问题已在SHELL和PERL版中有解答了, 现在想请C高手们帮助在C下解决, 是不是可以更高效呢?)

论坛徽章:
0
2 [报告]
发表于 2004-06-07 09:47 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

不妨将每一行开始的字符串理解为一个记录的记录号(id)。你还应该告诉人们下列信息:每个文件中是否存在相同记录号的记录,新生成的记录在文件中是否要按序存放等。对上述问题的不同回答将导致实现效率有较大的差异。

其实单纯从算法上来说,已经很难再有大的改进。如果你想得到高的效率,我倒建议你对原来使用的文件格式做一下改进。例如:记录号不要使用字符串,而选用整型数;不使用文本文件格式,而是使用二进制存储记录中的各项;等等。

论坛徽章:
0
3 [报告]
发表于 2004-06-07 15:04 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

谢谢whyglinux
"每个文件中是否存在相同记录号的记录,新生成的记录在文件中是否要按序存放"
情况如下:
每个文件中的记录号不完全相同, 有重复的, 也有不是重复的, 记录号为三位或四位数.  新生成的记录不用按序存放, 但最好是格式化输出, 即每个字段长度一定, 不足的在前面补空格. 因为是对其它程序生成的文本进行加工, 所以源文件只能是文本格式的.
各位C高手, 可以帮助写一段程序处理文本累加问题吗, 先谢谢了. (本人初学C, 不知如何入手, 请多帮助)

论坛徽章:
0
4 [报告]
发表于 2004-06-10 15:36 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

谢谢whyglinux
"每个文件中是否存在相同记录号的记录,新生成的记录在文件中是否要按序存放"
情况如下:
每个文件中的记录号不完全相同, 有重复的, 也有不是重复的, 记录号为三位或四位数. 新生成的记录不用按序存放, 但最好是格式化输出, 即每个字段长度一定, 不足的在前面补空格. 因为是对其它程序生成的文本进行加工, 所以源文件只能是文本格式的.
各位C高手, 可以帮助写一段程序处理文本累加问题吗, 先谢谢了. (本人初学C, 不知如何入手, 请多帮助)

论坛徽章:
0
5 [报告]
发表于 2004-06-10 17:17 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

你可以使用链表技术(检索树)将需要处理的所有文件读入内存, 然后在内存中对代码一样的数据进行累加, 数据处理完毕, 再将所有链表节点信息输出即可达到你的要求.

论坛徽章:
0
6 [报告]
发表于 2004-06-12 14:33 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

本人初学, 一时无法掌握"链表技术", 请多帮忙, 非常感谢!!

论坛徽章:
0
7 [报告]
发表于 2004-06-12 17:47 |只看该作者

数据累加的问题? (用SCO UNIX 5.0.5下C如何解决?)

在这里使用链表虽然适应性好,不浪费内存空间,但是效率实在太低,建议在这个题目中不使用为好。

这个题目的算法分析如下:

1. 定义记录的结构

  1. struct Record {
  2.     int id;
  3.     double r1, r2, r3;
  4. };
复制代码

在这里把记录号作为整型数据处理,比用字符串要快很多。当然,如果记录中同时存在诸如记录号为“001”和“0001”这样的记录,那记录号就只能用字符串了。希望你没有这种情况。

2. 确定记录数

由于文件中的记录数不固定,又没有限制每个文件中能够存放的最大记录数,所以不好定义一个固定长度的数组空间来存储所有记录。这就要求动态为全部记录分配内存空间。由于事先不知道具体的记录数,每个记录的长度也不一致,所以大概有两种处理方法来得到记录数是多少:

(1) 精确计算法:读取文件内容,找出所有的换行符 '\n' 的个数即为记录数。

(2) 大概估计法:用stat()函数得到文件的大小,然后找出最短的一个记录所含有的字符个数,两者之商即为记录数。

第1中方法要预先读一遍文件内容,耗时较多,所以选取第2种方法来估计记录数为好,尽管会造成一些内存浪费。记录数记为 Num。

3. 为全部记录动态分配内存

  1. struct Record* prec;
  2. prec = (struct Record*)malloc(Num*(sizeof(int) + 3*sizeof(double)));
复制代码

因为无法把记录作为一个struct Record整体来读,只能单独读取,所以才有了上面看似奇怪的内存空间计算方式。

4. 读取记录同时对记录计数
可以用这种形式读取记录到一个struct Record型变量中:

  1. fscanf(fp, "\"%d\",%lf,%lf,%lf\n", &prec[k].id, &prec[k].r1, &prec[k].r2, &prec[k].r3);
复制代码

k应该从0开始,文件都读取完毕后,k的值就是实际的记录数。

5. 对记录排序

记录排序之后,相同的记录变成了邻居,可大大减少相同记录相加时的搜索时间。

但是有一个问题需要考虑,即排序的方法。排序一般用 qsort() 函数是没有错的。但是如果直接在原记录集上排序的话,由于涉及到记录的交换,记录数多,很费时。

遇到这种情况的话可使用指向记录的指针数组来处理,排序的时候不交换记录本身,而交换的是指向记录的指针值,这样效率上可得到很大的提高。

可以这样定义一个指针数组,并使它指向每一个记录,然后排序:

  1. struct Record** pindex;
  2. pindex = (struct Record**)malloc(k*(sizeof(int) + 3*sizeof(double)));
  3. for (i=0; i<rsize_r; i++) {
  4.     pindex[i] = &prec[i];
  5. }
  6. qsort(pindex, k, (sizeof(int) + 3*sizeof(double)), Compare);
复制代码

其中,Comapre是比较函数,要由你自己定义。具体参见 man qsort或者你能找到的其它例子。

6. 计算

现在相同的记录已经存放在一起了(从pindex的角度来看),很容易地就可以计算它们的和,然后用 fprintf()函数写入文件。可以在计算完一个记录后立即写入文件中。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP