第九章 数据结构 :数组和结构体
目录标题
9.1数组数据类型
数组:具有相同变量名的一组数据项的集合。
数组元素:数组中每一个独立的元素。
9.1.1数组声明
并行数组:具有相同数组元素个数的两个或两个以上的数组,并且它们都用于存储一个对象集合的相关信息。
9.1.2数组的初始化
格式:element_type array-name[size];
element_type array_name[size]={initialization-List};
示例:char myNames[5];
float salaries[NUM_EMP];
char vowels[]={'A','E','I','O','U'};
9.1.3数组下标
数组下标:在数组名之后的方括号中的一个值或表达式,它用于确定存取哪个数组元素。
下标变量:用于指定一个特定数组元素的变量,该变量带有下标(置于方括号中)。
数组下标
格式:数组名[下标]
示例: x[3*i-2];
说明:下标值必须是整型表达式。每次在程序中遇到下标变量时,都要对下标求值,这个值决定了数组中哪个元素被引用。下标值应该在0到数组大小-1的范围内。如果下标值超出这个取值范围,那么将会引用数组外的某个内存单元。
例子:每个数组元素与平均值差值的数据表
#include<iostream>
#include<iomanip>
using namespace std;
int main()
{
const int MAX_ITEMS=8;
float x[MAX_ITEMS]; //数据的数组
float average; //数据的平均值
float sum; //数据的和
//进入数据
cout<<"Enter "<<MAX_ITEMS<<" numbers: ";
for(int i=0;i<MAX_ITEMS;i++)
cin>> x[i];
//计算数据的平均值
sum=0.0; //初始化和
for(int i=0;i<MAX_ITEMS;i++)
sum+=x[i]; //给和加入下一个元素
average=sum/MAX_ITEMS; //得到平均值
cout<<"The average value is "<<average<<endl<<endl;
//显示每个数和平均值的差值
cout<<"Table of differences between x[i] and the average."<<endl;
cout<<setw(4)<<"next"<<setw(8)<<"x[next]"<<setw(14)<<"difference"<<endl;
for(int i=0;i<MAX_ITEMS;i++)
cout<<setw(4)<<i<<setw(8)<<x[i]<<setw(14)<<(x[i]-average)<<endl;
return 0;
}
例子:密码生成器
#include<string>
#include<iostream>
#include<cctype>
using namespace std;
int main()
{
const string ALPHABET="abcdefghijklmnopqrstuvwxyz";
const string CODE="bcdefghijklmnopqrstuvwxyza";
string message; //要编码的信息
char ch; //下一个信息符号
int pos; //它的位置
cout<<"Enter a string to encode: ";
getline(cin,message);
//编码信息
for(int i=0;i<message.length();i++)
{
ch=tolower(message.at(i)); //ch 到小写
pos=ALPHABET.find(ch); //发现ch的位置
if((pos>=0)&&(pos<26))
message[i]=CODE.at(pos);
}
cout<<"The cryptogram is : "<<message<<endl;
return 0;
}
9.2数组元素的顺序存取
9.3数组参数
例子:交互两个浮点型内存单元内容的函数
void exchange(float& a1,float& a2) //输入输出
{
float temp;
temp=a1;
a1=a2;
a2=temp;
}
9.3.1数组元素作为函数参数
9.3.2传递数组参数
例子:函数sameArray
//比较两个浮点数组为了平等通过比较比较对应元素。
//Pre:a[i]和b[i](0<=i<=size-1)是被赋值
//Post:如果a[i]==b[i]对于范围 0 到 -1 范围内的所有 i返回正确,否则,返回错误
bool sameArray(float a[],float b[],const int size)
{
int i;//循环控制变量和数组下标
i=0;
while((i<size-1)&&(a[i]==b[i]))
i++;
return (a[i]==b[i]); //定义结果
}
z=x+y; 是无效的数组操作,因为运算符"+"不能用于数组实参的相加。
例子:函数addArray
//存储a[i],b[i]和c[i]的和
//对下标范围从 0 到大小为 1 的数组元素对求和
//pre:a[i]和b[i]被定义
//post:c[i]=a[i]+b[i](0<=i<=size-1)
void addArray(int size,const float a[],const float b[],float c[])
{
//添加 a 和 b 的相应元素并存储在 c 中
for(int i=0;i<size;i++)
c[i]=a[i]+b[i];
}
数组作为函数参数
1)在c++中,数组通过引用进行传递。
2)函数定义或函数原型中,使用一对空白的方括号([ ])告诉编译器该形参代表数组。
3)关键字const说明函数不能改变形参数组。
4)在函数调用中,实参数组的名字后是不带方括号的。
9.4读取部分数组元素
填充子数组:包含数据项的数组被部分地填入数据。
例子:函数readScores
//读取一系列考试分数,用于讲课部分,最高可达MAX_SIZE的学生
//pre:无
//post:数据值存储在数组分数中。读取的值数存储在节中大小.
void readScores(int scores[],const int MAX_SIZE,int& sectionSize)
{
const int SENTINEL=-1; //哨兵值
int tempScore; //每个分数的临时存储
//读取每个数组元素,直到完成
cout<<"Enter next score after the promot or enter "<<SENTINEL<<"to stop."<< endl;
sectionSize=0; //初始化班级规模
cout<<"Score: ";
cin>>tempScore;
while((tempScore!=SENTINEL)&&(sectionSize<MAX_SIZE))
{
scores[sectionSize]=tempScore; //保存分数只是为了阅读
sectionSize++;
cout<<"Score: ";
cin>>tempScore;
} //结束while
//已读取哨兵或已填充阵列
if(tempScore!=SENTINEL)
{
cout<<"Array is filled!"<<endl;
cout<<tempScore<<" not stored"<<endl;
}
}
例子:函数readScoresFile
//从文件中读取最多MAX_SIZE名学生的讲座部分的考试成绩数组
//pre:无
//post:数据值从文件中读取并存储在数组分数中.读取的值数存储在节中大小.
void readScoresFile(ifstream& ins,int scores[],const int MAX_SIZE,int& sectionSize)
{
int tempScore; //每个分数的临时存储
//读取每个数组元素,直到完成
sectionSize=0; //初始化班级规模
ins>>tempScore;
while(!ins.eof()&&(sectionSize<MAX_SIZE))
{
scores[sectionSize]=tempScore; //保存分数只是阅读
sectionSize++;
}//结束while
//到达文件末尾或阵列已满
if(!ins.eof())
{
cout<<"Array is filled!"<<endl;
cout<<tempScore<<"not stored"<<endl;
}
}
9.5查找和排序数组
查找数组以便确定一个特定值在数组中的位置和对数组进行排序,以一种新的顺序重新排列数组元素。
9.5.1查找数组中的最小值
例子:函数findIndexOfMin
//查找子数组中最小值的下标
//返回子数组中最小值的下标
//由元素 x[起始索引] 到 x[结束索引] 组成
//如果子数组边界无效,则返回 -1
//pre:子数组已定义且为 0<=起始索引<=结束索引
//post:x[最小索引] 是数组中的最小值
int findIndexOfMin(const float x[],int startIndex,int endIndex)
{
int minIndex; //找到的最小元素的索引
int i; //当前元素的索引
//验证子数组边界
if((startIndex<0)||(startIndex>endIndex))
{
cerr<<"Error in subarray bounds"<<endl;
return -1; //返回错误指示器
}
//假设子数组的第一个元素最小,并检查
//min索引将包含迄今为止检查的最小下标
minIndex=startIndex;
for(i=startIndex+1;i<=endIndex;i++)
if(x[i]<x[minIndex])
minIndex=i;
//断言:检查所有元素,最小索引是最小元素的索引
return minIndex; //返回结果
}//结束findIndexOfMin
9.5.2程序风格–作为注释的断言
断言:使得关于程序的语句必须为true的注释。
9.5.3数组查找
例子:函数linSearch
//在整数数组中搜索给定元素(目标)
//搜索大小从 0 到 -1 的数组元素,以查找等于目标的元素
//pre:目标和阵列已定义
//post:返回目标的下标(如果找到);否则,返回-1;
int linSearch(const int items[],int target,int size)
{
for(int next=0;next<size;next++)
if(items[next]==target)
return next; //找到,返回下标
//断言:所有元素都经过测试,但没有成功.
return -1;
}//结束linSearch
9.5.4对数组按升序进行排序
例子:函数selSort
//使用选择排序算法对数组进行排序(升序),使用交换和查找索引的索引
//对数组项(项[0] 到项 [n-1]) 中的数据进行排序
//pre:项目已定义,并且 n<= 实际参数数组的声明大小。
//post:从项目[0]到项目[n-1]中的值按递增顺序排列。
void selSort(float items[], int n)
{
int minSub; //每个最小项目的下标由查找索引的最小项目
for(int i=0;i<n-1;i++)
{
//在项目的未排序部分中查找最小元素的索引。
minSub=findIndexOfMin(items,i,n-1);
//在位置minSub和i交换物品
exchange(items[minSub],items[i]);
}
}
9.6 Big-O方法分析算法
有最大项是nn的尾为O(nn).
9.6.1查找算法的分析
为了定位数组中的目标值,必须测试n/2个数组元素。这就意味着线性查找算法的时间复杂度是O(n)。
9.6.2排序算法的分析
9.7结构体数据类型
结构体:一种可以用于存储不同数据类型的相关数据项集合的数据结构。
成员:结构体中的一个独立的组成部分。
9.7.1声明结构体类型和结构体变量
**结构体类型声明**
**格式**:struct struct_type
{
type1 id_list1;
type2 id_list2;
......
typen id_listn;
};
**实例**:struct complex
{
float realPart,imaginaryPart;
};
9.7.2访问结构体成员
成员访问运算符:在结构体变量名和成员名之间放置一个句点。
例子:
cout<<"The organist is ";
switch(organist.gender)
{
case 'F':case 'f':
cout<<"MS. ";
break;
case 'M':case 'm':
cout<<"Mr. ";
break;
default:
cout<<organist.gender<<" is bad character for gender!"<<endl;
}
cout<<organist.name<<endl;
9.8结构体作为操作数和参数
9.8.1结构体复制或赋值
organist=janitor; //将janitor复制给organist
9.8.2结构体作为参数进行传递
例子:函数printStats
//打印考试统计数据
//pre:结构变量 stuExam 的成员被赋值。
//post:显示每个实例成员.
void printStats(examStats stuExams)
{
cout<<"Exam scores for "<<stuExams.stuName<<": "
cout<<stuExams.scores[0]<<' '<<stuExams.scores[i]<<' '<<stuExams.scores[2]<<endl;
cout<<"Average score: "<<stuExams.average<<endl;
cout<<"Letter grade: "<<stuExams.grade<<endl;
}
9.8.3读取结构体
例子:函数readEmployee
//将一份员工记录读入一名员工
#include<string>
#include<iostream>
//pre:无
//post:数据被读入结构一员工
void readEmployee(employee& oneEmployee) //输出:读取数据的目标
{
cout<<"Enter a name terminated with the symbol # : ";
getline(cin,oneEmployee.name,'#');
cout<<"Enter an id number: ";
cin>>oneEmployee.id;
cout<<"Enter gender(F or M): ";
cin>>oneEmployee.gender;
cout<<"Enter number of dependents: ";
cin>>oneEmployee.numDepend;
cout<<"Enter hourly rate: ";
cin>>oneEmployee.rate;
}
9.8.4引用参数的效率
9.9字符串作为字符数组
9.9.1声明和初始化字符数组
字符串的声明:
char name[]=“Jackson”;或者
char name[8]=“Jackson”
最后一个字符存储的是‘\0’,即NULL字符,c++用它来标记字符数组中字符串的结尾。
9.9.2读写字符数组
1)可以使用插入运算符显示存储在name中的整个字符串。
例子:cout<<name<<endl;
2)使用如下循环显示数组中的每一个字符。
例子:
int i=0;
>while(name[i]!='\0'){
cout<<name[i];
i++;
}