850 likes | 1.01k Views
2008 年江苏省信息学奥林匹克冬令营 数组. 文件. 概述 文件的分类 对文件的操作. 数组. 概述. 定义:在 Pascal 中,同一类型的元素组成的顺序集合称为文件。. 如果文件中的信息是某个应用程序要处理的数据,则称其为该应用程序的数据文件。. 利用文件的优点:. (1) 文件可以永久保存,其中的数据不会因应用程序的结束而消失; (2) 文件中的数据可以为多个应用程序所共享; (3) 文件中的数据可以多次重复使用; (4) 文件中存放的数据的数量在理论上没有限制。. 文件的分类.
E N D
文件 • 概述 • 文件的分类 • 对文件的操作 • 数组
概述 • 定义:在Pascal中,同一类型的元素组成的顺序集合称为文件。 如果文件中的信息是某个应用程序要处理的数据,则称其为该应用程序的数据文件。
利用文件的优点: (1)文件可以永久保存,其中的数据不会因应用程序的结束而消失; (2)文件中的数据可以为多个应用程序所共享; (3)文件中的数据可以多次重复使用; (4)文件中存放的数据的数量在理论上没有限制。
文件的分类 顺序文件:对文件的读写操作只能按文件中元素的顺序,从前到后依次进行,而不能跳过前面的元素直接对文件中的某个元素进行读写。 • 按照对文件的读写方式 所以只能从文件的第一个元素开始一个一个地顺序读每个元素,也只能从第一个元素开始一个一个地向文件中顺序地写数据。由于顺序文件具有这种特征,所以对顺序文件的读写不能交叉进行。 随机文件: 可以直接对文件中的某个元素进行读写操作,可以交叉进行,所以也称直接文件。
文本文件:以ASCII代码形式(字符形式)存放的,称为TEXT类型文件 。 • 按文件的存储方式 类型文件:以二进制代码形式存放的文件 文本文件是顺序文件,类型文件是随机文件。
对文件的操作: • 读操作或取操作: 读取操作不会改变文件的原有内容;在读取文件中的数据时,必须先把文件中的数据元素从文件中通过一定的方式复制到计算机的内存中暂存起来,然后再处理。
写操作将会改变文件原有内容。写入数据的过程与从文件中读数据的过程相反,应用程序先把数据写入文件缓冲区,再把文件缓冲区中的内容存入外存中的实际文件中去。 • 写操作或存操作:
第一步:内存中建立一个文件缓冲区,并为指定文件分配一个通道,使得这个实际的文件与文件缓冲区建立联系。这一过程通常被称为打开一个文件;第一步:内存中建立一个文件缓冲区,并为指定文件分配一个通道,使得这个实际的文件与文件缓冲区建立联系。这一过程通常被称为打开一个文件; • 操作步骤1: assign(input,'cab.in'); assign(output,'cab.out');
第二步:对文件进行读写操作(实际是对文件缓冲区中的数据元素进行读写操作)第二步:对文件进行读写操作(实际是对文件缓冲区中的数据元素进行读写操作) • 操作步骤2: reset(input); for i:=1 to 4 do read(s[i]); readln; 读文件 rewrite(output); writeln(step); 写文件
第三步:文件操作结束后应释放占用的通道,切断实际文件与文件缓冲区之间的联系,并释放文件缓冲区。这一过程通常被称为关闭一个文件。第三步:文件操作结束后应释放占用的通道,切断实际文件与文件缓冲区之间的联系,并释放文件缓冲区。这一过程通常被称为关闭一个文件。 • 操作步骤3: close(input); close(output);
1)输出格式(是否有多余空格或空行); for i:=1 to m-1 do write(b[i],' '); writeln(b[m]); • 注意: for i:=1 to n do begin for j:=1 to n-1 do write(a[i,j],' '); writeln(a[i,n]); end;
2)结束程序前一定要关闭文件,特别是在程序中使用了halt语句。2)结束程序前一定要关闭文件,特别是在程序中使用了halt语句。 • 注意: close(output); Halt;
文件举例: var a:integer; begin assign(input,'tt.in'); assign(output,'tt.out'); reset(input); readln(a); rewrite(output); writeln(a*a); close(input); close(output); end.
数组 • 复习相关类型 • 一维数组的定义 • 一维数组的基本操作 • 二维数组及其操作 • 应用举例 • 字符串
子界类型定义 定义的一般格式为:type<子界类型标识符>=<常量1>..<常量2> type agetype=1..150; chtype='a'..'z';
子界类型简单应用 type agetype=1..150; chtype='a'..'z'; var a1,a2:agetype; ch:chtype; {定义了a1、a2为子界类型agetype的两个变量,ch为子界类型chtype的变量。} 也可将类型定义与变量定义合并起来在变量说明中进行定义: var a1,a2:1..150; ch:'a'..'z';
判断下列类型定义哪些是正确的,哪些是错误的。判断下列类型定义哪些是正确的,哪些是错误的。 (1)type atype=10..10*10; (2)type atype=1.2..2.0; (3)type atype=a..z; (4)type atype='1'..'5'; (5)type atype='k'..'e';
引例: 同一类型的变量,用同一个名字代表,比如:A[1],A[2],A[3],..,A[50],由此组成了A的数组,括号里的数字称为A数组的下标,每个下标变量称为数组元素 输入50名学生某门课程的成绩,要求把高于平均分的那些成绩打印出来. 数组A A[1] A[2] A[3] A[50]
一维数组的定义 TYPE 数组类型名=ARRAY[下标类型] OF 数组元素类型 例如: TYPE scoretype = array[1..50] of integer; VAR score:scoretype; 当数组中每个元素只带有一个下标时,我们称这样的数组为一维数组 直接在VAR区中定义数组,形式如下: VAR 数组名: ARRAY [下标类型] OF 数组元素类型; 例如: VAR score: array [1..50] of integer;
数值数组 数组元素的类型是数值类型的一维数组。 • 字符数组 数组元素的类型是字符类型的一维数组。
数组的基本操作 数组的输入、输出 数组元素的查找 数组元素的移动 数组元素的插入 数组元素的删除 排序
数组元素的输入、输出 例:按照顺序读入十个数,然后以逆序方式输出。 For i:=1 to 10 do read(A[i]);readln;{输入} For i:=10 downto 1 do write(A[i]:4);readln;{输出} Program ex2_1; const n=10; var a:array[1..n] of integer; i,m:integer; begin for i:=1 to n do read(a[i]); readln; {读入} for i:=n downto 1 do write(a[i],’‘);writeln; end.
思考:将上题A数组中的各元素的值按逆序重新放置再输出,如何操作?思考:将上题A数组中的各元素的值按逆序重新放置再输出,如何操作? 可以先开一个B数组,将A数组各元素的值按逆序赋值B数组元素,再将B数组各元素的值按顺序回到A数组相应元素中。
程序如下: Program ex2_1; const n=10; var a:array[1..n] of integer; i,m:integer; begin for i:=1 to n do read(a[i]); readln; {读入} for i:=1 to n do b[i]:=a[ ]; for i:=1 to n do a[i]:=b[i]; for i:=1 to 1 do write(a[i],’‘);writeln; end. n-i+1
若不允许重新开数组 var a:array[1..n] of integer; i,m,t:integer; begin for i:=1 to n do read(a[i]); readln; for i:=1 to (n div 2) do begin t:=a[i]; a[i]:=a[n-i+1] a[n-i+1]:=t; end; for i:=1 to 1 do write(a[i],’‘);writeln; end.
例:字符统计 例:输入一串小写字母(以“.”为结束标志),统计出每个字母在该字符串中出现的次数(若某字母不出现,则不要输出)。 例: 输入:aaaabbbccc. 输出: a:4 b:3 c:3
程序: • var a:array['a'..'z']of integer; • i,ch:char; • begin • for i:='a' to 'z' do a[i]:=0; • repeat • read(ch); • a[ch]:=a[ch]+1; • until ch='.'; • for i:='a' to 'z' do • if a[i]<>0 • then writeln(i,':',a[i]); • end.
数组元素的查找 p:=1;t:=N,f:=false; repeat i:=(p+t) div 2; if x=a[i] then f:=true else if x<a[i] then t:=i-1; else p:=i+1; until (t<p) or (f=true); If not f then writeln(‘no’) else writeln(‘yes’) 1、顺序查找法 从头开始,根据给定的值,依次与数组中元素进行比较,相同即为找到,若查遍整个数组仍然没有,则表示该元素不存在。 For i:=1 to n do if x=a[i] then writeln(‘yes!’) else writeln(‘no’) 2、折半查找法 利用三个变量分别指向头、尾和中间元素,每次都与中间元素比较,若相同,则找到,否则,调整头或尾指针,重新折半。
数组元素的移动 1 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 程序段:(移动一个) t:=a[1]; for i:=1 to n-1 do A[i]:=a[i+1]; a[n]:=t; 第一步: 取出A[1]中的数 1 第二步: 后面所有元素向前移动 1 第三步: 将A[1]的值放到A[10]处
数组元素的插入 porgram ex2_2(input,output); const n=10; var a:array[1..n+1] of integer; i,m,x,p:integer; begin for i:=1 to n do read(a[i]);readln; write('x=');readln(x); write('p=');readln(p); for I:=n downto p do a[i+1]:=a[i]; a[p]:=x; for i:=1 to n+1 do write(a[i]:4);writeln; end.
数组元素的删除 porgram ex2_3(input,output); const n=10; var a:array[1..n+1] of integer; i,m,x,p:integer; begin for i:=1 to n do read(a[i]);readln; write('p=');readln(p); for I:=p to n-1 do a[i]:=a[i+1]; a[p]:=x; for i:=1 to n-1 do write(a[i]:4);writeln; end.
注意: • 下标变量名的命名规定与简单变量的规定相同 • 下标必须写在方括号内,可以由常量、简单变量、表达式或下标变量等构成。如A[5],B[x],C[x-y-2],D[A[5]]等。 • 下标变量定义后就有一个确定的有限值 • 下标表达式值的类型, 必须与数组类型定义中下标类型完全一致,并且不允许超越所定义的下标下界和上界。 • a:array['a'..'z']of integer; • 下标变量的类型是相同的,存储位置是连续的,可通过下标随机存取其元素,运算与其类型相适应 • 必须遵循“先定义,后使用”的原则,分清类型和变量 • 特殊地,如果两个数组类型一致,它们之间可以整个数组元素进行传送。 如: var a,b,c:array[1..100] of integer; begin c:=a;a:=b;b:=c; end.
排序 冒泡排序法图示: 待排序数据:53 33 19 53 3 63 82 20 19 39 第一趟排序:3 53 33 19 53 19 63 82 20 39 第二趟排序:3 19 53 33 19 53 20 63 82 39 第三趟排序:3 1919 53 33 20 53 39 63 82 第四趟排序:3 1919 20 53 33 39 53 63 82
二维数组及其存储方式 二维数组元素有两个下标,第一个下标表示该元素在第几行,第二个下标表示在第几列 。
二维数组元素的输入、输出 例:输入5名学生5门功课的考试成绩,输出各人的各科成绩及总分。 分析:通过二重循环实现对二维数组各元素的赋值和输出。 begin write('input score:'); for i:=1 to n do begin writeln('No. ',i); for j:=1 to 5 do read(a[i,j]); readln; end; program ex_2_3(input,output); const n=50; var a:array[1..50,1..6] of real; i,j:integer;
for i:=1 to n do begin a[i,6]:=0; for j:=1 to 5 do a[i,6]:=a[i,6]+a[i,j]; end; writeln('No.':4,'yw':4,'sx':4,'wl':4,'hx':4,'yy':4,'zf':4); for i:=1 to n do begin write(i:4); for j:=1 to 5 do write(a[i,j]:4); writeln; end;
应用举例 • 验证卡布列克运算 • 猴子选大王 • 编码与解码问题 • 鞍点 • 回形方阵 • 螺旋方阵
[例1] 验证卡布列克运算。任意的一个四位数,只要它们各个位上数字不全相同,就有这样的规律,其中三个步骤设计三个函数实现: a) 将组成这个四位数的四个数字由大到小排列,形成由这四个数字构成的最大四位数。 b) 将组成这个四位数的四个数字由小到大排列,形成由这四个数字构成的最小四位数。(如果四个数字中有0,则得到的数不足四位) c) 求两个数的差,得到一个新的四位数。 重复以上过程,最后得到的结果总是6174。 • 验证卡布列克运算
var c,t:array[1..4] of integer; i,j,temp,step:integer; s:array[1..4] of char; begin assign(input,'cab.in'); reset(input); for i:=1 to 4 do read(s[i]); readln; close(input); for i:=4 downto 1 do c[i]:= ; step:=0; • 程序代码: ord(s[i])-ord('0')
while ((c[4]<>6) do begin for i:=1 to 3 do for j:=i+1 to 4 do if c[i]>c[j] then begin temp:=c[i]; c[i]:=c[j]; c[j]:=temp end; for i:=1 to 4 do t[i]:=c[5-i]; for i:=1 to 4 do begin c[i]:=c[i]-t[i]; j:=i; (c[1]<>4) or (c[2]<>7) or (c[3]<>1) or (c[4]<>6)
while c[j]<0 do begin c[j]:=c[j]+10; j:=j+1; c[j]:=c[j]-1 end end; step:=step+1 end; assign(output,'cab.out'); rewrite(output); writeln(step); close(output) end.
M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N报数,凡报到N的猴子退出到圈外,如此循环报数,直到圈内只剩下一只猴子时,这只猴子就是大王.M和N由键盘输入,打印出最后剩下的那只猴子的编号.M只猴子要选大王,选举办法如下:所有猴子按1…M编号围坐一圈,从第1号开始按顺序1,2,…,N报数,凡报到N的猴子退出到圈外,如此循环报数,直到圈内只剩下一只猴子时,这只猴子就是大王.M和N由键盘输入,打印出最后剩下的那只猴子的编号. 这个例题是由古罗马著名史学家Josephus提出的问题演变而来的,所以通常称为Josephus(约瑟夫)问题. • 猴子选大王
分析: 在确定程序设计方法之前首先来考虑如何组织数据,由于要记录m只猴子的状态,可利用含m个元素的数组monkey来实现.利用元素下标代表猴子的编号,元素的值表示猴子的状态,用monkey[k]=1表示第k只猴子仍在圈中,monkey[k]=0则表示第k只猴子已经出圈.程序采用模拟选举过程的方法,开始时将报数变量count置为1,用变量current表示当前报数的猴子的编号,也置为1,变量out记录出圈猴子数.当报数达到n时,对当前报数的猴子作出圈处理,即monkey[current]置0, count置0,out增加1.然后继续往下报数,直到圈中只剩一只猴子为止.
program ex4_2(input,output); const maxm=100; var i,m,n,count,current,out:integer; monkey:array [1..maxm] of integer; begin write('Input m,n:'); readln(m,n); for i:=1 to m do monkey[i]:=1; out:=0; count:=1; current:=1; while out<m-1 do begin • 程序代码:
while do begin repeat{寻找圈上的下一只猴子} current:=current+1; if current=m+1 then current:=1 until monkey[current]=1; count:=count+1 end; ; out:=out+1; ;end; for i:=1 to m do if monkey[i]=1 then writeln('The monkey king is no.',i) end. count<n monkey[current]:=0 count:=0
设有一个数组A:ARRAY[1..N] OF INTEGER;数组中存储的元素为1-N之间的整数,且A[I]≠A[J] (当I≠J)时。 例如:N=5时,有:(4,3,0,5,1,2) 此时,数组A的编码定义如下: A[1]的编码为0: A[I]的编码为:在A[1],A[2],……A[I-1]中比A[I]的值小的元素的个数(I=1,2,……N) 所以上面数组A的编码为:B=(0,0,0,3,1,2) 程序要求解决以下问题 ① 给出数组A后,求出其编码; ② 给出数组A的编码后,求出A的原数据。 • 编码和解码问题
问题①比较简单,只要统计一下即可。问题②是一个线性表的删除问题,将1到 N之间的N个整数顺序放在一个线性表C中,取出编码数组B中的最后一个元素b[N],则C中的第b[N]个元素为数组A的最后一个元素,取出该元素后从C中删除之,再取编码数组B中的前一个元素,重复上述操作,直到数组A的所有元素都得到为止。 • 分析
program ex4_1(input,output); const maxn=3000; type arraytype=array [1..maxn] of integer; var n,m,select,i,j,len:integer; a,b,c:arraytype; begin assign(input,'code.in');assign(output,'code.out'); reset(input);rewrite(output); • 程序代码