第15周报告2: 操作字符数组

任务2(字符数组和字符串):给出一个字符数组char str[],在程序中赋初值为一个句子,例如char str[]=”he threw threefree throws”,自编函数完成下面的功能:

(1)求出字符数组中字符的个数(从第一个字符读起,直到读到’\0’结束计数)(对于例句,输出为26);

(2)计算句子中各字符出现的频数

算法提示:

(a) i=0

(b)取字符串中的第i个符号c

(c)如果在c未在i之前出现过,在i位置上是第一次出现,频数f=1,从i+1位置到字符串结束,c每出现一次,f++,最后输出c-f(即字符-频数)对;如果在c在i之前出现过,则代表c字符已经计算过频数,不再处理,直接转(d)步;

(d)i++,若处理完,转(b)步;

可以动脑想想,或者集体讨论一下还可以采用什么算法完成这一道题,可能的算法很多。

实验目的:学会操作字符数组

实验内容:完成对字符数组的操作

/* 程序头部注释开始
* 程序的版权和版本声明部分
* Copyright (c) 2011, 烟台大学计算机学院学生
* All rights reserved.
* 文件名称:  char_array.cpp
* 作    者:     贺利坚
* 完成日期:  2011  年   12  月   4 日
* 版本 号:    v1.0
* 对任务及求解方法的描述部分
* 输入描述:要处理的字符串在程序中通过赋初值完成
* 问题描述:求出字符数组中字符的个数及计算句子中各字符出现的频数
* 程序输出:字符数组中字符的个数和句子中各字符出现的频数
* 程序头部的注释结束
*/
#include<iostream>
using namespace std;
int length(char[]);
void output_frequency(char[]);
int main(void)
{
 char str[]="he threwthree free throws";
 cout<<"要处理的字符串为:"<<str<<endl;
 cout<<"字符串长度为:"<<length(str)<<endl;
 cout<<"字符串中各字符出现的频数为:";
 output_frequency(str);
 cout<<endl;
 return 0;
}
int length(char s[])
{
 int i=0;
 while(s[i]!='\0') i++;
 return i;
}
// 下面的函数output_frequency用于求出各字符出现的频数
// 所用的算法是(算法1)
// (a) i=0
//  (b)取字符串中的第i个符号c
//  (c)如果在c未在i之前出现过,在i位置上是第一次出现,频数f=1,
//            从i+1位置到字符串结束,c每出现一次,f++, 最后输出c-f(即字符-频数)对;
//            如果在c在i之前出现过,则代表c字符已经计算过频数,不再处理,直接转(d)步;
// (d)i++,若处理未完成,转(b)步;
void output_frequency(char s[])
{
 int len=length(s);
 int i,j,f;
 char c;
 for(i=0;i<len;i++)
 {
  c=s[i];   //现在开始统计c字符,即s[i]出现的频数
  j=0;
 while(c!=s[j]&&j<i)j++;   //如果c字符在s[i]之前出现过,循环将由于c!=s[j]而退出,这时,j<i为真(
请通过走查验证)
  if(j==i)   //否则,这个字符已经处理过了,转到for循环开始,i++后继续处理
  {
   f=1;  //c在s[i]位置上第一次出现了,f置初值1
   for(j=i+1;j<len;j++)
    if(c==s[j]) f++;     //直到字符串结束,每出现一次,累加1
  cout<<c<<"-"<<f<<"; "; //输出c出现的频数f
  }
 }
}

运行结果:(贴图)

经验积累: 算法有些麻烦,但思路也算清晰,以后要习惯于将大脑中所想的过程自然地转换为代码

//下面是这一算法的另外一种表达,很简洁,对for循环的使用很老到
void output_frequency(char str[])
{
 int i , j ,num;
 for(i=0;i <= length(str);i++)//length(str)在for之前求出来保存到一个变量中就更好了
 {
   num = 0;
 for(j=0;j<length(str);j++)
  {
   if(str[i]==str[j])
   {
    if(i>j)
     break;  //在i之前发现了等待统计的字符,break了之
    else
     num++;  //这时已经过了大限,++即可
   }
  }

  if(num!=0)  //这儿我做些改动,只考虑不等于0即可
   cout <<str[i]<<"-"<<num<<"; ";
 }
}

下面再给出两个不同思想的算法供参考。有些同学们也想到了,不过有不少存在些小问题

算法2:

// 求出各字符出现的频数的算法2
// 算法思想:将字符数组排序,相同的字符将是连续的,形如aaaabbcccccc....计数方法比算法1简单很多
// 对于数组元素count[i],其下标为整型,而字符c当整型使用时,其值恰好为c的ASCII码。
void output_frequency(char s[])
{
 int len=length(s);
 char s1[80];   //无法预知字符数组长度,设一足够“长”的
 int i,j,f;
 char c;
 for(i=0;i<len;i++)
  s1[i]=s[i];   //将形参字符数组复制到临时数组变量中
 s1[i]='\0';   //一般复制完后应该加上字符串结束的符号,但本题中意义不大
 //下面对s1进行排序。讨论:也可以对s直接排序,但是会改变实际参数数组的值
 //这在一般情况是要避免的: 该函数仅是求各字符出现的频率,不可有更多的“副作用”
 //还是用冒泡法,其他方法也可以
 for(j=0;j<len-2;j++)
 for(i=0;i<len-j-1;i++)
   if (s1[i]>s1[i+1])
   {
    c=s1[i];
    s1[i]=s1[i+1];
    s1[i+1]=c;
   }
 //计数形如aaaabbcccccc....的字符数组中的符号
 c=s1[0];
 f=1;   //s1[0]字符出现了1次
 for(i=1;i<len+1;i++)   //i可以取值为len,有越界嫌疑,但此处不会,目标是在循环中完成最后一个符号频数的输出
 {
  if(c==s1[i])
   f++;  //重复出现相同字符,累加
  else
  {
  cout<<c<<"-"<<f<<"; ";  //输出前面的字符出现的频数
   c=s1[i];  //开始计数现在读到的符号
   f=1;
  }
 }
 return;
}

总结:(1)这个算法使计数过程简单了,但却需要一个较高代价的工作:排序。如果直接对s 排序,还有产生副作用的危险,不太提倡;(2)请在本解中研究一下对相同字符相邻的字符数组计数的算法。

算法3

// 求出各字符出现的频数的算法3
// 算法思想:设置一个数组count[],当读到字符c时,将c的ASCII码作下标的数组元素累加1即可。
// 对于数组元素count[i],其下标为整型,而字符c当整型使用时,其值恰好为c的ASCII码。
void output_frequency(char s[])
{
 int len=length(s);
 int count[256]={0}; //int数组初始化时,未指定的元素值为0
 int i,j,f;
 char c;
 for(i=0;i<len;i++)
 {
  c=s[i];
  count[c]++;  //c为字符,但此处用作下标,数据类型自动转换为int,取值为其ASCII码
 }
 for(i=0;i<256;i++)
 {
  if (count[i]>0)
  cout<<char(i)<<'-'<<count[i]<<';';   //ASCII码为i的符号出现了count[i]次
 }
}

总结:这是用空间换时间,通过count这个较大的数组,使计数简单地累加就行了。

算法4:

// 求出各字符出现的频数的算法4
// 这个算法由李洪悬提出,我们命名为李法
// 算法思想:当扫描中遇到正在统计的那个符号时,将其做一个标记,从而在以后扫描中不考虑这个符号
// 用'\0'作为这个标记。我们正在操作字符数组,而不是字符串,其循环由长度控制,故无碍
// 函数中要将s赋值比例本地的一个临时数组,目的是不致于改变实参数组的值
void output_frequency(char s[])
{
 int len=length(s);
 char s1[80];   //无法预知字符数组长度,设一足够“长”的
 int i,j,f;
 char c;
 for(i=0;i<len;i++)
  s1[i]=s[i]; //将形参字符数组复制到临时数组变量中
 s1[i]='\0';  //一般复制完后应该加上字符串结束的符号,但本题中意义不大

 for(i=0;i<len;i++)
 {
  if (s1[i]=='\0')continue;   //如果是'\0',该字符在前面的统计中已经被处理过了,continue即可
  c=s1[i];
  f=0;
  for(j=i;j<len;j++)
   if(s1[j]==c)
   {
    f++;
    s1[j]='\0';  //计数,当前字符赋值为'\0',以后将不再统计
   }
  cout<<c<<'-'<<f<<';';
 }
}

下面是对“he threw three free throws”统计时,正在统计字符“e”(i=1)时单步执行中的一个截屏。可以看到其中的一些字符数组元素的值(下标为0,1,4,6,10)已经为空字符。

 

时间: 2024-10-02 15:37:03

第15周报告2: 操作字符数组的相关文章

第15周报告3: ASCII文件的操作

任务3:从文件salary.txt中读入500名工人的工资,全部增加100元后进行排序(好事,涨工资了),将排序后的结果在屏幕上输出,并保存到文件ordered_salary.txt中. (salary.txt可以从BB平台下载) 实验目的:学会ASCII文件的操作 实验内容:从文件中读入数据,排序并输出到另外一个文件中 /* 程序头部注释开始 * 程序的版权和版本声明部分 * Copyright (c) 2011, 烟台大学计算机学院学生 * All rights reserved. * 文件

第15周报告1: 冒泡排序

任务1:(数组的排序)编函数,完成冒泡排序.要求不能改变下面的main函数. 重点体会:(1)排序算法:(2)数组名作形式参数,将能改变作为实际参数的数组的值,实际参数传递给形式参数的是数组的地址值,也是传值:(3)形式参数中不指定数组大小,实际数组的大小也一并作为参数传递. 实验目的:学会冒泡排序算法 实验内容:实现冒泡排序算法,并将之定义为一个函数 /* 程序头部注释开始 * 程序的版权和版本声明部分 * Copyright (c) 2011, 烟台大学计算机学院学生 * All right

C++第15周项目1扩展1 -数组类

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565,本周题目链接:http://blog.csdn.net/sxhelijian/article/details/9018813 [项目1-扩展1]建立专门的数组类处理有关数组的操作项目1情况见:http://blog.csdn.net/sxhelijian/article/details/9052881 要求:在MyArray基础上增加下面的成员或友元函数,扩充MyArra

《C语言及程序设计》实践项目——字符数组与字符串处理

返回:贺老师课程教学链接 [项目1-M$pszi$y是嘛意思?]背景:小明让同学传纸条给小丽.小丽接到会心一笑,大家却不知所云.纸条上写着M$pszi$y,两人暗中约定是,真实字符为实际字符前面的第4个!M$pszi$y是神马意思?推算一下,或从ASCII码表中查一下,自然是I love u.(1)小明请你写一个程序,在给小丽写情书时,再不用费功夫自己"翻译",原信中每一个字符加密为其后的第4个字符.例,输入I love u,输出M$pszi$y.(2)小丽请你写一个程序,在看小明的情

浅析C语言中的数组及字符数组_C 语言

我们来编写一个程序,以统计各个数字.空白符(包括空格符.制表符及换行符)以及所有其它字符出现的次数.这个程序的实用意义并不大,但我们可以通过该程序讨论 C 语言多方面的问题. 所有的输入字符可以分成 12 类,因此可以用一个数组存放各个数字出现的次数,这样比使用 10 个独立的变量更方便.下面是该程序的一种版本: #include <stdio.h> /* count digits, white space, others */ main() { int c, i, nwhite, nothe

2013级C++第14周项目——一维数组、字符数组

课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759 [项目1 - 数组大折腾] 将所有元素值加倍后保存在数组中,最后由前往后输出数组中所有元素的值,再由后往前输出数组中所有元素的值,再输出数组中的所有大于100的数,以及下标为3的倍数的元素值. (1)创建一个长度为20的整型数组,通过初始化,为数组中的前10个元素赋初值,然后通过键盘输入后10个元素的值,从前往后(从第0个到第19个)输出数组中元素的值,每5个元素换一行.

C++程序设计-第16周字符数组及指针上机实践项目

回到课程主页,链接:C++程序设计课程主页-2012级 本次上机对应的教学内容:第5章   数组 - 字符数组,第六章 指针 指针的基本概念 第一部分 程序分析 阅读下面的程序,先写出其运行结果,再上机运行进行对比.必要时,单步执行程序,在监视(watch)窗口中观察变量的动态变化,从而掌握程序的运行机理. (1) #include <iostream> using namespace std; void prt(int*, int*, int*); int a=10, b=40, c=20;

C++第16周项目2——带姓名的成绩单(字符数组版)

课程首页地址:http://blog.csdn.net/sxhelijian/article/details/7910565 [项目2-带姓名的成绩单(字符数组版)](参考15周项目3)设score数组中存储同学们的C++成绩,增加一个数组char name[][20]并赋初值,表示同学们的姓名(注意:本周不使用更方便的string类).这两个数组中,同学的姓名与成绩的下标保持一致(例如name[1]和score[1]表示同一位同学的姓名和C++成绩).请(1)输出按成绩排序后的同学的名单:(2

源代码-【二维字符数组】从键盘输入若干英文单词,单词最大长度不超过 15 个字母,把单词按照长度从大到小排序

问题描述 [二维字符数组]从键盘输入若干英文单词,单词最大长度不超过 15 个字母,把单词按照长度从大到小排序 用C语言来写,还没有学到指针,所以不要指针的写法,求大神给个源代码,我自己已经想了3个小时了还没有写出来. 解决方案 不用指针的话,没有办法动态分配内存,我们只能做一个假设,那就是键盘输入的单词不超过n(比如n=100,可以视作无限大) 至于排序,可以用冒泡都可以. 解决方案二: #include<string.h> #include<stdio.h> void main