第十五章 字符串(一)

C Primer Plus第十五章编程练习,仅供参考 第十五章编程练习 本章第一个编程练习的内容是让我们将二进制字符串转换为一个数值,传递字符串指针,逻辑并不复杂,完整程序代码以及运行结果如下: #include<stdio.h> #include<string.h> #include<math.h> int nfun(char * ptr); int main(void){ char * pbin = "01001001"; int number; number = nfun(pbin); 阅读详情

    第十五章是《编程珠玑》的最后一章,本章由易到难围绕字符串处理主要分三个部分:1,单词。2,短语。3,文本。在这三个问题中涉及到的技术有C++中的标准模板库,哈希表,新介绍的一种数据结构“后缀数组”。先从第一个部分“单词”入手。

    “我们的第一个问题是为文档中包含的单词生成一个列表”。这个问题用C++标准模板库中的set和string可以很容易解决。

[cpp]  view plain copy
  1. // Sorted list of words(between white space) in file   
  2.   
  3. #include <iostream>  
  4. #include <string>  
  5. #include <set>  
  6.   
  7. using namespace std;  
  8.   
  9. int main()  
  10. {  
  11.     string str;  
  12.     set<string> S;  
  13.     set<string>::iterator i;  
  14.     //while((cin>>str) != EOF)  
  15.     while(cin>>str)  
  16.         S.insert(str);  
  17.     for(i=S.begin(); i!=S.end(); i++)  
  18.         cout<<*i<<endl;  
  19.           
  20.     return 0;  
  21. }  
这里需要注意的问题是C++的标准输入函数cin()的用法,其自动识别空格,并且在输入终止符后自动退出,在我的编译环境下为Ctrl+Z加回车。


    “接下来的问题是对文档中每个单词的出现次数进行统计”。这个问题利用map容器即可方便地解决。

[cpp]  view plain copy
  1. // Sorted list of words and counts in file   
  2.   
  3. #include <iostream>  
  4. #include <string>  
  5. #include <map>  
  6.   
  7. using namespace std;  
  8.   
  9. int main()  
  10. {  
  11.     //int count=0;  
  12.     string str;  
  13.     map<string, int> M;  
  14.     map<string, int>::iterator i;  
  15.     //while((cin>>str) != EOF)  
  16.     /* 
  17.     while(cin>>str) 
  18.         M.insert(str, ++count); 
  19.     for(i=S.begin(); i!=S.end(); i++) 
  20.         cout<<(*i)->first<<"\t"<<(*i)->second<<endl; 
  21.     */  
  22.     /* 
  23.     while(cin>>str) 
  24.         M.insert(make_pair(str, ++count)); 
  25.     */  
  26.     while(cin>>str)  
  27.         M[str]++;  
  28.     for(i=M.begin();i!=M.end();++i)  
  29.         cout<<i->first<<"\t"<<i->second<<endl;      
  30.       
  31.     return 0;  
  32. }  
这里面主要需要注意的问题就是map的用法。


    程序达人们为了追求效率,减少处理的时间,对这个程序进行改进,定制了散列表,将字符串通过哈希算法分布到散列表中,这样就很有效地减少了程序运行过程中“插入”和“输出”的时间,据书中的记载是这个算法处理有29131个不同的单词詹姆斯一世钦定版《圣经》一共只需要3.0秒(map版本为7.6秒),其中处理时间(主要是插入和输出)是0.56秒(以前是5.2秒),所以用30行代码定制的散列表比C++标准模板库中的映射快一个数量级。

    标准模板库中的set和map大部分实现都使用到了“平衡搜索树”这个结构,其将字符串看作是不可分割的对象进行操作。平衡搜索树中的元素始终处于有序状态,从而很容易执行寻找前驱结点或者按顺序输出元素之类的操作。散列表的平均速度很快,但缺乏平衡树提供的最坏情况性能保证,也不能支持其他涉及顺序的操作。

    在散列表程序中,有初始条件如下:《圣经》中有29131个不同的单词,因此用跟29131最近接的质数作为散列表的大小,并将乘数定义为31:。

[cpp]  view plain copy
  1. //  Sorted list of words with counts (using hash method)  
  2.   
  3. #include <stdio.h>  
  4. #include <string.h>  
  5. #include <stdlib.h>  
  6.   
  7. #define NHASH 29989     //   
  8. #define MULT  31        //  
  9.   
  10. typedef struct node  
  11. {  
  12.         char *word;  
  13.         int count;  
  14.         struct node *next;  
  15. }node, *nodeptr;  
  16.   
  17. nodeptr bin[NHASH];  
  18.   
  19. #define NODEGROUP 1000  // 一次分配1000个节点块   
  20. int nodesleft = 0;  
  21. nodeptr freenode;  
  22.   
  23. nodeptr nmalloc()  
  24. {  
  25.         if(nodesleft == 0)  
  26.         {  
  27.                      freenode=(nodeptr)malloc(NODEGROUP*sizeof(node));  
  28.                      nodesleft=NODEGROUP;  
  29.         }  
  30.         nodesleft--;  
  31.           
  32.         return freenode++;  
  33. }  
  34.   
  35. #define CHARGROUP 10000 // 一次分配10000个字符   
  36. int charsleft = 0;  
  37. char *freechar;  
  38.   
  39. char *smalloc(int size)  
  40. {  
  41.      //if(charsleft == 0)  
  42.      if(charsleft < size)  
  43.      {  
  44.                   freechar=(char *)malloc((size+CHARGROUP)*sizeof(char)); // size+chargroup  
  45.                   charsleft=size+CHARGROUP;  
  46.      }  
  47.      charsleft-=size;  
  48.      freechar+=size;  
  49.        
  50.      return freechar-size;  
  51. }  
  52.   
  53. unsigned int hash(char *p)  
  54. {  
  55.     unsigned int h=0;  
  56.     for(;*p;++p)  
  57.         h=h*MULT+*p;  
  58.       
  59.     return h%NHASH;  
  60. }  
  61.   
  62. int inword(char *w)  
  63. {  
  64.     int x=hash(w);  
  65.     nodeptr p;  
  66.     for(p=bin[x];p!=NULL;p=p->next)  
  67.         //if(strcmp(p->word, w))  
  68.         if(strcmp(p->word, w)==0) //  
  69.         {  
  70.                            p->count++;  
  71.                            return 0;  
  72.         }  
  73.       
  74.     // THE wrong code  
  75.     /* 
  76.     p=(nodeptr)malloc(sizeof(node)); 
  77.     p->word=(char *)malloc(sizeof(w));    // calculate the size of new input word 
  78.     strcpy(p->word, w);                   // use strcpy() 
  79.     p->count=0; 
  80.     p->next=bin[0]->next; 
  81.     bin[0]->next=p; 
  82.     */  
  83.       
  84.     // THE inefficient code   
  85.     /* 
  86.     p=(nodeptr)malloc(sizeof(node)); 
  87.     p->word=(char *)malloc(strlen(w)+1);  // calculate the size for strcpy 
  88.     strcpy(p->word, w); 
  89.     p->count=1; 
  90.     //p->next=bin[x]->next; 
  91.     p->next=bin[x]; 
  92.     //bin[x]->next=p; 
  93.     bin[x]=p; 
  94.     */  
  95.       
  96.     // THE efficient code   
  97.     p=nmalloc();  
  98.     p->word=smalloc(strlen(w)+1);  
  99.     p->count=1;  
  100.     strcpy(p->word, w);  
  101.     p->next=bin[x];  
  102.     bin[x]=p;  
  103.       
  104.     return 0;  
  105. }  
  106.   
  107. int main()  
  108. {  
  109.     int i;  
  110.     //char *input;  
  111.     char input[100];  
  112.     nodeptr p;  
  113.     for(i=0;i<NHASH;++i)  
  114.         bin[i] = NULL;  
  115.     //while(scanf("%s", &input) != EOF)  
  116.     while(scanf("%s", input) != EOF)    
  117.         inword(input);  
  118.     for(i=0;i<NHASH;++i)  
  119.     {  
  120.                         for(p=bin[i];p!=NULL;p=p->next)  
  121.                             printf("%s\t%d\n",p->word,p->count);  
  122.     }  
  123.       
  124.     return 0;  
  125. }  
这个程序中需要注意的问题是:1,首先对内存分配算法进行了优化,利用整块的分配取代每次单独的malloc()。2,还是需要注意scanf()函数的用法,(这个问题到后面的单词级别生成随机文本时才被我仔细地发现),其自动识别空格键,并在为每个单词(由空格分隔的字符串)提供空字符作为结束标志。3,哈希函数的用法,其中包括哈希表大小的确定和乘数的选择。哈希表的大小可以确定为是质数为最好,可以证明的是这样会使冲突尽量减少而且使数据的分布更加均匀。但是这个质数是选择比数据量大的好还是少的好呢?这个我还没有太多考虑深入研究,就本程序来说,其定义的NHASH为29989要比不同的单词数29131大,但在后面的一个单次级别随机文本生成的问题的哈希表解决方法中,其定义的NHASH要比实际的数量少。我想还是应该定义哈希表的大小比实际的数据量大小小,但是要比实际的哈希值的数量大小大,这样冲突处理方法链地址法才有用武之地,而又不浪费太多的空间又减少了冲突,在本程序中真正的单词数量要远比29131大得多,这个数据只是不同单词的数量。总之哈希部分要再研究研究。
C Primer Plus (第六版) 第十五章_编程练习答案 no1.c //编写一个函数,把二进制字符串转换为一个数值.例如,有下面语句: //char * pbin = "01001001" ; //那么把pbin作为参数传递给函数后,他应该返回一个int类型的值25; # include <stdio.h> # include <limits.h> # include <string.h> # include ... 阅读详情

相关推荐

CPrimer Plus第6版第十五章编程练习答案(C语言)(自学记录)

第一题 #define _CRT_SECURE_NO_WARNINGS //第十五章,编程练习题,第一题 #include <stdio.h> #include <stdlib.h> #include <string.h> int printStrInt(char* str); char* fget_s(char* st, int n); int main(void) { int ch; char str[100]; printf("请输入一个二进制字符串:");

这个很可以的博客 373

cin>>和cin.get()对EOF的处理机制有什么不同

请问cin>>和cin.get()对EOF的处理机制有什么不同? #include #include using namespace std; int main() {     char c;          while(!cin.eof())     cin.get(c);//cin>>c;     return 0; } 采用cin.get()的时候运行时输入一个^

morethanicansay的博客 2659

C++ 中怎么结束 while (cin>>str) 的输入

cin 当从键盘上进行输入并按下回车时,输入的字符就会被送到输入缓冲区进行存储,且以空白字符为分隔符。 window 下 如果本行存在输入字符的情况下,在行尾加 ctrl+z 并且回车之后并不会结束输入,而是将 ctrl+z 当作一个字符来解释,将该字符当作普通字符缓冲并输出。 要结束输入需要在新行(即输入完成之后回车到新行)之后,输入 ctrl+z 并回车结束输入。 linux 下 在新行开头,输入ctrl+d,即为 EOF,此时输入结束。 在行尾结束输入 ctrl+d 则表示输出输入缓存区的数据,此时再

我不是码农的博客~~~ 5015

C++字符输入方式初探——为什么不能eof

前言 众所周知,C++的字符处理,尤其是输入输出,各种“读到文件结束”十分复杂。本文简单研究一下C++的各种字符输入方式。 由于C++提供了各种eof方法以供判断文件结尾,这就让人产生一种写类似这样代码的冲动: while(eof){ 读入什么东西; }而它在绝大多数情况下都是不能正常工作的。如果你改成这样: while(true){ 读入什么东西;

uKJLThHU$(eQ 4448

使用java理解程序逻辑第十五章

java入门基础,入门宝典,新手学习必备,好东西不容错过!

螺丝锁付系统软件设计 C# Winform

视觉螺丝锁付系统软件设计 C# Winform ,这是其中通信子模块设计

weixin_42522973的博客 340

c++中 cin对 EOF 的判断

<br />输入流中用成员 eofbit  来记录是否遇到 EOF ,再遇到EOF后 eofbit将被设置为1, 可以用成员函数 ::eof()来测试。<br /> <br />输入流是以行为缓冲的 意思是只有在一次输入以 enter 结束时 输入流才真正开始工作(读取)<br /> <br />EOF (win -- ctrl+z,unix -- ctrl + d)  <br /> <br />而只有当 EOF 出现在一行输入的首部时  输入流才会正确的设置 eofbit<br /> <br />当EOF

foxpeter的专栏 2万+

SPSS27 paired t-test 中的Cohen’s D – Effect Size for T-Test

两组数据是相关的且是连续的。

moonlightpeng的博客 910

第十五章 字符串本地化和消息字典(一)

本文概述了字符串本地化,并描述了如何导出、导入和管理消息字典。当本地化应用程序的文本时,会创建一种语言的文本字符串清单,然后当应用程序区域设置不同时,建立约定以另一种语言替换这些消息的翻译版本。支持以下本地化字符串的过程:这种机制各不相同,但最常见的机制是 宏。代替硬编码的文字字符串,开发人员包含 宏的实例,为宏参数提供如下值: 替换为 编译代码时,编译器会在消息字典中为 宏的每个唯一实例生成条目。 消息字典是全局的,因此可以在管理门户中轻松查看(例如)。有一些类方法可以帮助完成常见任务。结果是一

yaoxin521123的博客 507

5G移动网络运维(优化)

5G 网络优化现状 移动通信行业属于技术密集型行业,是国民经济的重要支柱以及整个社会经济运转体系中不可或缺的基础。2019 年年底 5G 开始商用,截止到 2020 年3月,我国三大运营商建设了 16.1 万个 5G 基站,我国成为目前全球 5G 基站最多的国家。预计到 2020 年年底,我国运营商会建设大概 70 万个 5G 基站。基于 5G高频段的特性,信号覆盖距离会低于ins 基站,再加上 5G 万物互联的巨大经济潜力价值需求,后续三大运营商在 5G 基站建设数量上势必会超过当前 LTE 基站数量的

2301_78171382的博客 1325

一位海外开发者的 OpenSPG KAG 实践分享

KAG 是一个以创建和操作知识图谱为核心的框架。知识图谱是数据之间相互关联的可视化和结构化表示,对于搜索引擎、推荐系统和机器学习等应用至关重要。KAG 的目标是提供一个强大的平台,使开发者能够:轻松构建图谱;通过增强算法丰富数据;集成人工智能,以进行更精确的推理。通过理解 KAG,可以明显看出,这个框架旨在帮助从初学者到专业开发者,在项目中创造更优的解决方案。它在简便性和集成方面的优势,使其成为下一代基于数据的应用程序的前景工具。

金融机器智能社区 3405

第十五章 ObjectScript - 字符串函数

要使用数组中的单个节点,可以使用前面描述的任何函数。

yaoxin521123的博客 542

b站up“麦辣翅翅”《YOLOv8修改损失函数》问题解决RuntimeError: The size of tensor a (4) must match the size of tensor

b站up“麦辣翅翅”《YOLOv8修改损失函数》问题解决RuntimeError: The size of tensor a (4) must match the size of tensor ;TypeError: bbox_iou() got an unexpected keyword argument 'xywh‘

weixin_68331871的博客 3020

第十五章字符串

一、如何定义声明一个字符串? 1.以前的写法:数据类型 变量名=赋值; String name="张三"; 2.现在的写法:类名 对象名=new 类名(); 为什么还可以new?因为字符串本身就是一个class类,属于引用类型,使用时就必须要用new关键字创建。 String name=new String("张三");二、字符串的9个常用方法 只需要会使用即可: 1.length() 获取长度 返回int类型

m0_72658137的博客 180

用R语言做WGCNA分析全步骤一(附代码解读)【转载】

代码逐句分析一、文章来源二、基因共表达网络构建及模块识别1.数据导入、清洗及预处理2.检查过度缺失值和离群样本3.聚类做离群样本检测4.载入临床特征数据三、自动构建网络及识别模块1.确定合适的软阈值:网络拓扑分析2.一步构建网络和识别模块 一、文章来源 初学WGCNA,觉得博主的代码写的很不错,但其中很多代码在第一遍看的时候有很多地方不理解,后查阅了很多资料,终于看明白了,于是写了一篇笔记,记录自己的学习心得,有不准确的地方,还望各位大佬们不吝赐教~ 原文链接:WGCNA简明指南 二、基因共表达网络构建及模

qq_43138237的博客 2万+

ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory解决方案

本文主要介绍了ERROR: Could not install packages due to an OSError: [Errno 2] No such file or directory解决方案,希望能对使用Python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案

weixin_43178406的博客 11万+

第十五章 字符串

字符串一、字符串使用基础二、复杂的字符串处理三、StringBuffer类的使用 一、字符串使用基础 字符串是非常常用的一种数据类型 日常中的很多信息都可以与字符串表示:密码、用户名、文章标题… 定义并初始化字符串: String str = "abc"; String str = new String();//等同于String str =""; String str = new String("abc");//等同于String str = "abc"; Stri

weixin_56258427的博客 201

C#实现将DataGridView中数据导出到Excel (附完整源码)

C#实现将DataGridView中数据导出到Excel (附完整源码)

希望我的博客,能帮上你解决学习中工作中所遇到的问题 1589

第十五章 字符串

package com.tt; import java.util.Scanner; public class S4 { public static void main(String[] args) { StringBuffer sb=new StringBuffer(); int num=100; StringBuffer b1=sb.append("青春无悔");

qq_36074150的博客 1436

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C Primer Plus 第十五章 课后答案

目录   复习题 1.把下面的十进制转换为二进制: a.3        b.13        c.59        d.119 2.将下面的二进制值转换为十进制、八进制和十六进制的形式: a.00010101        b.01010101        c.01001100        d.10011101 3.对下面的表达式求值,假设每个值都为8位: a.~3   ...

asdgyy的博客 4755

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

CLR via C# 第十四章—第十五章

CLR摘要

2301_79124729的博客 989

第十五章 字符串

众所周知,java提供了很多字符串截取的方式。下面就来看看大致有几种。 1.split()+正则表达式来进行截取。 将正则传入split()。返回的是一个字符串数组类型。不过通过这种方式截取会有很大的性能损耗,因为分析正则非常耗时。 String str = "abc,12,3yy98,0"; String[] strs=str.split(","); for(int i...

ansixue3661的博客 239

python教程知识(第十五章)

python知识

zzj13283671195的博客 732
上一篇: 第十四章 堆
下一篇: 第十五章 字符串(二)
ProfessionalEngineer
博客等级 码龄19年 295粉丝 154原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值