第 8 章 数组 计算机科学学院 李淮 Tel 13198572163 QQ 303167586.

Slides:



Advertisements
Similar presentations
C语言基础——指针的高级应用 Week 05.
Advertisements

第九章 指针 目录 指针与指针变量的概念 变量的指针和指向变量的指针变量 数组的指针和指向数组的指针变量
C语言程序设计 第十二章 位运算.
第六章 数 组 主讲教师 贾月乐 联系电话:
C语言程序设计 课程 第5章 数组 主讲:李祥 博士、副教授 单位:软件学院软件工程系.
第5章 函数与预处理 《 C语言程序设计》 (Visual C++ 6.0环境) 本章导读
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
循环结构又称为重复结构:用来处理需要重复处理的问题,它是程序中一种很重要的结构。
選擇排序法 通訊一甲 B 楊穎穆.
第3章 顺序结构程序设计 本章要点: 格式化输出函数──printf() 格式输入函数——scanf() 字符输出函数——putchar()
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
排序 Sorting.
项目六 用指针优化学生成绩排名 项目要求 项目分析
Chap 9 结构 9.1 构建手机通讯录 9.2 结构变量 9.3 结构数组 9.4 结构指针.
搜尋資料結構 Search Structures.
Introduction to the C Programming Language
Introduction to the C Programming Language
目录 第八章 数组 1 简单学生成绩管理系统的开发 2 一维数组 3 多维数组 4 字符数组 5 数组作函数参数.
第七章 函数 目录 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
C语言程序设计 李祥.
QQ: 李祥 QQ: 欢迎多种方式的学习交流,祝大家学有所成.
第7章 编译预处理 本章要求: 本章重点: 本章难点: 掌握用#define定义无参数宏和带有参数宏定义和调用方法;
算法的基本概念.
第八章 使用指针.
計數式重複敘述 for 迴圈 P
第十章 指针.
2.1 C语言的数据类型 2.2 常量与变量 2.3 变量赋初值 2.4 各类数值型数据间的混合运算 2.5 C语言的运算符和表达式
第5讲 结构化程序设计(Part II) 周水庚 2018年10月11日.
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
電子音樂 通訊系 B 楊穎穆.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
第0章作业: 教材P12-练习与实践 1.写出用符号’*’输出描绘汉字”大”的流程图。
数组 梁春燕 华电信息管理教研室.
C++大学基础教程 第5章 数组 北京科技大学 信息基础科学系.
目录 9.1 结构体类型 9.2 共用体类型 9.3 枚举类型 9.4 类型声明符typedef 1.
C语言概述 第一章.
第1讲 C语言基础 要求: (1) C程序的组成 (2) C语言的标识符是如何定义的。 (3) C语言有哪些基本数据类型?各种基本数
資料結構與C++程式設計進階 排序與搜尋 講師:林業峻 CSIE, NTU 6/ 14, 2010.
C语言复习3----指针.
第 二 章 数据类型、运算符与表达式.
C语言大学实用教程 第6章 数组 西南财经大学经济信息工程学院 刘家芬
函数 概述 模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块, 特点: 开发方法: 自上向下,逐步分解,分而治之
C语言程序设计 教案 崔武子制作
第八章 指標 (Pointer).
C语言的特点 1. C程序由许多函数组成 2. C程序必须有且只有一个主函数main( ) 3. 函数用“{”和“}”表示起点和终点
第1章 绪论(二) 教学目标 理解算法的特性及评价标准 掌握算法时间复杂度和空间复杂度的分析方法 1/
第十四章 若干深入问题和C独有的特性 作业: 函数指针 函数作参数 函数副作用 运算 语句 位段 存储类别 编译预处理
C语言程序设计 李祥 QQ:
第2章 认识C语言 教学要点 2. 1 项目二C语言程序识读 2 .2 项目三班级成绩排名 2 .3 知识链接 返回.
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第3章 数据类型、运算符与表达式.
第2章 数据类型、运算符与表达式 本章要点: 基本数据类型 常量和变量 算术运算符和算术表达式 关系运算符和关系表达式
第二章 语言设计问题.
第二章 类型、对象、运算符和表达式.
实验七 数 组 第21讲 C程序设计 Main() { int x,y; X=10; y=x*x+1;
Introduction to the C Programming Language
第3章 最简单的C程序设计 3.1 顺序程序设计举例 3.2 数据的表现形式及其运算 3.3 C语句 3.4 数据的输入输出.
本节内容 指针类型.
第七章  数 组.
目录 12.1 位运算符 12.2 位域(位段) 1.
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
C/C++基礎程式設計班 陣列 講師:林業峻 CSIE, NTU 3/14, 2015.
C++程序语言设计 Chapter 14: Templates.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C语言基础学习 从外行到入门.
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

第 8 章 数组 计算机科学学院 李淮 Tel QQ

/49 本章学习内容本章学习内容  对数组名特殊含义的理解  数组类型,数组的定义和初始化  向函数传递一维数组和二维数组  排序、查找、求最大最小值等常用算法

/49 为什么使用数组 (Array)? 【例 8.1 】读入并保存 10 人的成绩,再计算平均成绩 需定义 10 个不同名整型变量,需要使用多个 scanf() 需定义 10 个不同名整型变量,需要使用多个 scanf() int score1,score2,…score10; int score1,score2,…score10; scanf("%d",&score1); scanf("%d",&score1); scanf("%d",&score2); scanf("%d",&score2); 用数组 用数组 int score[10],i; int score[10],i; for (i=0; i<10; i++) for (i=0; i<10; i++) { scanf("%d",&score[i]); scanf("%d",&score[i]); } 保存大量同 类型的相关 数据

/49 数组概念 1 、数组:一组具有相同数据类型的数据的有序的集合。 2 、数组元素:构成数组的数据。数组中的每一个数组元 素具有相同的名称,不同的下标,可以作为单个变量使 用,所以也称为下标变量。 3 、数组的下标:是数组元素的位置的一个索引或指示。 4 、数组的维数:数组元素下标的个数。根据数组的维数 可以将数组分为一维、二维、三维、多维数组。

/ 一维数组的定义和初始化 一维数组的定义 一维数组的定义 存储类型 数据类型 数组名 [ 整数 1] [ 整数 2] …… [ 整数 n]; 存储类型 数据类型 数组名 [ 整数 1] [ 整数 2] …… [ 整数 n]; a[9] a[8]a[7] a[1] a[0] … 数组首地址 int a[10]; 定义一个有 10 个 int 型元素的数组 定义一个有 10 个 int 型元素的数组 – 系统分配 10 个连续的存储空间给数组 数组名 a 就是此数组的首地址 数组名 a 就是此数组的首地址 基类型 下标从 0 开始

/ 一维数组的定义和初始化 a[9] a[8]a[7] a[1] a[0] … int a[10]; 数组大小必须是值为正的常量,不能为变量 数组大小必须是值为正的常量,不能为变量 – int n=10; – int a[n]; 数组大小可以用宏来定义 数组大小可以用宏来定义 #define SIZE 10 int a[SIZE]; int a[SIZE]; 一维数组的定义 一维数组的定义 存储类型 数据类型 数组名 [ 整数 1] [ 整数 2] …… [ 整数 n]; 存储类型 数据类型 数组名 [ 整数 1] [ 整数 2] …… [ 整数 n]; ×

/ 一维数组的定义和初始化 数组定义后的初值仍然是随机数 数组定义后的初值仍然是随机数 一般需要我们来初始化 一般需要我们来初始化 int a[5] = { 12, 34, 56,78,9 }; int a[5] = { 12, 34, 56,78,9 }; 部分元素初始化,其余元素为零 部分元素初始化,其余元素为零 int a[5] = { 0 }; int a[5] = { 0 }; 如果全部元素均指定初值,定义中可以省略 元素的个数 如果全部元素均指定初值,定义中可以省略 元素的个数 int a[] = { 11, 22, 33, 44, 55 }; int a[] = { 11, 22, 33, 44, 55 };

/ 一维数组的定义和初始化 数组的引用 数组的引用 数组名 [ 下标 ] 数组名 [ 下标 ] 数组下标 (index) 都是从 0 开始 数组下标 (index) 都是从 0 开始 使用 a[0] 、 a[1] 、 a[2] 、 …… 、 a[9] 访问元素 使用 a[0] 、 a[1] 、 a[2] 、 …… 、 a[9] 访问元素 下标既可是常量,也可是整型表达式,如 a[i] 下标既可是常量,也可是整型表达式,如 a[i] – 可以像使用普通变量一样使用它们

/49 如何使两个数组的值相等? main() { int a[4] = {1,2,3,4}, b[4]; b = a; } 解决方法 方法 1: 逐个元素赋值 b[0]=a[0]; b[1]=a[1]; b[2]=a[2]; b[3]=a[3]; 方法 2: 通过循环赋值 int i; for (i=0;i<4;i++) { b[i] = a[i]; } 原因 : 数组名表示数组的首地址, 其值不可改变 !

/ 一维数组的定义和初始化 【例 8.2 】编程实现显示用户输入的月份(不包括 闰年的月份)拥有的天数 【例 8.2 】编程实现显示用户输入的月份(不包括 闰年的月份)拥有的天数

/ 一维数组的定义和初始化 下标越界是大忌! 下标越界是大忌! – 编译程序不检查是否越界 – 下标越界,将访问数组以外的空间 – 越界的数据是未知的

/49 b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9] c a 【例 8.3 】 当下标值小于 0 或超过数组长度时 会出现什么情况? 运行程序或单步执行观察变量变化情况可以看到, 变量 c 和 a 的值因数组越界而被悄悄破坏了 c c c

/49 [ 例 ] 使数组元素 a[0] ~ a[9] 的值为 1 ~ 10 ,然后逆序 输出。 main(){ int i,a[10]; int i,a[10]; for (i=0;i<=9;i++) for (i=0;i<=9;i++) a[i] = i+1; a[i] = i+1; for(i=9;i>=0; i--) for(i=9;i>=0; i--) printf("%d ",a[i]); printf("%d ",a[i]);} 运行输出: 运行输出:

/ 向函数传递一维数组 传递整个数组给另一个函数,可 将数组的首地址作为参数传过去 传递整个数组给另一个函数,可 将数组的首地址作为参数传过去 – 用数组名作函数参数 – 由于首地址相同,故实参数组与形 参数组占用同一段内存 – 在该函数内,形参不仅可以读这个 数组的元素,还可以修改它们

/49 简单变量和数组作函数参数的区别 简单变量和数组作函数参数的区别

/49 【例 8.5 】输入人数,计算平均分 计数控制的循环 计数控制的循环

/49 【例 8.5 】输入人数,计算平均分 计数控制的循环 计数控制的循环

/49 【例 8.6 】输入分数,统计人数,计算平 均分,当输入负值时,表示输入结束 标记控制的循环 —— 负值作为输入结束标记 标记控制的循环 —— 负值作为输入结束标记

/49 【例 8.6 】输入分数 ( 人数? ) ,计算平均 分,当输入负值时,表示输入结束 标记控制的循环 —— 负值作为输入结束标记 标记控制的循环 —— 负值作为输入结束标记

/49 【例 8.7 】计算最高分 #include #define N 40 int ReadScore(int score[]); int FindMax(int score[], int n); int main() { int score[N], max, n; n = ReadScore(score); printf("Total students are %d\n", n); max = FindMax(score, n); printf("The highest score is %d\n", max); return 0; }

最值算法 算法描述 算法描述 求最大值时,假设第一个数为最大值 求最大值时,假设第一个数为最大值 将每个数逐个与最大值相比较,若比最大值大 则将该数作为新的最大值,直到数组元素比较 完。 将每个数逐个与最大值相比较,若比最大值大 则将该数作为新的最大值,直到数组元素比较 完。

/49 max(i=0) max(i=2)max(i=3) 计算最大值算法计算最大值算法

/49 假设其中的一个学生成绩为最高 假设其中的一个学生成绩为最高 maxScore = score[0]; 对所有学生成绩进行比较,即 对所有学生成绩进行比较,即 for (i=1; i<n; i++) for (i=1; i<n; i++) { 若 score[i] > maxScore 若 score[i] > maxScore 则修改 maxScore 值为 score[i] } 打印最高分 maxScore 打印最高分 maxScore 【例 8.7 】计算最高分

/49 【例 8.7 】计算最高分

/ 排序和查找 排序( Sorting )算法 排序( Sorting )算法 – 交换法排序 – 选择法排序

比较交换法 基本过程(以降序为例): 将第一个元素顺序与其后面的元素比较,比第一 个大则进行交换,第一轮完毕后,最大的元素被 挪到了第一个位置 将第一个元素顺序与其后面的元素比较,比第一 个大则进行交换,第一轮完毕后,最大的元素被 挪到了第一个位置 第二轮从第二个元素开始重复上面的过程,结束 后得到第二个最大的元素, 第二轮从第二个元素开始重复上面的过程,结束 后得到第二个最大的元素, 如此下去,经过 N-1 轮的比较,可将 N 个数排好 如此下去,经过 N-1 轮的比较,可将 N 个数排好

第一轮结束,数据 5 已排好 比较交换法 举例 原始数据: 1 , 2 , 3 , 5 , 4 要求:降序

第 二 轮 比 较 :第 二 轮 比 较 : 第二轮结束,找到第二最大值 4 比较交换法

第三轮结果: 第四轮结果: 公式表示: (N 为排序的个数, OP 为操作,降序为 “>”) for( i=0 ; i<n-1 ; i++) 外层循环 N-1 次 for( j=i+1 ; j <n ; j++) 内层依赖外层 if ( S(j) OP S(i) ) { t=S(i):S(i)=S(j):S(j)=t‘ 交换 } 方法:双重循环(循环嵌套) 外循环:控制排序趟数 内循环:排序过程中的数组元素下标取值

/49 【例 8.8 】交换法从高到低排序 交换法排序 for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) for (j=i+1; j<n; j++) { if (score[j] > score[i]) if (score[j] > score[i]) " 交换成绩 score[j] 和 score[i]" " 交换成绩 score[j] 和 score[i]" }}

/49 如何实现两数交换?如何实现两数交换? temp = score[j]; score[j] = score[i]; score[i] = temp; temp score[j] score[i] ??

/49 【例 8.8 】交换法从高到低排序 void DataSort(int score[], int n) /* 交换法排序 */ { int i, j, temp; for (i=0; i<n-1; i++) { for (j=i+1; j<n; j++) { if (score[j] > score[i]) /* 从高到低 */ { temp = score[j]; score[j] = score[i]; score[i] = temp; }

选择法排序思想方法:按递增排序 对 n 个数排序,先将第一个数与第二个数到第 n 个数逐 一比较,找出最小数的位置 i( 下标 ) ,然后将 a(1) 与 a(i) 进 行 交换,将最小数存放在 a(1) 中 对 n 个数排序,先将第一个数与第二个数到第 n 个数逐 一比较,找出最小数的位置 i( 下标 ) ,然后将 a(1) 与 a(i) 进 行 交换,将最小数存放在 a(1) 中 然后将第二个数依次与第三个到第 n 个数逐一进行比 较,找出第二个到第 n 个数中最小数,然后将 a(2) 与 a(i) 进行交换 然后将第二个数依次与第三个到第 n 个数逐一进行比 较,找出第二个到第 n 个数中最小数,然后将 a(2) 与 a(i) 进行交换 重复上面的步骤,直到排序结束为止 ( 进行 n-1 趟排序 ) 重复上面的步骤,直到排序结束为止 ( 进行 n-1 趟排序 ) 选择法排序

第一趟排序 原始数据 a(1) a(2) a(3) a(4) a(5) a(6) 第一趟排序 第二趟排序 第二趟排序 第三趟排序 第三趟排序 第四趟排序 第四趟排序 第五趟排序 、求数组的最小元素 2 、交换数组中的两个元素 方法:双重循环(循环嵌套) 外循环为 i :控制排序趟数 内循环为 j :排序过程中的下标变量 选择法排序

/49 选择法排序选择法排序 选择法排序 for (i=0; i<n-1; i++) { k = i; k = i; for (j=i+1; j<n; j++) for (j=i+1; j<n; j++) { if (score[j] > score[k]) if (score[j] > score[k]) 记录此轮比较中最高分的元素下标 k = j; 记录此轮比较中最高分的元素下标 k = j; } } 若 k 中记录的最大数不在位置 i ,则 若 k 中记录的最大数不在位置 i ,则 " 交换成绩 score[k] 和 score[i]" , " 交换成绩 score[k] 和 score[i]" , " 交换学号 num[k] 和 num[i]" ; " 交换学号 num[k] 和 num[i]" ;}

/49 void DataSort(int score[], long num[], int n) /* 选择法 */ { int i, j, k, temp1; long temp2; for (i=0; i<n-1; i++) { k = i; for (j=i+1; j<n; j++) { if (score[j] > score[k]) { k = j; /* 记录最大数下标位置 */ } if (k != i) /* 若最大数不在下标位置 i*/ { temp1 = score[k]; score[k] = score[i]; score[i] = temp1; temp2 = num[k]; num[k] = num[i]; num[i] = temp2; }

/49 【例 8.8 】成绩从高到低顺序

/ 排序和查找 查找( Searching )算法 查找( Searching )算法 – 顺序查找 – 折半查找

/49 【例 8.10 】顺序查找学号 int LinSearch(long num[], long x, int n) { int i; int i; for (i=0; i<n; i++) for (i=0; i<n; i++) { if (num[i] == x) if (num[i] == x) { return (i); return (i); } } return (-1); return (-1);} 哈,找到了! 事先不必排序

/49 【例 8.11 】折半查找学号 哈,找到了! 按升序排序

/49 【例 8.11 】折半查找学号 唉,没找到!

/49 int BinSearch(long num[], long x, int n) { int low, high, mid; low = 0; high = n - 1; while (low <= high) { mid = (high + low) / 2; mid = (high + low) / 2; if (x > num[mid]) { low = mid ; } else if (x < num[mid]) { high = mid ; }else{ return (mid); }} return(-1); } 找到时返回 下标位置 找不到时 返回 -1 若未按学号排序, 则如何修改程序?

/ 二维数组的定义和初始化 一维数组 一维数组 – 用一个下标确定各元素在数组中的顺序 – 可用排列成一行的元素组来表示 如 int a[5]; 如 int a[5]; 二维数组 二维数组 – 用两个下标确定各元素在数组中的顺序 – 可用排列成 i 行, j 列的元素组来表示 如 int b[2][3]; 如 int b[2][3]; n 维数组 n 维数组 – 用 n 个下标来确定各元素在数组中的顺序 如 int c[3][2][4]; 如 int c[3][2][4]; – n≥3 时,维数组无法在平面上表示其各元素的位置 a[0]a[1]a[2]a[3]a[4] b[0][0]b[0][1]b[0][2]b[1][0]b[1][1]b[1][2]

/49 【例】以下程序的运行结果是什么? int main() { int a[][3]={{1,2,3},{4,5},{6},{0}}; int a[][3]={{1,2,3},{4,5},{6},{0}}; printf("%d,%d,%d\n",a[1][1],a[2][1],a[3][1]); printf("%d,%d,%d\n",a[1][1],a[2][1],a[3][1]); return 0; return 0;} 结果: 5, 0, 0 【例】若 int a[ ][3]={1, 2, 3, 4, 5, 6, 7} , 则 a 数组的第一维大小是多少? 二维数组的初始化

/49 数组的数据类型和存储类型 根据数组的数据类型,为每一元素安排相同长度的存储单元 根据数组的数据类型,为每一元素安排相同长度的存储单元 根据数组的存储类型,将其安排在内存的动态存储区、静态 存储区或寄存器区 根据数组的存储类型,将其安排在内存的动态存储区、静态 存储区或寄存器区 用 sizeof(a) 来获得数组 a 所占字节数 用 sizeof(a) 来获得数组 a 所占字节数 short

/49 short int a[2][3]; a[0] a[1] a[1][0] a[1][1] a[1][2] a[0][0] a[0][1] a[0][2] 存放顺序:按行存放 先顺序存放第 0 行元素,再存放第 1 行元 素 a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 需知道数组每行列数才能从起始地址开始正确读出数组元素 二维数组的存储结构二维数组的存储结构

/49 二维数组实例二维数组实例 【例 8.4 】从键盘输入 4 个学生的 3 门成绩,并显示。 【例 8.4 】从键盘输入 4 个学生的 3 门成绩,并显示。 #include<stdio.h> void main() { int score[4][3],i,j; int score[4][3],i,j; for(i=0;i<4;i++) { for(i=0;i<4;i++) { for(j=0;j<3;j++) { printf("input score[%d][%d]:",i,j); printf("input score[%d][%d]:",i,j); scanf("%d",&score[i][j]); scanf("%d",&score[i][j]);}}}for(i=0;i<4;i++){ for(j=0;j<3;j++) for(j=0;j<3;j++) { printf("%d\t",score[i][j]); printf("%d\t",score[i][j]); }putchar('\n'); }

/ 向函数传递二维数组 a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 实际传送的是数组第一个元素的地址 short a[2][3];

/ 向函数传递二维数组 在声明二维数组形参时,不能省略数组第二 维的长度(列数),为什么? 在声明二维数组形参时,不能省略数组第二 维的长度(列数),为什么? 想想数组在内存中是如何分布的? 想想数组在内存中是如何分布的? 元素 a[i][j] 在数组 a 中的位置是: 元素 a[i][j] 在数组 a 中的位置是: i * N + j i * N + j 元素地址: 首地址 + 偏移量 元素地址: 首地址 + 偏移量 a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] 实际传送的是数组第一个元素的地址 short a[M][N]; 偏移 1*3+2

/49 例 8.12 计算每门课程的总分和平均分 void AverforCourse(int score[][COURSE_N], int sum[], float aver[], int n) float aver[], int n){ int i, j; for (j=0; j<COURSE_N; j++) { sum[j] = 0; sum[j] = 0; for (i=0; i<n; i++) for (i=0; i<n; i++) { sum[j] = sum[j] + score[i][j]; sum[j] = sum[j] + score[i][j]; } aver[j] = (float) sum[j] / n; }} 可省略数组第一维的长度 不能省略第二维的长度

/49 例 8.12 计算每个学生的总分和平均分 void AverforStud(int score[][COURSE_N], int sum[], float aver[], int n) float aver[], int n){ int i, j; for (i=0; i<n; i++) { sum[i] = 0; sum[i] = 0; for (j=0; j<COURSE_N; j++) for (j=0; j<COURSE_N; j++) { sum[i] = sum[i] + score[i][j]; sum[i] = sum[i] + score[i][j]; } aver[i] = (float) sum[i] / COURSE_N; }}

/49 例 8.12 计算每门的总分和平均分

/49 作业 习题