基本的数据结构.docx
- 文档编号:8079936
- 上传时间:2023-01-28
- 格式:DOCX
- 页数:26
- 大小:175.78KB
基本的数据结构.docx
《基本的数据结构.docx》由会员分享,可在线阅读,更多相关《基本的数据结构.docx(26页珍藏版)》请在冰豆网上搜索。
基本的数据结构
1.2基本的数据结构
(8课时机上8课时)
1.2基本的数据结构(8课时)
第一课时
教学目标
数据结构的概念,基本的数据结构及其优缺点,和数据结构相关的几个定义(数据库,字段,关键字)。
1.2.1.1什么是数据结构
数据结构是对在计算机内存中(有时在磁盘中)的数据的一种安排。
数据结构包括数组,表,栈,二叉树,哈希表等。
数据结构可以解决哪些方面的问题呢?
粗略的估计一下,可以用于以下三类情况:
·现实世界数据存储
·程序员的工具
·建模
现实世界数据存储——现实世界数据值得是哪些描述处于计算机外部的物理实体的数据。
看几个例子:
一条人事档案记录描述了一位真实人的记录,一条存货记录描述了一个真实存在的汽车部件或杂货店里的一种商品,一条财务交易记录描述了一笔支付电费实际填写的支票。
举一个非计算机的现实世界数据存储的例子,有一叠3x5的索引卡片,这些卡片可以被用在不同的场合。
如果每张卡片上写有某人的姓名,地址和电话号码,那么折叠卡片一定是一本地址簿。
如果每一张卡片上写有家庭拥有物的名称,位置和价值,那么这一定是一本家庭财产清单。
当然索引卡片并不能代表现在的科技发展水平。
几乎索引以前用索引卡片处理的事务现在都可以用计算机来处理。
如果想将旧式的所以卡片系统更新为计算机程序,边有可能会发现会被如下问题所困扰:
·如何在计算机内存中安放数据?
·所用方法适用于100张卡片吗?
那1000张呢?
10000000张呢?
·所用方法能够快速的插入新卡片和删除老卡片吗?
·它能快速的查找一张特定的卡片吗?
·若想将卡片按照字母顺序排列,又应该如何去排呢?
然而,大多数程序比所以卡片要复杂得多。
想象一下机动车管理部门的数据库,这个库被用来记录驾驶员的执照的情况;或者看一个航班预定系统,这个系统存储了旅客和航班的各种信息。
这些系统由许多数据结构组成。
程序员的工具——并不是所有的数据结构都用来存储现实世界的数据。
通常情况下,现实世界的数据或多或少会由程序的用户直接存取。
但是有些数据存储结构并不打算让用户接触,它们仅被程序本身所使用。
程序员经常将诸如栈,队列和优先级队列等结构当作结构来简化另一些操作,这些数据结构就是程序员的工具了。
现实世界的建模——有些数据结构能直接对现实世界的情况构造建模。
其中最重要的数据结构是图。
图可以用来表示城市之间的航线。
电路中的连接线和连接点,或者是某一工程中的任务安排关系。
其它诸如栈和队列等数据结构也会应用在时间的建模中。
例如,一个队列可以模拟顾客在银行中排队等待的模型,还可以模拟汽车在收费站前面等待缴费的模型等等。
1.2.1.2基本的数据结构及其优缺点
知道了数据结构的概念及基本用途,那么到底有哪些数据结构,以及它们各自的优点和缺点有哪些呢接下来我们用下面的表格来对基本的数据结构以及其优缺点进行详细说明:
数据结构
优点
缺点
数组
插入块,如果知道下标,可以非常快的存取
查找慢,删除慢,大小固定
有序数组
比无序的数组查找快
删除和插入慢,大小固定
栈
提供后进先出方式的存取
存取其它项很慢
队列
提供先进先出方式的存取
存取其它项很慢
链表
插入快,删除快
查找慢
二叉树
查找,插入,删除都快(如果数保持平衡)
删除的算法比较复杂
红-黑树
查找,插入,删除都快,树总是平衡的
算法复杂
2-3-4树
查找,插入,删除都快。
书总是平衡的,类似的树对磁盘存储有用
算法复杂
哈希表
如果关键字已知则存取极快,插入快
删除慢,如果不知道关键字很慢,对存储空间使用不充分
堆
插入,删除快,对最大数据项的存储很快
对其它数据项存取慢
图
对现实世界建模
有些算法慢且复杂
知道了这些基本的数据结构及其优缺点,那么我们再平平时的编程中选择正确的数据结构将会大大提高程序的运行效率。
1.2.1.3关于数据结构的一些概念
数据库(database)——我们将会使用数据库这个术语来表示在某一特定情况下所有要查阅的数据,数据库中的每一条数据都被认为是同样格式的,这种存储数据的统一格式就是我们前面所说的数据结构。
例如:
如果使用索引卡片来做一本地址簿,其中所有的卡片便构成了一个数据库,没一张卡片就是一条数据,而卡片本身就是数据结构。
记录(record)——记录是指数据库中划分成的单元。
它们为存储信息提供了一个结构格式。
在索引卡片的模拟系统中,每一张卡片就代表一条记录。
当有许多类似的实体时,一条记录包含了某一个实体的所有信息。
一条记录可能应对与人事档案中的某一个人,汽车供应存货目录中的某一个零部件,或是烹调书中的某一道菜谱。
字段(field)——一条记录经常被划分为几个字段。
一个字段保存某一种特定的数据。
在地址簿中的一张索引卡片上,一个人的名字,地址或电话号码都是一个独立的字段。
更复杂的数据库程序使用带有更多字段的记录。
如下图显示了一条记录,其中每一行代表了一个不同的字段。
雇员号码:
社会保险号码:
姓:
名:
地址:
城市:
省:
邮编:
电话:
生日:
开始工作时间:
工资:
在java语言(和其它面向对象语言)中,记录经常被表示为一个相应类的对象。
一个实例中各个变量表示不同的数据字段(datafield)。
关键字——在数据库中查找一条记录,需要指定记录的某一个字段位关键字(或查找关键字)。
通过这个特定的关键字来进行查找。
例如,在一个地址簿的程序中,可以再每条记录的姓名字段中查找关键字“Brown”。
当找到具有该关键字的记录时,便可以访问它的所有字段,而不仅仅是关键字了,可以说是关键字释放了整个记录。
还可以通过电话号码字段或地址字段在整个文件中再次查找。
上图中任何字段都可以被用作查找关键字。
第二课时
教学目标
一维数组的概念,一维数组的创建,一维数组的初始化,一维数组数据项的访问。
1.2.2.1引言
数组(array)是相同类型变量的集合,可以使用共同的名字引用它。
它是应用最广泛的数据结构,被植入到大部分变成语言中。
由于数组十分易懂,所以它被用来作为介绍数据结构的起步点,并展示面向对象变成和数据结构之间的关系。
数组可以被定义为任何类型,可以是一维的也可以是多维的。
数组中的一个特别要素是通过下标来访问他。
数组提供了一种将有联系的信息分组的便利方法。
下面我们来详细介绍一维数组。
1.2.2.2一维数组的创建
一维数组(one-dimensionalarray)实质上市相同类型变量列表。
正如第一章所提到的,java中有两种数据类型:
基本类型(如int,double等)和引用类型在许多编程语言中(甚至有些面向对象语言,如C++),数组也是基本类型,但在java中把它当作对象类型来对待,因此在创建数组时必须使用new操作符。
要创建一个数组,你必须首先定义数组变量所需的类型。
通用的一维数组的声明格式是:
Typevar-name[];
获得一个数组需要两步。
第一步,你必须定义变量所需的类型。
第二步,你必须使用运算符new来为数组所要存储的数据分配内存,并把它们分配给数组变量。
这样java中的数组被动态地分配。
如下所示:
Int[]intArray;//声明一个数组变量
intArray=newint[100]//给数组变量分配内存空间
或者使用等价的但语句声明方法:
Int[]intArray=newint[100];
[]操作符对于编译器来说是一个标志,它说明正在命名的是数组对象而不是普通的变量。
当然还可以通过另一种语法来使用这个操作符,将它放在变量名的后面而不是类型的后面:
IntintArray[]=newint[100];
但是将[]放在int后面会清楚的说明[]是数据类型的一部分,而不是变量名的一部分。
由于数组是一个对象,所以它的名字(前面程序中的intArray)是数组的一个引用:
它并不是数组本身。
数组存储在内存中的其它地址中,而intArray仅仅保存着这个地址。
数组有一个length字段,通过它可以得知当前数组大小(数据项的个数);
Intarraylength=intArray.length;//取得数组长度
数组一旦被创建,其大小不可改变。
1.2.2.3一维数组的初始化
当创建整型数组后,如果不另行指定,那么整型数组会自动初始化成空。
与C++不同的是,即使通过方法(函数)来定义数组也是这样的。
常见一个对象数组如下:
autoData[]varArray=newautoData[4000];
除非将特定的值赋给数组数据项,否则它们一直是特殊的null对象。
如果尝试访问一个含有null的数组数据项,程序会出项NullPointerAssignment(空指针赋值)的运行错误。
这主要是为了保证在读取某个数据项之前要先对其赋值。
使用下面的语法可以对一个基本类型的数组初始化,赋入非空值:
int[]intArray={0,3,6,9,12,15,18,21,24,27};
上面的语句可能简单的令人惊讶,它同时取代了引用声明和使用new来创建数组。
在大括号中的数据被称为数据列表。
数组大小由列表中数据项的个数决定。
1.2.2.4一维数组数据项的访问
数组数据项通过使用方括号中的下标数来访问。
这与其它语言类似:
Temp=intArray[3];//定义一个有四个数据项的数组
intArray[7]=66;//给第八个数组元素赋值为66
请注意无论是C,C++,还是java中,第一个数据项的下标都是0,所以,一个有10个数据项的数组小标是0至9.
如果访问小于0或者比数组大小大的数据项,程序会出现ArrayIndexOutOfBounds(数组小标越界)的运行错误。
第三-四课时
教学目标
多维数组概念,多维数组的声明,多维数组的初始化,多维数组长度的取得,锯齿数组的简单介绍。
1.2.3-4.1引言
在学校里,由于一个班的人数不多,所以按照顺序编号即可,当人数增多时,例如对于学校里的人,在编号时就要增加层次,例如XX班XX号。
在部队中也是这样,XX师XX团XX营XX连XX排XX班,这里的层次就比较深了。
为了管理数据的方便,一般要加深管理的层次,这就是多维数组的由来。
多维数组,指二维以及二维以上的数组。
二维数组有两个层次,三维数组有三个层次,依次类推。
每个层次对应一个下标。
在实际使用中,为了使结构清晰,一般对于复杂的数据都是用多维数组。
关于多维数组的理解,最终的是理解数组的数组这个概念,因为数组本身就是一种复合数据类型,所以数组也可以作为数组元素存在。
这样二维数组就可以理解成内部每个元素都是一维数组类型的一个一维数组。
三维数组可以理解成一个一维数组,内部的每个元素都是二维数组。
无论在逻辑上还是语法上都支持“数组的数组”这种理解方式。
通常情况下,一般用二维数组的第一维代表行,第二维代表列,这种逻辑结构和现实中的结构一致。
和一维数组类似,因为多维数组有多个下标,那么引用数组中的元素时,需要指定多个下标。
下面以二维数组为例,来介绍多维数组的语法。
1.2.3-4.2多维数组声明
多维数组的声明如下:
数据类型[][]数组名称;
数据类型[]数组名称[];
数据类型数组名称[][];
以上三种语法在声明二维数组时的功能是等价的。
同理,声明三维数组时需要三对中括号,中括号的位置可以在数据类型的后面,也可以在数组名称的后面,其它的依次类推。
例如:
int[][]map;
charc[][];
和一维数组一样,数组声明以后在内存中没有分配具体的存储空间,也没有设定数组的长度。
1.2.3-4.3多维数组初始化
和一维数组一样,多维数组的初始化也可以分为静态初始化(整体赋值)和动态初始化两种,其语法格式如下。
静态初始化——以二维数组的静态初始化为例,来说明多维数组静态初始化的语法格式。
示例代码如下:
int[][]m={
{1,2,3},
{2,3,4}
};
在二维数组静态初始化时,也必须和数组的声明写在一起。
数值书写时,使用两个大括号嵌套实现,在最里层的大括号内部书写数字的值。
数值和数值之间使用逗号分隔,内部的大括号之间也使用逗号分隔。
由该语法可以看出,内部的大括号其实就是一个一维数组的静态初始化,二维数组只是把多个一维数组的静态初始化组合起来。
同理,三维数组的静态初始化语法格式如下:
int[][][]b={
{
{1,2,3},
{1,2,3}
},
{
{3,4,1},
{2,3,4}
}
};
说明:
这里只是演示语法格式,数值本身没有意义。
动态初始化——二维数组动态初始化的语法格式:
数据类型[][]数组名称=new数据类型[第一维的长度][第二维的长度];
数据类型[][]数组名称;
数组名称=new数据类型[第一维的长度][第二维的长度];
示例代码:
byte[][]b=newbyte[2][3];
intm[][];
m=newint[4][4];
和一维数组一样,动态初始化可以和数组的声明分开,动态初始化只指定数组的长度,数组中每个元素的初始化是数组声明时数据类型的默认值。
例如上面初始化了长度为2X3的数组b,和4X4的数组m。
使用这种方法,初始化出的第二维的长度都是相同的,如果需要初始化第二维长度不一样的二维数组,则可以使用如下的格式:
intn[][];
n=newint[2][];//只初始化第一维的长度
//分别初始化后续的元素
n[0]=newint[4];
n[1]=newint[3];
这里的语法就体现了数组的数组概念,在初始化第一维的长度时,其实就是把数组n看成了一个一维数组,初始化其长度为2,则数组n中包含的2个元素分别是n[0]和n[1],而这两个元素分别是一个一维数组。
后面使用一维数组动态初始化的语法分别初始化n[0]和n[1]。
1.2.3-4.4引用多维数组元素
对于二维数组来说,由于其有两个下标,所以引用数组元素值的格式为:
数组名称[第一维下标][第二维下标]
该表达式的类型和声明数组时的数据类型相同。
例如引用二维数组m中的元素时,使用m[0][0]引用数组中第一维下标是0,第二维下标也是0的元素。
这里第一维下标的区间是0到第一维的长度减1,第二维下标的区间是0到第二维的长度减1。
四、获得多维数组长度
对于多维数组来说,也可以获得数组的长度。
但是使用数组名.length获得的是数组第一维的长度。
如果需要获得二维数组中总的元素个数,可以使用如下代码:
int[][]m={
{1,2,3,1},
{1,3},
{3,4,2}
};
intsum=0;
for(inti=0;i sum+=m[i].length;//第二维的长度相加 } 在该代码中,m.length代表m数组第一维的长度,内部的m[i]指每个一维数组元素,m[i].length是m[i]数组的长度,把这些长度相加就是数组m中总的元素个数 1.2.3-4.5锯齿数组 下面我们要介绍一种比较特殊的二维数组,可能大家也已经注意到了,在前面我们所举的例子中就有这么一种数组,它的第二维的长度是不一样的,我们把这种第二维长度不同的二维数组叫做锯齿数组。 锯齿数组直接初始化——锯齿数据直接初始化的格式形如下面: int[][]a={{1,2},{3,4,5,6,7,8},{9},{0,1,2}}; 锯齿数组的动态初始化如下: int[][]a; a=newint[4][]; a[0]=newint[2]; a[1]=newint[6]; a[2]=newint[1]; a[3]=newint[3]; 第五课时 教学目标 枚举类型的概念,枚举类型的使用,枚举类型的特点。 1.2.5.1枚举类型 我们已经知道,Java代码的两个基本的构造块是类和接口。 现在又引入了枚举,一般简称它为enum。 那么什么是枚举呢,枚举其实就是一种类型,跟int,char这种差不多,就是定义变量时限制输入的,你只能够赋enum里面规定的值。 这个新类型允许您表示特定的数据点,这些数据点只接受分配时预先定义的值集合。 当然,熟练的程序员可以使用静态常量实现这项功能,就是我们常说的publicstaticfinal代码。 如下所示: PublicclassOldGrade{ publicstaticfinalintA=1; publicstaticfinalintB=2; publicstaticfinalintC=3; publicstaticfinalintD=4; publicstaticfinalintF=5; publicstaticfinalintINCOMPLETE=6; } 但是在这样做的时候,请记住这类常量是Java中int类型的常量,这意味着该方法可以接受任何int类型的值,即使它和OldGrade中定的所有级别都不对应。 因此,您需要检测上界和下界,在出现无效值的时候,可能还要包含一个IllegalArgumentException。 而且,如果后来又添加另外一个级别(例如OldGrade.WITHDREW_PASSING),那么必须改变所有代码中的上界,才能够接受现在的这个值。 换句话说,在使用这类带有整型常量的类时,该解决方案也许可行,但并不是非常有效。 幸运的是,枚举提供了更好的方法。 1.2.5.2枚举类型的定义 枚举类型在定义时要使用一个关键字enum,为enum提供了一个名称,并指定了允许的值。 形如下面的例子: PublicenumGrade{ A,B,C,D,F,INCOMPLETE }; 1.2.5.3枚举的使用 枚举类型最经常的用法,是使用枚举类型,在各个枚举值之间切换做各种分歧处理,及常用的switch语句。 把枚举的各个值,作为switch语句的各个case来进行所需要的处理。 当然必须切记的是这时候的switch语句中一定要在处理完所有的case后在加上default处理块,以免枚举类型被程序员修改后,我们在不知情的情况下,对这种新的枚举值漏处理,而且还发现不了错误。 1.2.5.4枚举具有的核心功能 类型安全: 枚举的申明创建了一个新的类型。 它不同于其他的已有类型,包括原始类型(整数,浮点数等等)和当前作用域(Scope)内的其它的枚举类型。 当你对函数的参数进行赋值操作的时候,整数类型和枚举类型是不能互换的(除非是你进行显式的类型转换),编译器将强制这一点。 比如说,用下面申明的枚举定义这样一个函数: 枚举定义: enumDay{SUNDAY,MONDAY,TUESDAY, WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}; 函数定义: Publicvoidfun(Day); 如果你用整数作为参数来调用这个函数,那么,编译器肯定会报错。 fun(4);//错误 要调用这个函数,参数必须严格使用上面枚举中所列举出来的值。 紧凑有效的枚举数值定义: 定义枚举的程序应该很简单,虽然java中也有类似于publicstaticfinal的“准枚举”的定义,但这种枚举似乎很不简洁。 如果有大量的数据要定义,这一点就尤为重要,你也就会感受更深。 虽然这一点不如其他另外3点重要,但我们总是希望申明能尽可能的简洁。 无缝的和程序其它部分的交互操作: 语言的运算符,如赋值,相等/大于/小于判断都应该支持枚举。 枚举还应该支持数组下标以及switch/case语句中用来控制流程的操作。 比如: for(Dayd=SUNDAY;d<=SATURDAY;++d){ switch(d){ caseMONDAY: ...; break; caseTUESDAY: ...; break; caseWEDNESDAY: ...; break; caseTHURSDAY: ...; break; caseFRIDAY: ...; break; caseSATURDAY: caseSUNDAY: ...; } } 要想让这段程序工作,那么枚举必须是整数常数,而不能是对象(objects)。 Java中你可以用equals()或是compareTo()函数来进行对象的比较操作,但是它们都不支持数组下标和switch语句。 运行的高效率: 枚举的运行效率应该和原始类型的整数一样高。 在运行时不应该由于使用了枚举而导致性能比使用整数有下降。 第六-七课时 教学目标 引用型数据类型的概念,值传递,引用传递。 1.2.6-7.1引用型数据类型 早些时候的编程语言和初级程序员将每个变量看作相互无关的实体。 例如,如果一个程序需处理某个日期,则要声明三个单独的整数: intday,month,year; 上述语句作了两件事,一是当程序需要日、月或年的有关信息时,它将操作一个整数;二是为那些整数分配存储器。 尽管这种作法很容易理解,但它存在两个重大缺陷。 首先,如果程序需同时记录几个日期,则需要三个不同的声明。 例如,要记录两个生日,你可能使用: intmyBirthDay,myBirthMonth,myBirthYear; intyourBirthDay,yourBirthMonth,yourBirthYear; 这种方法很快就会引起混乱,因为需要的名称很多。 第二个缺陷是这种方法忽视了日、月和年之间的联系并把每个变量都作为一个独立的值,每个变量都是一个独立单元。 为了解决这个问题,Java引入了引用类型,允许程序员自己定义类型。 引用类型(referencetype)指向一个对象,不是原始值,指向对象的变量是引用变量。 在Java里面除去基本数据类型的其它类型都是引用数据类型,自己定义的class类都是引用类型,可以像基本类型一样使用。 在Java程序运行时,会为引用类型分配一定量的存储空间并解释该存储空间的内容。 示例如下: publicclassMyDate{ privateintday=8; privateintmonth=8; privateintyear=2008; publicMyDate(intday,intmonth,intyear){…} publicvoidprint(){…} } publicclassTestMyDate{ publicstaticvoidmain(Stringargs[]){ //这个today变量就是一个引用类型的变量 MyDatetoday=newMyDate(23,7,2008); } } 1.2.6-7.2引用类型的赋值 在Java编程语言中,用类的一个类型声明的变量被指定为引用类型,这是因为它正在引用一个非原始类型,这对赋值具有重要的意义。 请看下列代码片段:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 基本 数据结构