备战NOIP提高组初赛复习数据结构篇Word文件下载.docx
- 文档编号:21748458
- 上传时间:2023-02-01
- 格式:DOCX
- 页数:53
- 大小:57.21KB
备战NOIP提高组初赛复习数据结构篇Word文件下载.docx
《备战NOIP提高组初赛复习数据结构篇Word文件下载.docx》由会员分享,可在线阅读,更多相关《备战NOIP提高组初赛复习数据结构篇Word文件下载.docx(53页珍藏版)》请在冰豆网上搜索。
项目ixij
……
项目8
选手总分sumSumxj=
(图1—1)
线性表具有如下结构特征:
均匀性:
即同一线性表的各数据元素的数据类型一致且数据项数相同;
有序性:
表中数据元素之间的相对位置是线性的,即存在唯一的“第一个”和“最后一个”数据元素。
除第一个和最后一个外,其它元素前面均只有一个数据元素(直接前趋)和后面均只有一个数据元素(直接后继)。
按照表中数据元素的存储方式分顺序存储结构和链式存储结构二类线性表。
顺序存储结构是指用一组地址连续的存贮单元依次存储线性表的元素,通常用数组实现;
而在链式存储结构的线性表中,逻辑上相邻的两元素,其物理位置不要求相邻。
其实现既可采用静态数组,亦可采用动态指针。
为了扩大用户空间和更多地体现链式存储结构的便利,实践中大都采用动态链表形式。
为此,本书在讲解顺序存储结构的线性表时采用数组类型,在讲解链式存储结构的线性表采用指针类型。
另外,根据存取方式的限制和表元素类型的限制,还存在几种特殊类型的线性表:
栈、队列、串,它们一般采用顺序存储结构
§
1.1数组
我们称有限个同类型数据元素的序列为数组,它是一种定长的线性表。
若数组元素不再有分量,该序列叫一维数组;
若数据元素为数组,则称该元素为多维数组。
例如
var
A:
array[c‥d]ofatype;
B:
array[c1‥d1,c2‥d2]ofbtype;
A为一维数组,表长为(d-c+1),元素类型为atype;
B为二维数组,表长为(d1-c1)*(d2-c2),元素类型为btype。
一维数组和多维数组的元素个数由其类型说明或变量说明静态确定,执行中不能增减其内存空间。
一、数组的顺序存储结构
数组的物理实现是一块连续的存储空间,它是按首址(表中第1个元素的地址)十位移来访问每一个元素的。
设
loc(a[i])—A表中元素i的内存地址(c≤i≤d);
loc(b[i,j])—B表中(i,j)元素的内存地址(c1≤i≤d1,c2≤j≤d2);
loc(a[i])=loc(a[c])+(i-c)*lala—atype类型的长度;
首址位移
loc(b[i,j])=loc(b[c1,c2])+((d2-c2+1)*(i-c1)+(j-c2))*lblb—btype类型的长度;
一维数组按照下标递增的顺序访问表中元素
a[c]→a[c+1]→……→a[d]
二维数组按照先行后列的顺序访问表中元素
b[c1,c2]→b[c1,c2+1]→……→b[c1,d2]→……→b[i-1,d2]→b[i,c2]→……→b[d1,d2-1]→b[d1,d2]
在数组中,数据元素的下标间接反映了数据元素的存储地址。
而计算机内存是随机存取的装置,所以在数组中存取一个数据元素只要通过下标计算它的存储地址就行了,数组中任意一个元素的存取时间都相等。
从这个意义上讲,数组的存储结构是一个随机存取的结构。
二、数组在顺序存储结构下的插入与删除
设数组定义为
Constm=数组的长度上限;
Typevtype=array[1‥m]ofelementype;
{数组类型}
n:
integer;
{数组的实际长度}
v:
vtype;
{数组}
按上述定义,v为一个长度为n的数组v={v[1],v[2],……,v[n]},元素类型为elementype。
1、插入操作
现要在数组的第i-1个元素v[i-1]与第i个元素v[i]之间插入一个新元素b,插入后将得到一个长度为n+1的新数组v’={v’[1],…,v’[n],v’[n+1]}
插入前后两数组的元素v[j]与v’[j]满足如下关系
显然,若插入运算在数组未尾(即在v[n]后插入新元素)进行,则只要在数组末尾增加一个元素即可。
但是,在一般情况下,如果插入运算在第i(1≤i≤n)个元素之前进行,则原来第i个元素及其之后的所有元素都必须移动。
移动从最后一个元素(即v[n])开始,直到第i个元素之间共n-i+1个元素依次向后移动一个位置,然后将新元素插入第i项:
procedureinsert(b:
elementype;
i:
varn:
varv:
vtype);
begin
ifn≥m{上溢}
thenwriteln(‘overflow’)
elseif(i<
1)or(i>
n+1)
thenwriteln(‘without’)
elsebegin
forj:
=ndowntoidov[j+1]←v[j];
{v[i]‥v[n]向后移动一个位置}
v[i]←b;
n←n+1;
{b插入i位置,v数组的长度+1}
end;
{else}
{insert}
执行insert过程的时间复杂度:
对顺序存储的数组作一次插入运算,平均起来,大约需要移动数组中一半的元素。
2、删除操作
现要删除数组v中的第i个元素,使得删除后的v数组变为v’={v’[1],v’[2],……,v’[n-1]},其长度变为n-1。
显然删除前后两数组元素v[j]和v’[j]满足下列关系
同样,为了删除数组中第i个元素,则原来第i个元素之后的所有元素必须依次向前移动一个位置。
如果要删除数组最后一个元素,则很简单,不需要移动数组元素;
如果要删除数组的第一个元素,则很复杂,必须将数组中的所有元素依次向前移动一个位置。
在一般情况下,要删除第i个元素,需要将数组中第i+1到第n共n-i个元素依次向前移动一个位置。
proceduredelet(i:
if(i<
1)or(i>
n)
thenwriteln(‘without’)
=iton-1dov[j]←v[j+1];
{v[i+1]‥v[n]向前移动一个位置}
n←n-1;
{v数组的长度-1}
{else}
end;
{delet}
执行delet过程的时间复杂度:
对顺序存储的数组作一次删除,平均起来,大约需要移动表中一半的元素。
综上所述,数组的顺序分配,其结构比较简单,便于随机访问数组中的任一元素。
但是如果数组要保持线性表特征的话(由下标指明元素间的有序性),其增删操作的效率比较低。
特别当数组很大时,插入与删除运算颇为费时。
因此,比较小的数组或元素不常变动(很少进行插入与删除运算)的数组可用作线性表,而对于大的线性表或元素经常变动的线性表,可以采用链式存储结构。
三、数组的应用实例
1、在编程时(使用任一种高级语言,不一定是Pascal),如果需要从磁盘文件中输入一个很大的二维数组(例如1000*1000的double型数组),按行读(即外层循环是关于行的)与按列读(即外层循环是关于列的)相比,在输入效率上()。
A.没有区别B.有一些区别,但机器处理速度很快,可忽略不计
C.按行读的方式要高一些D.按列读的方式要高一些E.取决于数组的存储方式。
1.2栈
栈是一种线性表,对它的插入和删除都限制在表的同一端进行。
这一端叫做栈的“顶”,另一端则叫做栈的“底”。
根据栈的定义,每次删除的总是当前“最年轻”的表目,即最后插入的表目,而最先插入的表目则被放在栈的底部,要到最后才能删除。
因此,栈又被称为“后进先出表”(LIFO—lastinputfirstoutput)。
仿佛食堂里的一叠盘子,每次只许一个一个地往上堆,一个一个地往下取。
通常栈可以用顺序的方式存储,分配一块连续的存储区域存放栈中的表目,并用一个变量t指向当前栈顶。
假设栈中表目数的上限为m,所有表目都具有同一类型stype,则可以用下列方式定义栈:
Const
m=栈表目数的上限;
Type
stack=array[1‥m]ofstype;
{栈类型}
Var
s:
stack;
{栈}
t:
integer;
{栈顶指针}
m
t→
……………
1
栈s
(图1.2—1)
一、栈的基本运算
1、过程push(s,x,t)—往栈s中压入一个值为x的表目
procedurepush(vars:
x:
stype;
vart:
integer);
ift=mthenwriteln(‘overflow’){上溢}
elsebegint←t+1;
s[t]←x;
{else}{x入栈}
{Push}
2、函数pop(s,t)—从栈中弹出一个表目
functionpop(vars:
integer):
ift=0thenwriteln(‘underflow’){下溢}
elsebeginpop←s[t];
t←t-1;
{else}{栈顶元素出栈}
{pop}
3函数top(s,t)—读栈顶元素
functiontop(s:
ift=0thenwriteln(‘stackempty’)
elsetop←s[t];
{返回栈顶元素}
{top}
二、栈的应用
1.递归过程和函数调用时,处理参数和返回地址,通常使用一种称为()的数据结构。
A.队列B.多维数组C.线性表D.链表E.栈
2.设栈S的初始状态为空,元素a,b,c,d,e,f依次入栈,出栈顺序为b,d,c,f,e,a那么栈容量至少应该是()。
A.6B.5C.4D.3E.2
3.某个车站呈狭长形,宽度只能容下一台车,并且只有一个出入口。
已知某时刻该车站状态为空,从这一时刻开始的出入记录为:
“进,出,进,进,进,出,出,进,进,进,出,出”。
假设车辆入站的顺序为1,2,3,……,则车辆出站的顺序为()。
A.1,2,3,4,5B.1,2,4,5,7C.1,4,3,7,6
D.1,4,3,7,2E.1,4,3,7,5
4.地面上有标号为A、B、C的3根细柱,在A柱上放有10个直径相同中间有孔的圆盘,从上到下次依次编号为1,2,3,……,将A柱上的部分盘子经过B柱移入C柱,也可以在B柱上暂存。
如果B柱上的操作记录为:
“进,进,出,进,进,出,出,进,进,出,进,出,出”。
那么,在C柱上,从下到上的盘子的编号为()。
A.243657B.241257C.243176
D.243675E.214375
5.设栈S的初始状态为空,元素a,b,c,d,e依次入栈,以下出栈序列不可能出现的有()(不定项)。
A.a,b,c,e,dB.b,c,a,e,d
C.a,e,c,b,dD.d,c,e,b,a
6.表达式a*(b+c)-d的后缀表达式是:
A)abcd*+-B)abc+*d-C)abc*+d-D)-+*abcd
1.3队列
一、队列的基本概念
队列是不同于栈的另一种线性表。
在日常生活中,无论是购物、订票或候车都有可能要排队。
排队所遵循的原则是“先来先服务”,后来者总是加到队尾,排头者总是先离开队伍。
队列就是从日常生活中的排队现象抽象出来的。
所谓队列,就是允许在一端进行插入,在另一端进行删除的线性表。
允许插入的一端称为队尾,通常用一个队尾指针r指向队尾元素,即r总是指向最后被插入的元素;
允许删除的一端称为队首,通常也用一个队首指针f指向排头元素的前面。
初始时f=r=0。
abcdbcdBcde
一个队列删除一个元素插入一个元素
(图1.3—1)
显然,在队列这种数据结构中,最先插入在元素将是最先被删除;
反之最后插入的元素将最后被删除,因此队列又称为“先进先出”(FIFO—firstinfirstout)的线性表。
与栈相似,队列的顺序存储空间可以用一维数组q[1‥m]模拟:
m=队列元素的上限;
equeue=array[1…m]ofqtype;
{队列的类型定义}
q:
equeue;
{队列}
r,f:
{队尾指针和队首指针}
Q:
1m
(图3.1—2)
二、队列的基本运算
队列的运算主要有两种
1、过程ADD(q,x,r)—在队列q的尾端插入元素x
procedureADD(varq:
equeue;
qtype;
varr:
ifr=mthenwriteln(‘overflow’){上溢}
elsebegin{后移队尾指针并插入元素x}
r←r+1;
q[r]←x;
{ADD}
2、过程DEL(q,y,f,r)—取出q队列的队首元素y
procedureDEL(varq:
vary:
varf:
iff=rthenwriteln(‘underflow’){下溢}
elsebegin{后移队首指针并取出队首元素}
f←f+1;
y←q[f];
{DEL}
由于队列只能在一端插入,在另一端删除,因此随着入队及出队运算的不断进行,就会出现一种有别于栈的情形:
队列在数组中不断地向队尾方向移动,而在队首的前面产生一片不能利用的空闲存储区,最后会导致当尾指针指向数组最后一个位置(即r=m)而不能再加入元素时,存储空间的前部却有一片存储区无端浪费,这种现象称为“假溢出”。
例如:
mmmr→mAm
A4
3A3f,r→3f→3
2A222
11A111
f,r→f→
初始时队列空加入三个元素删除三个元素队列空加入m-3个元素队列满
f=r=0f=0r=3f=r=3r=mf=3
(图1.3—3)
三、循环队列及其运算
所谓循环队列,就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用,循环队列的定义如队列。
当存储空间的最后一个位置已被使用而要进行入队运算时,只要存储空间第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。
采用首尾相接的循环队列结构后,可以有效地解决假溢出的问题,避免数据元素的移动。
对循环队列操作有以下几种状态:
初始时队列空,队首指针和队尾指针均指向存储空间的最后一个位置,即f=r=m。
入队运算时,尾指针进一,即
ifr=m+1thenr←1;
这两条语句可用一条语句替代:
r←(r+1)modm;
出队运算时,首指针进一,即
iff=m+1thenf←1;
f←(f+1)modm;
队列空时有f=r。
队列满时有f=(r+1)modm。
(为了区分队列空和队列满,改用“队尾指针追上队首指针”这一特征作为队列满标志。
这种处理方法的缺点是浪费队列空间的一个存储单元)
循环队列的运算有两种:
1、过程ADD2(q,x,r)—在循环队列q中插入一个新元素x
procedureADD2(varq:
begin
t←(r+1)modm;
{计算插入位置}
ift=fthenwriteln(‘full’){队列满}
elsebegin{新元素x插入队尾}
r←t;
{ADD2}
2过程DEL2(q,y,f)—从循环队列q中取出队首元素y
procedureDEL2(varq:
inteqer);
iff=rthenwriteln(‘empty’){队列空}
f←(f+1)modm;
y←q[f];
{取出队首元素}
{DEL2}
四、队列的应用举例
1.设栈S和队列Q的初始状态为空,元素e1,e2,e3,e4,e5,e6依次通过栈S,一个元素出栈后即进入队列Q,若出队的顺序为e2,e4,e3,e6,e5,e1,则栈S的容量至少应该为()。
A)2B)3C)4D)5
1.4串
前面介绍的线性表的操作都是对一个元素进行处理的,但实际中我们经常要对一串元素进行操作。
如信息检查系统、文字编辑系统、自然语言翻译系统以及音乐分析程序等等,都是以字符串数据作为处理对象的。
随着非数值的广泛应用,字符串的处理将显得越来越重要。
一、串的基本概念
串是由零个或多个字符组成的有限序列。
一个串中包含的字符个数称为这个串的长度。
长度为零的串称为空串,它不包含任何字符。
通常用撇‘’将字符串括起来。
⑴‘x1’长度为2的串
⑵‘123’长度为3的数串
⑶‘’长度为0的空串
⑷‘’包含一个空白字符(长度为1)的非空串
假设s1和s2是两个串:
s1=a1……an
s2=b1……bm
其中ai、bi代表字符(0≤m≤n)。
如果存在整数i(0≤i≤n-m),使得
bj=ai+jj=1‥m
同时成立,则称s2是s1的子串,又称串s1包含串s2。
串中所能包含的字符依赖于具体机器的字符集,按字符的字符集中的次序可以规定字符的大小。
目前世界上最为广泛的字符集是ASCII(美国信息变换标准码)和EBCDIC(扩充的二进制编码、十进制信息码),它们都规定数字字符‘0’‥‘9’的字符集是顺序排列的,字母字符‘A’‥‘Z’(‘a’‥‘z’)的字符集也是顺序排列的,因此用ord函数计算字符在字符集中的序号就有
ord(‘a’)<
ord(‘b’)<
……<
ord(‘z’)
ord(‘0’)<
ord(‘1’)<
ord(‘q’)
并且对所有数字i(0≤i≤9)满足
i=ord(‘i’)-ord(‘0’)
通常可对两个字符ch1和ch2作比较,所谓ch1<
ch2的含义就是指ord(ch1)<
ord(ch2),必要时可以将串按其构成的字符用字符顺序排列,从而定义两个串的大小。
‘a’<
’abo’<
’x’
‘012’<
’123’<
’2’
程序中使用的串可以分成两种
1、串常数
串常数具有固定的串值,即可以用直接量表示,用以原样输出,亦可以给串常数命名,以便反复使用时书写和修改方便。
constobject=’datastructure’;
{命名串常数}
writeln(‘overflow’){原样输出串常数}
2、串变量
串变量的取值是可以改变的,但必须用名字来识别,说明串变量的方法与其它变量相似。
var
string[30];
上面定义了一个串变量s,s最多能容纳30个字符,且顺序存在一个字符数组中,类似于
array[0‥30]ofchar;
其中s[0]记载了s的实际长度。
若string类型中省略长度标记,则串长上限为255个字符。
二、串的基本运算
PASCAL中提供了一些串运算的库函数,我们将作以简单的介绍
1、连接运算——函数concat(s1,[,s2,…,sn])
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 备战 NOIP 提高 初赛 复习 数据结构