概述
迄今为止,我们介绍了简单的数据类型:整形、实型、字符型以及数组定义的变量,其中数组中各元素都具有相同的类型。
现在,我们要处理一个学生的数据: 包括姓名, 年级 , 性别, 地址等不同的数据类型又该如何处理?
在数据库中,我们通常要用“记录”来描述一个实体:如学生、教材、……
在C语言中,允许程序员自定义类型,这就是结构:
一、结构体(struct)定义和操作
第一种定义方式:
第二种定义方式:
也可以不定义结构类型,而直接定义结构变量。
定义了student类型,同时定义了student类型的三个变量stud1、stud2、stud3。注意分号的位置。
二、结构体变量的特点
(1)结构体变量可以整体操作,
例如: swap(a[j],a[j+1]);
(2)结构体变量的成员访问也很方便、清晰,
例如: cin>>a[i].name;
(3)结构体变量的初始化和数组的初始化类似,
例如: student op={"gaoxiang",89,90,179};
三、成员调用
结构体变量与各个成员之间引用的一般形式为:
结构体变量名 . 成员名
对于上面定义的结构体变量,我们可以这样给成员赋值: cin>>a[i].name; 不能写成cin>>a[i];
a[i].total=a[i].chinese+a[i].math; //就像用整型变量一样
实际上结构体成员的操作与该成员类型所具有的操作是一致的。
成员运算符“.”在存取成员数值时使用,其优先级最高,并具有左结合性。
在处理包含结构体的结构体时,可记作: strua.strub.membb 这说明结构体变量strua有结构体成员strub;结构体变量strub有成员membb。
四、成员函数调用
结构体成员函数调用的一般形式为: 结构体变量名.成员函数 结构体成员函数默认将结构体变量作为引用参数。
五、例题
例1、学生信息
【问题描述】
输入一个学生的信息,包括姓名、性别、年龄、体重,再输出这些信息。
【输入格式】
一行,依次是学生的姓名、性别、年龄、体重。
【输出格式】
一行,依次是姓名、性别、年龄、体重(体重保留一位小数)。
【输入样例】
zhangsan m 20 90.5
【输出样例】
zhangsan m 20 90.5
#include<bits/stdc++.h>
using namespace std;
struct student{
string name;
char sex;
int age;
double weight;
};
int main(){
student stu;
cin >> stu.name >> stu.sex >> stu.age >> stu.weight;
cout <<stu.name <<" "<< stu.sex <<" "<< stu.age <<" "<< stu.weight << endl;
return 0;
}
例2、成绩统计。输入N个学生的姓名和语文、数学的得分,按总分从高到低输出。
输入格式:
第1行,有一个整数N,N的范围是[1…100];
下面有N行,每行一个姓名,2个整数。姓名由不超过10个的小写字母组成,整数范围是[0…100]。
输出格式:
总分排序后的名单,共N行,每行格式:姓名 语文 数学 总分。
输入样例:
4
gaoxiang 78 96
angxi 70 99
liujia 90 87
zhangjin 78 91
输出样例:
liujia 90 87 177
gaoxiang 78 96 174
wangxi 70 99 169
zhangjin 78 91 169
分析:由于姓名是字符串,分数是整数,如果用数组保存,则要两个数组,比如: string name[100]; int score[100][3]; 这种方法不利于把一个学生的信息当成一个整体处理。
下面程序中通过使用结构(struct)类型的方法来解决这个问题。
#include<bits/stdc++.h>
using namespace std;
struct student
{ string name;
int chinese,math;
int total;
}; //定义一个struct的类型,类型名叫:student
student a[110]; //定义一个数组a,每个元素是student类型
int n;
int main()
{ cin>>n;
for (int i=0; i<n; i++) //对结构体中成员的赋值、取值。
{ cin>>a[i].name;
cin>>a[i].chinese>>a[i].math;
a[i].total=a[i].chinese+a[i].math;
}
for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++) //冒泡排序
if (a[j].total<a[j+1].total) swap(a[j],a[j+1]);
for (int i=0; i<n; i++) //输出
cout<<a[i].name<<' '<<a[i].chinese<<' '<<a[i].math<<' '<<a[i].total<<endl;
return 0;
}
用sort排序:
#include<bits/stdc++.h>
using namespace std;
struct student
{ string name;
int chinese,math;
int total;
}; //定义一个struct的类型,类型名叫:student
student a[110]; //定义一个数组a,每个元素是student类型
bool cmp(student a,student b)
{
return a.total>b.total;
}
int n;
int main()
{ cin>>n;
for (int i=0; i<n; i++) //对结构体中成员的赋值、取值。
{ cin>>a[i].name;
cin>>a[i].chinese>>a[i].math;
a[i].total=a[i].chinese+a[i].math;
}
sort(a,a+n,cmp);
for (int i=0; i<n; i++) //输出
cout<<a[i].name<<' '<<a[i].chinese<<' '<<a[i].math<<' '<<a[i].total<<endl;
return 0;
}
例3、年龄排序
【问题描述】
输入 n 个学生的信息,包括姓名、性别、出生年月。要求按年龄从小到大依次输出这些学生的信息。数据保证没有学生同年同月出生。
【输入格式】
第一行一个整数 n,表示学生人数,n≤100。
接下来 n 行,每一行依次输入学生的姓名、性别、出生年份、出生月份。
【输出格式】
按年龄从小到大,一行输出一个学生的原始信息。
【输入样例】
5
John male 1999 12
David female 1999 8
Jason male 1998 11
Jack female 1998 8
Kitty female 2000 7
【输出样例】
Kitty female 2000 7
John male 1999 12
David female 1999 8
Jason male 1998 11
Jack female 1998 8
#include<bits/stdc++.h>
using namespace std;
struct stu
{
string name;
string sex;
int year,month;
};
const int MAXN = 110;
stu a[MAXN];
int main()
{ int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i].name >> a[i].sex >> a[i].year >> a[i].month;
for(int i = 1; i <= n; i++)
for(int j = i+1; j <= n; j++)
if(a[i].year < a[j].year || a[i].year == a[j].year && a[i].month < a[j].month)
swap(a[i],a[j]);
for(int i = 1; i <= n; i++){
cout<< a[i].name <<" "<< a[i].sex <<" ";
cout<< a[i].year <<" "<< a[i].month << endl;
}
return 0;
}
用sort排序:
#include<bits/stdc++.h>
using namespace std;
struct stu
{
string name;
string sex;
int year,month;
};
const int MAXN = 110;
stu a[MAXN];
bool cmp(stu a,stu b)
{ return a.year > b.year || a.year == b.year && a.month > b.month;
}
int main()
{ int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i].name >> a[i].sex >> a[i].year >> a[i].month;
sort(a+1,a+n+1,cmp);
for(int i = 1; i <= n; i++){
cout<< a[i].name <<" "<< a[i].sex <<" ";
cout<< a[i].year <<" "<< a[i].month << endl;
}
return 0;
}
例5、 离散化基础。
以后要学习使用的离散化方法编程中,通常要知道每个数排序后的编号(rank值)。
输入格式:
第1行,一个整数N,范围在[1…10000];
第2行,有N个不相同的整数,每个数都是int范围的。
输出格式:
依次输出每个数的排名。
输入样例:
5
8 2 6 9 4
输出样例:
4 1 3 5 2
分析:
排序是必须的,关键是怎样把排名写回原来的数“下面”。程序使用了分别对数值和下标不同关键词2次排序的办法来解决这个问题,一个数据“节点”应该包含数值、排名、下标3个元素,用结构体比较好。
#include<bits/stdc++.h>
using namespace std;
struct node
{ int data; //数值
int rank; //排名
int index; //下标
}; //定义struct类型
node a[10001];
int n;
bool comp1(node x,node y)
{ return x.data<y.data;} //自定义比较函数
bool comp2(node x,node y)
{ return x.index<y.index;} //自定义比较函数
int main()
{ cin>>n;
for (int i=1; i<=n; i++)
cin>>a[i].data,a[i].index=i;
sort(a+1,a+1+n,comp1); //根据值排序,求排名rank
for (int i=1; i<=n; i++) a[i].rank=i;
sort(a+1,a+1+n,comp2); //根据下标排序,回到原数据次序
for (int i=1; i<=n; i++)
cout<<a[i].rank<<' ';
return 0;
}