第 8 章 c++ 结构体,链表

63
1 第 8 第 C++ 第第 第第 体, 第 9 第第第

Upload: tauret

Post on 27-Jan-2016

199 views

Category:

Documents


3 download

DESCRIPTION

第 8 章 C++ 结构体,链表. 第 9 次见面!. 学习新内容了,准备好了吗?. 记住 :. 学习是快乐的~. 第 8 章 数据封装 — 结构体. 结构体的概述 结构体类型的定义 结构体类型的变量 结构体数组 结构体作为函数的参数 链表. 结构体的概念. 打印学生成绩单 ,格式如下:. 如何在程序中表示这组学生信息?. 可选方案. 用二维的数组来表示 该方案不可行,因为这些信息有不同的类型 每一列用一个一维数组来表示,这种方法称为并联数组。 要保证每位学生信息的正确性很难. 为什么要使用记录. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 8 章  C++ 结构体,链表

1

第 8 章 C++ 结构体,链表

第 9 次见面!

Page 2: 第 8 章  C++ 结构体,链表

2

学习新内容了,准备好了吗?

记住 :

Page 3: 第 8 章  C++ 结构体,链表

第 8 章 数据封装—结构体

• 结构体的概述• 结构体类型的定义• 结构体类型的变量• 结构体数组• 结构体作为函数的参数• 链表

Page 4: 第 8 章  C++ 结构体,链表

结构体的概念• 打印学生成绩单 ,格式如下:

学号 姓名 语文成绩 数学成绩 英语成绩 .

00001 张三 96 94 88

00003 李四 89 70 76

00004 王五 90 87 78

如何在程序中表示这组学生信息?

Page 5: 第 8 章  C++ 结构体,链表

可选方案

• 用二维的数组来表示–该方案不可行,因为这些信息有不同的类型

• 每一列用一个一维数组来表示,这种方法称为并联数组。–要保证每位学生信息的正确性很难

Page 6: 第 8 章  C++ 结构体,链表

为什么要使用记录

• 当我们考虑怎么逻辑地组织数据时,应该将一个人的所有信息项放在一起,即保持相关性。

学号 姓名 语文成绩 数学成绩 英语成绩 .

00001 张三 96 94 88

00003 李四 89 70 76

00004 王五 90 87 78

Page 7: 第 8 章  C++ 结构体,链表

我们希望的结构

学生一

00001

张三96

94

88

学生二

00003

李四89

70

76

学生三

00004

王五90

87

78

记录

在 C++ 中称为结构体

Page 8: 第 8 章  C++ 结构体,链表

结构体类型作用• 结构体类型允许程序员把一些分量聚合

成一个整体,用一个变量表示。• 一个结构体的各个分量都有名字,把这

些分量称为成员 (member) 。• 由于结构体的成员可以是各种类型的,

程序员能创建适合于问题的数据聚合。

Page 9: 第 8 章  C++ 结构体,链表

结构体的使用

• 定义一个新的结构体类型 • 定义新类型的变量 • 访问结构体变量

Page 10: 第 8 章  C++ 结构体,链表

结构体类型的定义• 定义结构体类型中包括哪些分量• 格式:

struct 结构体类型名 {

字段声明;} ;

如:struct studentT {

char no[10];

char name[10];

int chinese;

int math;

int english;

};

Page 11: 第 8 章  C++ 结构体,链表

注意

• 字段名可与程序中的变量名相同 • 在不同的结构体中可以有相同的字段名 • 结构体成员的类型可以是任意类型,当

然也可以是结构体类型

Page 12: 第 8 章  C++ 结构体,链表

struct dateT{ int month;

int day;int year;};

struct studentT{ ...

dateT birthday;}; 

Page 13: 第 8 章  C++ 结构体,链表

指向记录的指针

• 直接定义指针变量 studentT *sp;

• 也可以在定义结构体类型的同时定义指向结构体的指针

struct 结构体类型名 {

字段声明;

} * 结构体指针;

Page 14: 第 8 章  C++ 结构体,链表

通过指针操作记录• 给结构体指针赋值,如: sp = &student1;

• 结构体指针的引用:(*指针 ).成员 如:

(*sp).name 指针 -> 成员 如: sp->name

student1. 成员

-> 是所有运算符中优先级最高的

通常程序员习惯使用第二种方法

Page 15: 第 8 章  C++ 结构体,链表

单链表

nil

head

头结点

只指出后继关系的链表

Page 16: 第 8 章  C++ 结构体,链表

双链表

head

循环链表

head

同时存储前趋和后继

Page 17: 第 8 章  C++ 结构体,链表

单链表的存储

struct linkRec {

datatype data; linkRec *next;

}

存储链表就是存储链表中的一个节点的地址,因此需要定义一个节点类型

Page 18: 第 8 章  C++ 结构体,链表

单链表操作—插入

• 申请空间• 输入数据放入申请到的空间• 链入 p 后

在结点 p 后插入一个结点 head p

tmp

Page 19: 第 8 章  C++ 结构体,链表

tmp = new LinkRec; // 创建一个新节点

tmp->data = x; // 把 x 放入新节点的数据成员中

tmp->next = p->next; // 把新节点和 p 的下一成员相连

p->next = tmp; // 把 p 和新节点连接起来

Page 20: 第 8 章  C++ 结构体,链表

单链表操作—删除把结点 p 后的结点删除

head p

delPtr

delPtr=p->next;

p->next=delPtr->next;

delete delPtr;

Page 21: 第 8 章  C++ 结构体,链表

单链表操作 -- 建立• 定义头指针: linkRec *head;

• 建立头结点– 申请空间– 设为头结点

head

Page 22: 第 8 章  C++ 结构体,链表

单链表操作 -- 建立(续)

• 逐个从键盘输入数据,存入链表 – 接受输入– 申请空间– 输入数据放入申请到的空间– 链入链表尾

• 置链表结束标志head

a b c d ^

Page 23: 第 8 章  C++ 结构体,链表

head = new linkRec;

rear = head;

Cin >> in_data;

while( 输入未结束 )

{ p= new linkRec;

p->data = in_data;

rear->next = p;

rear=p;

cin >> in_data;

}

rear->next = NULL;

Page 24: 第 8 章  C++ 结构体,链表

单链表操作—输出head

a b c d ^

p = head->next;

while ( p != NULL)

{ cout << p->data;

p = p->next;

}

Page 25: 第 8 章  C++ 结构体,链表

创建并访问一个带头结点的、存储整型数据的单链表,数据从键盘输入, 0 为输入结束标志。

#include <iostream>using namespace std; struct linkRec { int data; linkRec *next;};

Page 26: 第 8 章  C++ 结构体,链表

int main(){ int x; // 存放输入的值 linkRec *head, *p, *rear; head = rear = new linkRec;  while (true) { // 创建链表的其他结点 cin >> x; if (x == 0) break; p = new linkRec; p->data = x; rear->next = p; rear = p; }  rear->next = NULL; // 设置 rear 为表尾,其后没有结点了  // 读链表 cout << " 链表的内容为: \n"; p = head->next; while (p != NULL) { cout << p->data << '\t'; p = p->next; } cout << endl;  return 0;}

Page 27: 第 8 章  C++ 结构体,链表

单链表

• 链表的概念

• 链表的存储

• 链表的操作

• 链表的应用

• 循环链表

Page 28: 第 8 章  C++ 结构体,链表

链表的应用

合并二个有序链表

A 1 3 5 6

2 74B 98

1

C 1 8765432 9

Page 29: 第 8 章  C++ 结构体,链表

struct LinkRec {int data; struct lk *next; }LinkRec *merge(LinkRec *a, LinkRec *b) {LinkRec *c, *p; if (a->data < b->data) {c=a; a=a->next;} else {c=b;b=b->next;} p=c; while (a!=NULL && b!= NULL) { if (a->data < b->data) {p->next=a; a=a->next;} else {p->next=b; b=b->next;} p=p->next; } if (a==NULL) p->next=b; else p->next=a; return (c);

}

Page 30: 第 8 章  C++ 结构体,链表

第 9 章 模块化开发

• 自顶向下的分解• 模块划分• 库的设计与实现• 库的应用

Page 31: 第 8 章  C++ 结构体,链表

设计自己的库 • 如果你的工作经常要用到一些特殊的工具,你可

以设计自己的库• 一个库应该有一个主题。一个库中的函数都应该

是处理同一类问题。如标准库 iostream 包含输入输出功能, cmath 包含数学运算函数。我们自己设计的库也要有一个主题。

• 设计一个库还要考虑到它的通用性。库中的功能应来源于某一应用,但不局限于该应用,而且要高于该应用。在某一应用程序中提取库内容时应尽量考虑到兼容更多的应用,使其他应用程序也能共享这个库。

Page 32: 第 8 章  C++ 结构体,链表

库的设计和实现• 设计库的接口:

– 库的用户必须了解的内容,包括库中函数的原型、这些函数用到的符号常量和自定义类型

– 接口表现为一个头文件

• 设计库中的函数的实现:表现为一个源文件

• 库的这种实现方法称为信息隐藏

Page 33: 第 8 章  C++ 结构体,链表

随机函数库的设计

• 库的功能 – 用一个函数概括:生成 low 到 high 之间的随机数 int RandomInteger(int low, int high)

– 初始化函数 RandomInit() 实现设置随机数种子的功能 – srand(time(NULL)); 封装这个函数– 使用 rand() 这个函数

用到了随机数的一些特性。如果我们的工作经常需要用到随机数,我们可以把随机数的应用写成一个库。

Page 34: 第 8 章  C++ 结构体,链表

接口文件

• 头文件的格式:

• 头文件中,每个函数声明前应该有一段注释,告诉用户如何使用这些函数。

Page 35: 第 8 章  C++ 结构体,链表

库接口的设计// 文件: Random.h// 随机函数库的头文件

#ifndef _random_h#define _random_h

// 函数: RandomInit// 用法: RandomInit()// 作用:此函数初始化随机数种子void RandomInit();

// 函数: RandomInteger// 用法: n = RandomInteger(low, high)// 作用:此函数返回一个 low 到 high 之间的随机数,包括 low 和highint RandomInteger(int low, int high);

#endif

Page 36: 第 8 章  C++ 结构体,链表

库的实现 • 库的实现文件和头文件的名字是相同的。如

头文件为 Random.h ,则实现文件为Random.cpp 。

• 实现文件的格式:– 注释:这一部分简单介绍库的功能。– include 此 cpp 文件所需的头文件。– 每个实现要包含自己的头文件,以便编译器能检查函数定义和函数原型声明的一致性。

– 每个函数的实现代码。在每个函数实现的前面也必须有一段注释。

Page 37: 第 8 章  C++ 结构体,链表

// 文件: Random.cpp// 该文件实现了 Random 库

#include <cstdlib>#include <ctime>#include "Random.h"

// 函数: RandomInit// 该函数取当前系统时间作为随机数发生器的种子void RandomInit(){ srand(time(NULL));}

Page 38: 第 8 章  C++ 结构体,链表

// 函数: RandomInteger

// 该函数将 0 到 RAND_MAX 的区间的划分成 high - low + 1 个

// 子区间。当产生的随机数落在第一个子区间时,则映射成 low 。

// 当落在最后一个子区间时,映射成 high 。当落在第 i 个子区间

// ( i 从 0 到 high-low ),则映射到 low + i

int RandomInteger(int low, int high)

{

return (low + (high - low + 1) * rand() / (RAND_MAX + 1));

}

Page 39: 第 8 章  C++ 结构体,链表

第 9 章 模块化开发

• 自顶向下的分解• 模块划分• 库的设计与实现• 库的应用

Page 40: 第 8 章  C++ 结构体,链表

库的应用 -- 龟兔赛跑 动物 跑动类型 占用时间 跑动量乌龟 快走 50% 向前走 3 点

后滑 20% 向后退 6 点慢走 30% 向前走一点

兔子 睡觉 20% 不动大后滑 20% 向后退 9 点快走 10% 向前走 14 点小步跳 30% 向前走 3 点慢后滑 20% 向后退 2 点

Page 41: 第 8 章  C++ 结构体,链表

龟兔赛跑解题思路•分别用变量 tortoise 和 hare代表乌龟和兔子的当前位置

•时间用秒计算•用随机数来决定乌龟和兔子在每一秒的动作,根据动作决定乌龟和兔子的位置的移动

•跑道的长度设为 70个点

Page 42: 第 8 章  C++ 结构体,链表

第一层分解main()

{ int hare = 0, tortoise = 0, timer = 0; //timer 是计时器,从 0 开始计时

while (hare < RACE_END && tortoise < RACE_END)

{ tortoise += 乌龟根据他这一时刻的行为移动的距离; hare += 兔子根据他这一时刻的行为移动的距离 ;

输出当前计时和兔子乌龟的位置 ;

++timer;

}

if (hare > tortoise) cout << "\n hare wins!";

else cout << "\n tortoise wins!";

}

Page 43: 第 8 章  C++ 结构体,链表

抽取函数

• 乌龟在这一秒的移动距离: int move_tortoise();

• 兔子在这一秒的移动距离: int move_hare();

• 输出当前计时和兔子乌龟的位置 void print_position(int timer, int tortoise, int

hare);

Page 44: 第 8 章  C++ 结构体,链表

模块划分

• 主模块• 移动模块

– move_tortoise

– move_hare()

• 输出模块– print_position

Page 45: 第 8 章  C++ 结构体,链表

主模块#include "Random.h" // 包含随机数库#include <iostream>using namespace std;

const int RACE_END = 70; // 设置跑道的长度

int move_tortoise();int move_hare();void print_position(int, int, int);

Page 46: 第 8 章  C++ 结构体,链表

int main(){ int hare = 0, tortoise = 0, timer = 0;

RandomInit(); // 随机数初始化

cout << "timer tortoise hare\n"; // 输出表头 while (hare < RACE_END && tortoise < RACE_END)

{ tortoise += move_tortoise(); // 乌龟移动 hare += move_hare(); // 兔子移动

print_position(timer, tortoise, hare); ++timer;

} if (hare > tortoise) cout << "\n hare wins!\n";

else cout << "\n tortoise wins!\n"; return 0;

}

Page 47: 第 8 章  C++ 结构体,链表

如何用随机数模拟概率• 以乌龟为例,它的三种情况和概率如下:

为此我们可以生成 0-9 之间的随机数,当生成的随机数为 0-4 时,认为是第一种情况, 5-6 是第二种情况, 7-9 是第三种情况。这样就可以根据生成的随机数确定发生的事件

快走 50%

后滑 20%

慢走 30%

Page 48: 第 8 章  C++ 结构体,链表

Move 模块// 文件名: move.cpp

#include "Random.h" // 本模块用到了随机函数库

int move_tortoise()

{int probability = RandomInteger(0,9); // 产生 0 到 9 之间的随机数 if (probability < 5) return 3; // 快走 else if (probability < 7) return -6; // 后滑 else return 1; // 慢走}

Page 49: 第 8 章  C++ 结构体,链表

int move_hare()

{int probability = RandomInteger(0,9);

if (probability < 2) return 0; // 睡觉

else if (probability < 4) return -9; // 大后滑

else if (probability < 5) return 14; // 快走

else if (probability < 8) return 3; // 小步跳

else return -2; // 慢后滑

}

Page 50: 第 8 章  C++ 结构体,链表

Print 模块// 文件名: print.cpp

#include <iostream>

using namespace std;

void print_position(int timer, int t, int h)

{

if (timer % 6 == 0) cout << endl; // 每隔 6 秒空一行 cout << timer << '\t' << t << '\t' << h << '\n';

}

Page 51: 第 8 章  C++ 结构体,链表

用 code_block 多文件的例子• 要注意看

51

Page 52: 第 8 章  C++ 结构体,链表

头文件的设计• 为方便起见,我们把所有的符号常量定义、类型定义

和函数原型声明写在一个头文件中,让每个模块都include 这个头文件。

• 那么,每个模块就不必要再写那些函数的原型声明了• 但这样做又会引起另一个问题,当把这些模块连接起

来时,编译器会发现这些类型定义、符号常量和函数原型的声明在程序中反复出现多次,

• 解决方法:需要用到一个新的编译预处理命令:#ifndef 标识符…

#endif

Page 53: 第 8 章  C++ 结构体,链表

头文件的格式

#ifndef _name_h

#define _name_h

头文件真正需要写的内

#endif

Page 54: 第 8 章  C++ 结构体,链表

石头、剪子、布游戏的头文件 // 文件: p_r_s.h// 本文件定义了两个枚举类型,声明了本程序包括的所有函数原型

#ifndef P_R_S#define P_R_S #include <iostream> #include <cstdlib> #include <ctime> using namespace std;

enum p_r_s {paper, rock, scissor, game, help, quit} ; enum outcome {win, lose, tie, error} ; outcome compare(p_r_s player_choice, p_r_s machine_choice); void prn_final_status(); void prn_game_status(); void prn_help(); void report(outcome result); p_r_s selection_by_machine(); p_r_s selection_by_player();#endif

Page 55: 第 8 章  C++ 结构体,链表

计算 2 个数的和, 2 个数差

55

Page 56: 第 8 章  C++ 结构体,链表

Main.cpp 函数• #include <iostream>

• #include "yu.h"

• using namespace std;

• int main()

• {

• cout<<jia(1,2)<<endl;

• cout<<jian(4,2)<<endl;

• cout << "Hello world!" << endl;

• return 0;

• }

56

Page 57: 第 8 章  C++ 结构体,链表

Yu11.cpp

• #include "yu.h"

• int jia(int a,int b)

• {

• return a+b;

• }

57

Page 58: 第 8 章  C++ 结构体,链表

Yu12.cpp

• #include "yu.h"

• int jian(int a,int b)

• {

• return a-b;

• }

58

Page 59: 第 8 章  C++ 结构体,链表

Yu.h

• #ifndef YU_H_INCLUDED //系统生成• #define YU_H_INCLUDED

• int jia(int a,int b);// 这里写具体的函数名• int jian(int,int); // 这里写具体的函数名

• #endif // YU_H_INCLUDED59

Page 60: 第 8 章  C++ 结构体,链表

• File—new --file:

• 选择头文件 源文件• 尤其注意下面操作:必须选上 debug

release

• 否则找不到函数

60

Page 61: 第 8 章  C++ 结构体,链表

要注意的问题

61

Page 62: 第 8 章  C++ 结构体,链表

62

Welcome to HDOJ

Thank You ~

Page 63: 第 8 章  C++ 结构体,链表

• 课后一定要练习之!

63