C++数据结构篇 第一章 结构体和共用体

一、结构体

5.1   概述

        迄今为止,我们介绍了简单的数据类型:整形、实型、字符型 以及 数组变量,其中,数组中各元素都具有相同的类型。
        在存储和处理大批量数据时,一般会使用数组来实现,但是每一个数据的类型及含义必须一样。如果需要把不同类型、不同含义的数据当作一个整体来处理,如 1000 个学生的姓名、性别、年龄、体重、成绩等,怎么处理呢?
        C++ 提供了结构体(struct)来解决这类问题。
 

5.2   结构体的定义

         C++ 中的结构体是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。

        使用结构体,必须要先声明一个结构体类型,再定义和使用结构体变量。 
 
        第一种定义声明方式: 
 
      

 

 
      
      第二种定义方式:   也可以不定义结构类型,而直接定义结构变量
      

           

1 定义一个反映学生基本情况的结构类型
struct  date         //日期结构类型:由年、月、日三项组成
{   int year;  
    int month;
    int day;
};                   //分号不能少

struct  std_info     //学生信息结构类型:由学号、姓名、性别和生日组成
{   char  no[11]; 
    char  name[9]; 
    char  sex[3]; 
    struct date birthday;
};                   //分号不能少

struct  score        //成绩结构类型:由学号和三门成绩共4项组成
{   char  no[11]; 
    int  score1;
    int  score2;
    int  score3;
};                   //分号不能少

 

5.3  结构体变量的初始化

结构变量初始化的格式,与一维数组相似:     结构变量 = {初值表}
 
struct  std_info  stud={“2000281021”, “张红“ , "男”, {1983,9,20} };

 

5.4  访问结构成员

1. 结构体变量的引用方式: 结构体变量 . 成员
 
[例2] 利用[例1]中定义的结构类型struct std_info,定义一个结构变量student,用于存储和显示一个学生的基本情况。
 
#include<bits/stdc++.h>
struct  date
{    int year;  
     int month;
     int day;
};

struct  std_info
{    char  no[11]; 
     char  name[9]; 
     char  sex[3]; 
     struct date birthday;
} stud={"2000281021","张红","男",{1983,9,20}};

int main()
{   printf("No: %s\n",stud.no);
    printf("Name: %s\n",stud.name);
    printf("Sex: %s\n",stud.sex);
    printf("Birthday: %d-%d-%d\n",stud.birthday.year,
                                  stud.birthday.month, 
                                  stud.birthday.day   ); 
}
 
 

5.5  结构体数组 (具有相同结构类型的变量集合)

1、定义一个结构体数组:

 
     
 
 
 [例3]  定义一个结构,该结构由课程号,课程名、学时数和任课教师等四个成员项组成,建立一个由四门课程构成的结构数组 ,每门课程都具有所定义的结构类型。通过键盘输入,对各个数组元素的每个成员项赋值,然后输出每门课程的有关信息。
 
#include<bits/stdc++.h>
#define N 4
using namespace std;
struct sct
{  char cno[4];
   char cname[20];
   int chour;
   char teacher[10]; 
};

int main()
{  struct sct course[N];
   int i;
   for(i=0;i<N;i++)
   { printf("Enter cnum:");
     scanf("%s",course[i].cno);
     printf("Enter cname:");
     scanf("%s",course[i].cname);
     printf("Enter chour:");
     scanf("%d",&course[i].chour);
     printf("Enter teacher:");
     scanf("%s",course[i].teacher);
   }
   printf("学号\t 课程名\t 学时\t 教师 \n");
   for(i=0;i<N;i++)
   printf("%-8s%-12s%-8d%-20s\n",course[i].cno,
                                 course[i].cname,
                                 course[i].chour,
                                 course[i].teacher);
}

 

2.  结构数组的引用方式
 
结构数组的每一个元素,都是结构类型数据,均包含结构类型的所有成员。
 
[例4] 利用[例1]中定义的结构类型struct  std_info,定义一个结构数组student,用于存储和显示三个学生的基本情况。
 
#include<bits/stdc++.h>
struct  date{ int year; int month; int day; };
struct  std_info{ char  no[11];  char  name[9];  char  sex[3]; 
                  struct date birthday; } ;
struct std_info stud[3]={{"20028102","张明","男",{1982,9,20}},
                         {"20028105","李明","男",{1983,8,15}},
                         {"20028112","王琳","女",{1983,3,10}}};   
   
int main()
{ int i;
   printf("No.\tName\tSex\tBirthday\n"); /*打印表头*/
   for(i=0; i<3; i++) /*输出三个学生的基本情况*/
   { printf("%s\t",stud[i].no);
     printf("%s\t",stud[i].name);
     printf("%s\t",stud[i].sex);
     printf("%d-%d-%d\n",stud[i].birthday.year, 
                         stud[i].birthday.month,
                         stud[i].birthday.day );
   }
}
 
例5、输入N个学生的姓名和语文、数学的得分,按总分从高到低输出。分数相同的按输入先后输出。
 
1、用swap()交换函数,冒泡排序
 
#include<bits/stdc++.h>
using namespace std;
struct student
{	string name;
	int yw,sx;
	int total;	
} a[100];
int n;
int main()
{  cin>>n;
   for(int i=1;i<=n;i++)//对结构体中成员的赋值、取值。
   { cin>>a[i].name>>a[i].yw>>a[i].sx;
     a[i].total=a[i].yw+a[i].sx;
   }
   for(int i=1;i<n;i++) 
     for (int j=1; j<=n-i;j++) //冒泡排序 
       if (a[j].total<a[j+1].total)  swap(a[j],a[j+1]);        
   for(int i=1;i<=n;i++)//输出 
      cout<<a[i].name<<" "<<a[i].yw<<" "<<a[i].sx<<" "<<a[i].total<<endl;
   return 0;
}

输入:

4
a 78 23
b 55 67
c 67 89
d 67 45
 
输出:
 
 
2、用sort函数排序:
#include<bits/stdc++.h>
using namespace std;
struct student
{	string name;
	int yw,sx;
	int total;	
} a[100];
int n;
bool cmp(student a,student b)
{ return a.total>b.total;
}
int main()
{  cin>>n;
   for(int i=1;i<=n;i++)//对结构体中成员的赋值、取值。
   { cin>>a[i].name>>a[i].yw>>a[i].sx;
     a[i].total=a[i].yw+a[i].sx;
   }
   sort(a+1,a+n+1,cmp);       
   for(int i=1;i<=n;i++)//输出 
      cout<<a[i].name<<" "<<a[i].yw<<" "<<a[i].sx<<" "<<a[i].total<<endl;
   return 0;
}

输入:

4
a 78 23
b 55 67
c 67 89
d 67 45
 
输出:
 
 

 

 

5.6  结构体的扩展

C++ 中,由于类(class)技术的出现使结构体功能得到了很大的增强。
 
1. 运算符重载
运算符重载常用于解决结构体或自定义数据类型的加法、减法等特殊含义的运算。运算符重载的一般格式为:
 
        类型名 operator 运算符 (const 类型名 变量)cons t
        {
              
        }
 
  例6、作业统计 
【问题描述】
为了了解学生的课后作业负担情况,需要统计学生连续若干天完成作业所需的总时间。现在,输入某位学生 n 天完成作业的时间,格式为时、分、秒,最后输出这位学生 n 天完成作业的总时间(秒)。
【输入格式】
1 行一个正整数 n,表示有 n 天;
2~ n+1 行,每行 3 个整数,分别代表时、分、秒。
【输出格式】
一行信息,表示这个学生完成作业的总时间,具体格式见输出样例。
【输入样例】
3
1 20 30
1 20 45
1 19 30
【输出样例】
4hour   0minute    45second
 
【问题分析】
本题需要把若干时间(时、分、秒)相加,但又不是普通的加法运算。所以,可以利用运算符重载,另外定义一个+运算,实现对两个结构体变量的加法。
#include<bits/stdc++.h>
using namespace std;
struct worktime  // 声明一个结构体类型 worktime 记录学生完成作业的时间
{  int hr,minut,sec; // hr,minut,sec 分别代表时分秒
   worktime operator +(const worktime x)const   // 对 + 进行重新定义
   {   worktime tmp;
       tmp.sec = (sec + x.sec) % 60;
       tmp.minut = (minut + x.minut + (sec + x.sec) / 60) % 60;
       tmp.hr = hr + x.hr + (minut + x.minut + (sec + x.sec) / 60) / 60;
       return tmp;
   }
};
int main(){
    worktime stu,sum;
    int n;
    cin >> n;
    sum.hr = sum.minut = sum.sec = 0;
    for(int i = 1; i <= n; i++){
          cin >> stu.hr >> stu.minut >> stu.sec;
          sum = sum + stu;// 两个结构体 sum 和 stu 通过重载 + 运算符进行加法运算
    }
    cout <<sum.hr<<"hour"<<sum.minut<<"minute" <<sum.sec<<"second" ;
    return 0;
}

 

 
2. 成员函数
C++ 中,允许在结构中定义函数,该函数称为成员函。描述形式如下:
 
            struct    结构名
         {
                数据成员
               成员函数
        };  
 
 
  例7、身高问题 
 
【问题描述】
输入 n 个学生的信息,每个学生信息包括姓名、身高、学号。编程输出身高最高的学生的信息。
【输入格式】
1 行一个正整数 n,表示学生个数,n100
以下 n 行,每一行依次输入学生的姓名、身高、学号。
【输出格式】
输出最高的学生信息,如存在身高一样的请输出学号小的那个同学。
【输入样例】
5
John 172 20160302
David 173 20160306
Jason 168 20160309
Jack 152 20160311
Kitty 147 20160319
【输出样例】
David 173 20160306
 
#include<bits/stdc++.h>
using namespace std;
struct stu
{   string name;
    int heigh;
    int num;
    void input()
    {   cin >> name >> heigh >> num;    }
    void output()
    {   cout<<name<<"  "<<heigh <<"  "<<num<<endl;    }
} a[110];
int main()
 {  int n;
    stu maxn;
    maxn.heigh = maxn.num = 0;
    cin >> n;
    for(int i = 1; i <= n; i++)
    {   a[i].input();
        if(a[i].heigh > maxn.heigh) maxn = a[i];
        else if(a[i].heigh == maxn.heigh && a[i].num < maxn.num) maxn = a[i];
    }
    maxn.output();
    return 0;
}

 

二、共用体

        在 C++ 中,共用体也称联合(union),是一种数据格式,能存储不同类型数据,但同一时间只能存储其中的一种类型数据。例如,存放一个人的信息,如果是成年人,存放他的身份证号码;否则,存放他的学籍号。这里面就有两个成员,但是任何一个人只能使用其中的一个。
使用共用体前必须先声明一个共用体类型,才可以定义和使用共用体变量。例如,要声明一个记录个人信息的共用体,可以这样:
                  union person           // 声明一个共用体类型 person
               {     char id[18];         // 声明一个字符数组,存储身份证号码
                      int num;              // 声明一个整数,存放学籍号
                };
  
 
  例1、成绩统计
【问题描述】
兴趣小组收集学员成绩信息,每个学员的成绩有两种表示方法,一种用 bestgoodpoor 三种等级来表示,还有一种就是直接用分数来表示(百分制)。请保存学员成绩信息,并且统计有多少人是用等级来表示成绩的,用分数来表示成绩的人的平均分是多少(取整就行)。
【输入格式】
1 行一个正整数 n,表示学员人数,n1000
2~n+1 行,每行一个字符和一个字符串,中间用一个空格隔开。第一个字符表示这个学生成绩类型,有 CN 两种分别代表等级表示和分数表示,第二个字符串表示成绩信息。  
【输出格式】
一行两个整数,分别表示用等级表示成绩的人数和用分数表示成绩人的平均分(取整),中间用一个空格隔开。
【输入样例】
5
C best
C good
N 90
C poor
N 98
【输出样例】
3 94
 
#include<bits/stdc++.h>
using namespace std;
int main()
{   union res            // 声明一个共用体 res
   {   char rank[5];     // 用等级表示成绩
       int x;            // 用分数表示成绩
   };
    struct stu
    {  char f;          // 代表学生用哪种方式记录成绩
       res score;       // 定义 score 为共用体
    }  a[1001];
    int n,count = 0, num = 0;
    cin >> n;
    for(int i = 1; i <= n; i++)
	{  cin >> a[i].f;
       switch(a[i].f)
       {  case 'C':for(int j=0;j<4;j++) cin>>a[i].score.rank[j]; count++;break;
          case 'N':cin>>a[i].score.x;   num += a[i].score.x;
       }
    }
    cout<<count<<"  "<<num/(n-count)<<endl;
    return 0;
}

 

三、结构体练习:

 

1、近似排序

试题描述
读入一对正整数,将这两个数之间(包括这两个数本身)的所有数按下述特别规则排序后输出,该特别规则是按两数倒过来的值进行比较决定其大小,如30倒过来为3,29倒过来为92,则29大于30.

输入要求
1行两个正整数x和y,用一个空格隔开,1<=x<=y<=10000,y-x<=100

输出要求
包括y-x+1行,每行一个正整数,按两数到过来的值进行比较决定其大小,然后由小到大输出。

输入样例
22 39

输出样例
30
31
22
32
23
33
24
34
25
35
26
36
27
37
28
38
29

 

2、奖学金   NOIP普及组 2007 第一题

题目描述

某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。期末,每个学生都有3门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学 排在前面,这样,每个学生的排序是唯一确定的。

任务:先根据输入的3门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名名学生的学号和总分。注意,在前5名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:

7   279
5   279

这两行数据的含义是:总分最高的两个同学的学号依次是7号、5号。这两名同学的总分都是 279 (总分等于输入的语文、数学、英语三科成绩之和) ,但学号为7的学生语文成绩更高一些。如果你的前两名的输出数据是:

5   279
7   279

则按输出错误处理,不能得分。

输入格式

共n+1行。

第1行为一个正整数n(≤300),表示该校参加评选的学生人数。

第2到n+1行,每行有3个用空格隔开的数字,每个数字都在0到100之间。第 j 行的3个数字依次表示学号为j−1的学生的语文、数学、英语的成绩。每个学生的学号按照输入顺序编号为1~n(恰好是输入数据的行号减1)。

所给的数据都是正确的,不必检验。

输出格式

共5行,每行是两个用空格隔开的正整数,依次表示前5名学生的学号和总分。

输入输出样例

样例输入一

6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98

样例输出一

6 265
4 264
3 258
2 244
1 237

样例输入二

8
80 89 89
88 98 78
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98

样例输出二

8 265
2 264
6 264
1 258
5 258

3、生日相同

描述

在一个有180人的大班级中,存在两个人生日相同的概率非常大,现给出每个学生的名字,出生月日。试找出所有生日相同的学生。

输入

第一行为整数n,表示有n个学生,n ≤ 180。此后每行包含一个字符串和两个整数,分别表示学生的名字(名字第一个字母大写,其余小写,不含空格,且长度小于20)和出生月(1 ≤ m ≤ 12)日(1 ≤ d ≤ 31)。名字、月、日之间用一个空格分隔

输出

每组生日相同的学生,输出一行,其中前两个数字表示月和日,后面跟着所有在当天出生的学生的名字,数字、名字之间都用一个空格分隔。对所有的输出,要求按日期从前到后的顺序输出。 对生日相同的名字,按名字从短到长按序输出,长度相同的按字典序输出。如没有生日相同的学生,输出”None”

样例输入

6
Avril 3 2
Candy 4 5
Tim 3 2
Sufia 4 5
Lagrange 4 5
Bill 3 2

样例输出

3 2 Tim Bill Avril
4 5 Candy Sufia Lagrange

 

 

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值