1、85-1,第2章 数据的线性结构,数据的逻辑关系和存储表示 线性表 栈 队列,85-2,数据的逻辑关系和存储表示,基本概念和术语 数据的逻辑结构 数据的存储方式,85-3,一、基本概念和术语,引例 例1 学生档案管理 组织成一个二维表,85-4, 组织成一棵树,85-5,例2 在n个城市间建立通信网络,代价最小,代价最小,85-6,从上面两个例子中可以看出:数据结构中元素之间存在着逻辑关系,上述例子中给出了三种逻辑结构:线性表、树、图 数据结构主要解决: 如何分析数据元素之间的关系,并确定合适的逻辑结构 如何在计算机中存储这些数据 为完成对数据的操作设计算法,并作出分析,85-7,基本概念和术
2、语,数据(data):. 数据元素(data element):. 数据项(data item) 数据对象(data object) 数据结构(data structure):.,性质相同的数据元素的集合,85-8,数 据,数据是一些可以被计算机接收和处理的描述客观事物的符号,是计算机化的信息,如数值、字符、声音、图象,返回,85-9,数据元素,数据的基本单位,又称结点(Node)或记录(Record),由一个或多个数据项(Data Item)组成如一个学生的有关信息是一个数据元素,它由姓名、学号等数据项组成数据项是数据的最小单位,返回,85-10,数 据 结 构,数据结构:描述一组性质相同的
3、数据元素及元素间的相互关系,85-11,数 据 结 构,研究内容: 数据元素之间的逻辑关系(数据的逻辑结构) 数据元素在计算机中的存储方式(数据的物理结构) 在这些数据元素上定义的运算集合(数据结构的运算),85-12,二、数据的逻辑结构,概念:客观事物本身存在的结构形式及关系 特点:描述数据间的顺序(逻辑)关系,抽象地反映数据元素的结构,而不管它们在计算机中如何存放, 与物理存放位置无关,85-13,二、数据的逻辑结构,描述方法:一个数据结构B可以用一个二元组B =(D,R) 表示。其中: D:数据元素(结点)的有限集合 R:D上的关系的有限集合。一般R中只涉及一种关系,而且大多数是数据元素
4、之间的连接关系,85-14,例3有4个人,分别为a、b、c、d,其中a是b的父亲,b是c的父亲,c是d的父亲,如果只讨论他们所表达的父子关系,则可以用下面的二元组形式化地表示为:B(D,R)其中 D=a,b,c,dR=rr = ,,85-15,例4另有4个人,分别为e,f,g,h;其中e是f和g的父亲,g是h的父亲,则可用下面的二元组形式化地表示为:B(D,R)其中 D=e,f,g,hR=rr = ,,85-16,可以用图形方式分别表示为:,a,b,c,d,f,e,g,h,85-17,几个概念设B=(D,R)是一个逻辑结构,rR,di、dj D。如果 r,则称di是dj的前驱, dj是di的后
5、继。如果某个结点没有前驱,则称之为开始结点;如果某个结点没有后继,则称之为终端结点;既非开始结点,也非终端结点的结点称之为内部结点,二、数据的逻辑结构,85-18,可以用图形方式分别表示为:,a是b的前驱、b是c的前驱、c是d的前驱 b是a的后继、c是b的后继、d是c的后继,开始结点,终端结点,85-19,线性结构整个结构中开始和终端结点均只有一个,中间结点只有一个前驱和一个后继结点。即元素之间存在着一对一的关系。 非线性结构结构中至少有一个结点存在不止一个前驱结点或后继结点。非线性结构有两类:a、树形结构:元素之间存在着一对多的关系b、图形结构:元素之间存在着多对多的关系,85-20,线性结
6、构非线性结构,85-21,三、数据的存储方法,一般地,数据的存储方法有四种: 顺序存储 链式存储 索引存储 散列存储 (后两种方法主要用于查找,此处不作详述),把逻辑上相邻的数据元素存储在物理位置相邻的存储单元之中。通常借助于程序设计语言中的数组来实现,把数据元素和指针定义成一个存储体,使用指针把发生联系的数据元素链接起来。通常借助于程序设计语言中的指针来实现,85-22,顺序存储结构,概念:把数据元素按某种顺序存放在一块连续的存储单元中的存储形式 数据结点结构:,数据域,85-23,存储举例,存储单元,字符串:A B C D E,顺序存储,插入:C+,删除:C+,C+,特点: 连续存放。逻辑
7、上相邻,物理上也相邻 结构简单,易实现 插入、删除操作不便(需大量移动元素),85-24,链式存储结构,概念:以链表形式将数据元素存放于任意存储单元中。可连续存放,也可以不连续存放。以指针实现链表间的联系 数据结点结构:,85-25,1536,元素2,1400,元素1,1346,元素3,元素4,1345,h,每个节点都由两部分组成:数据域和指针域。 数据域存放元素本身的数据, 指针域存放指针。 数据元素之间逻辑上的联系由指针来体现。,链式存储结构,85-26,链式存储结构,1536,元素2,1400,元素1,1346,元素3,元素4,1345,h,85-27,1.比顺序存储结构的存储密度小(每
8、个节点都由数据域和指针愈组成)。 2.逻辑上相邻的节点物理上不必相邻。 3.插入、删除灵活(不必移动节点,只要改变节点中的指针)。,链接存储结构特点:,链式存储结构,1536,元素2,1400,元素1,1346,元素3,元素4,1345,h,85-28,线性表,线性表定义线性表基本运算线性表的顺序存储 顺序表的基本操作 链表 单链表操作,85-29,(a1, a2, ai-1,ai, ai1 ,, an),一、线性表定义,线性表的逻辑结构:,n=0时称为,数据元素,线性起点,ai的直接前趋,ai的直接后继,下标,是元素的序号,表示元素在表中的位置,n为元素总个数,即表长。,空表,线性终点,a1
9、 - 开始结点(无前驱) an - 终端结点(无后继) ai - 中间结点,85-30,数据元素: 简单的整数、英文字母等 (1,2,7,5,3,9)(A,D,C,B,E) 较复杂的元素(记录)。由复杂元素构成的线性表又称为文件,85-31,线性表的特点,2.除第一个和最后一个数据元素之外,其它数据元素有且仅有一个前驱和一个后继。第一个数据元素无前驱,最后一个数据元素无后继,1.线性表中所有元素的性质相同,3.数据元素在表中的位置只取决于它自身的序号,85-32,1)线性表的初始化 Init_List(L):构造一个空的线性表L 2)求表长 3)取表中第i个数据元素 4)查找具有特定值的结点
10、5)插入操作 6)删除操作,二、线性表的基本运算,85-33,三、线性表的顺序存储,用一组地址连续的存储单元依次存放线性表的数据元素 特点: 逻辑上相邻的元素在物理存储上亦相邻 任一元素的存取时间相同,是一种随机存取结构,85-34,元素an,元素ai,元素a2,元素a1,b,b+m,b+(i-1)*m,b+(maxlen-1)*m,存储地址,内存状态,Loc(ai)=b +(i-1)*m,顺序存储结构示意图(顺序表):,首地址 起始地址 基地址,85-35,顺序表插入,在顺序表的第i个位置上插入一个值为x的新元素 原线性表:长度为n(a1,a2,ai-1,ai,an) 插入后的线性表:长度为
11、n+1 (a1,a2,ai-1,x,ai,an),85-36,四、顺序表的操作,初始化 构建一个空表 存储地址计算 (1)Loc(ai)=Loc(a1)+(i-1) (2)Loc(ai)=Loc(a1)+(i-1)m 顺序表插入 顺序表删除,85-37,顺序表初始化顺序表的初始化实际上就是构建一个空的顺序表L,顺序表是否为空取决于表中的元素个数是否为零,因此只需将当前表长置0即可。,85-38,实现步骤 将第n至第i 位的元素向后移动一个位置 将要插入的 元素x写到第i个位置 表长加1 注意:事先应判断 插入位置i 是否合法? 表是否已满?,x,顺序表插入,85-39,顺序表插入,核心语句,f
12、or ( j=L-length-1; j=i-1; j- )L-dataj+1 = L-dataj; L-datai-1 = x; L-length+;,/*元素后移*/,/*插入x*/,/*表长加1*/,类C,类VB,For j = L.length-1 To i-1 Step -1L.data(j + 1) = L.data(j) Next jL.data(i-1) = xL.length = L.length + 1,元素后移,插入x,表长加1,VB,C,85-40,#define ERROR 0 #define OK 1 int listinsert_sq ( sqlist *L, i
13、nt i, x ) int j;if ( L-length = maxnum ) printf( “list is full” );return (ERROR);if ( iL-length+1 )printf( “ i is invalid value” );return (ERROR);,for ( j=L-length-1; j=i-1; j- )L-dataj+1 = L-dataj; L-datai-1 = x; L-length+; return ( OK ); ,85-41,Public Sub listinsert_sq(L As sqlist, ByVal i As Inte
14、ger, ByVal x As Integer)Dim j As IntegerIf L.length = maxnum ThenMsgBox (“顺序表已满!“)Exit SubEnd IfIf i L.length + 1 ThenMsgBox (“i是非法数字或者超 出了顺序表的长度!“)Exit SubEnd If,85-42,顺序表删除,将第i(1in+1)个元素删去,使长度为n的线性表 (a1,a2,.,ai-1,ai,ai+1,.,an),变为长度为n-1的线性表 (a1,a2,.,ai-1,ai+1,.,an),85-43,顺序表删除,实现步骤 将第i+1 至第n 位的元素向前
15、移动一个位置 表长减1 注意:事先应判断删除位置i 是否合法,85-44,顺序表删除,核心语句,类C,类VB,For j = i + 1 To na(j - 1) = a(j)Next jn = n - 1,元素后移一个位置,表长减1,for ( j=i; jlength; j+ )L-dataj-1 = L-dataj; L-length-;,/*元素前移*/,/*长度减1*/,VB,C,85-45,顺序表删除算法的类C语言描述:int ListDelete_sq ( SqList *L, int i ) int j;if ( iL-length-1 ) printf( “i is inva
16、lid value” );return( ERROR ); for ( j=i; jlength; j+ )L-dataj-1 = L-dataj; /* 元素前移 */L-length-; /* 长度减1 */return ( OK ); ,85-46,顺序表删除算法的类VB语言描述: Public Sub ListDelete_sq( L As SqList, ByVal i As Integer ) Dim j As IntegerIf i L.length-1 ThenMsgBox (“i 是非法数字或者超出了顺序表的长度!“)Exit SubEnd IfFor j = i To L.
17、length-1 Step 1L.data(j - 1) = L.data(j) 元素前移Next jL.length = L.length - 1 长度减1MsgBox (“删除成功!“) End Sub,85-47,顺序表的小结,线性表顺序存储结构特点:逻辑关系上相邻的两个元素在物理存储位置上也相邻 优点:可以随机存取表中任一元素,方便快捷 缺点:在插入或删除某一元素时,需要移动大量元素;需要预先确定数据元素的最大个数 解决问题的思路:改用另一种线性存储方式:,链式存储结构,85-48,链表,特点 用一组任意的存储单元(连续或不连续)存放线性表的数据元素 结点 表中元素的存储单元 结点组成
18、,存放数据元素,存储直接后继的存储位置,85-49,链表,常用链表 单链表 结点只有一个指针域的链表 单循环链表 首尾相接的链表 双向链表 有两个指针域的链表,85-50,单链表的两种形式,带头结点的单链表,不带头结点的单链表,Head 中为 NULL,85-51,逻辑上相邻的两个数据元素,物理存储位置不要求紧邻,单链表的存储结构示例,85-52,用数组描述线性链表,用两个具有相同下标值的不同数组元素描述一个结点。 dadai:存放结点的数据域值 nexti:存放直接后继结点的存放位置(指针域值),85-53,带头结点的单循环链表不带头结点的单循环链表,head,85-54,带头结点的双向链表
19、,不带头结点的双向链表,85-55,头指针、头结点和首元结点的区别,头指针,头结点,首元结点,头指针 是指向链表中第一个结点(或为头结点、或为首元结点)的指针 头结点 是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息,它不计入表长度 首元结点 是指链表中存储线性表第一个数据元素的结点,85-56,单链表的操作,单链表插入单链表删除,85-57,单链表插入,链表原为空,新结点作为链表的第一个结点 新结点插在最前面 新结点插在某两个结点之间 新结点插在末尾,85-58,单链表插入,在第i个位置插入,算法操作步骤:,step1 找到ai-1的位置,使指针p指向ai-1,q指向a
20、i ,否则结束,step2 申请并生成新结点s,step3 使s插入到ai-1和ai之间,85-59,单链表删除,删除ai算法操作步骤: Step1 寻找第i个元素位置,若找到则由q指向第i个位置,p指向第i-1个位置;否则结束,a i-1,ai,a i+1,Step3 释放q所指向的结点空间,Step2 从链表中删除q所指向的结点,即使结点ai脱链,85-60,单链表的操作,单链表特点 插入和删除方便,不需要移动结点,只要改变指针的指向即可,85-61,栈(Stack),定义 操作受限的线性表,它限定仅在表尾进行插入和删除操作 基本术语 栈顶:允许插入、删除的一端 栈底:另一端 栈顶元素:处
21、于栈顶位置的数据元素 栈底元素:处于栈底位置的数据元素 空栈:不含任何数据元素的栈,例:元素以a1,a2, ,an的顺序进栈,栈底,栈顶,只能进出一人的死胡同 装网球的纸筒 子弹夹 ,栈的两个要素,栈的两个要素:存放栈元素的存储空间和栈顶指针,85-63,例1、一个栈的输入序列为1,2,3,若在入栈的过程中允许出栈,则可能得到的出栈序列是什么?,解:可以通过穷举所有可能性来求解: 1入1出, 2入2出,3入3出, 即123 1入1出, 2、3入,3、2出, 即132 1、2入,2出, 3入3出, 即231 1、2入,2、1出,3入3出, 即213 1、2、3入,3、2、1出, 即321,85-
22、64,例2、一个栈的输入序列是12345,若在入栈的过程中允许出栈,则栈的输出序列43512可能实现吗?12345的输出呢?, 43512不可能实现 主要是其中的12顺序不能实现 12345的输出可以实现 每压入一数便立即弹出即可,85-65,例3、设依次进入一个栈的元素序列为c,a,b,d,则可得到出栈的元素序列是: )a,b,c,d )c,d,a,b )b,c,d,a )a,c,d,b,A)、D)可以, B)、C)不行。,讨论:有无通用的判别原则? 若输入的序列是 ,PjPkPi (PjPkPi) ,一定不存在这样的输出序列 ,PiPjPk ,答:,即对于输入序列1,2,3,不存在输出序列
23、3,1,2,有!,85-66,栈(Stack),栈的基本运算 初始化 inistack(s) 进栈 push(s,x) 出栈 pop(s) 读栈顶元素 gettop(s),85-67,顺序存储的栈,顺序栈 采用顺序存储结构的栈 组成 一个一维数组和一个记录栈顶位置的变量(top,栈顶指针)组成,85-68,栈的几种状态,(a) inistack(sq),(b) push(sq,A),(c) push(sq,B) push(sq,C),(d) pop(sq),(e) push(sq,D) push(sq,F) push(sq,E) push(sq,G),(a)栈空,若作pop,则下溢 (e)栈满
24、,若作push,则上溢,85-69,A,A,B,C,D,E,A,B,栈操作图示,A进栈,B C D E 进栈,E D C 出栈,C,D,E,入栈与出栈,栈的特征:后进先出,85-70,栈初始化,4 3 2 1 0,top = -1,栈顶指针赋初值 -1,顺序栈的基本运算,核心语句,85-71,入栈,4 3 2 1 0,top = 1,算法步骤: 1.判别栈满否 若满,则显示栈溢出信息,停止执行; 否则,执行下一步 2.栈顶指针top上移(加1) 3.在top所指的位置插入元素x,顺序栈的基本运算,85-72,出栈,4 3 2 1 0,4 3 2 1 0,top = 1,top = 0,顺序栈的
25、基本运算,算法步骤: 1.判别栈是否为空 若空,则显示栈下溢信息,停止执行; 否则,执行下一步 2.栈顶指针top下移(减1),85-73,取栈顶元素,4 3 2 1 0,4 3 2 1 0,top = 1,top = 1,顺序栈的基本运算,算法步骤: 1.判别栈是否为空 若空,则显示栈下溢信息,停止执行; 否则,执行下一步 2.栈顶元素送入x,x = 15,85-74,链接存储的栈,链栈 采用链接存储结构的栈 一个链栈由它的栈顶指针(top)唯一确定,栈空 top=NULL 不会发生栈满,85-75,队 列,定义 插入限定在表的某一端进行,删除限定在表另一端进行的线性表 术语 队尾:允许插入
26、的一端 队头:允许删除的一端,特征:先进先出,例如:食堂买饭,85-76,队 列,队列的三个要素 存放队列元素的存储空间 队头指针 队尾指针 按存储方式分 顺序 链接,85-77,队 列,队列的基本运算 取队头元素之值getfront(q, x) 取出队列q的队头元素置入x,由x传出 入队addq(q, x) 在队列q的队尾插入元素x 出队delq(q) 删除队列q的队头元素 队列初始化initqueue(q) 建立一个空队列q,85-78,顺序存储的队列,顺序队列 采用顺序存储结构的队列若用一维数组qm存储队列中的数据元素,则队列所允许的最大容量为m 队头指针front 指向队头元素的前一个
27、位置 队尾指针rear 指向队尾元素的所在位置 假溢出 队列中还有空间可利用,但rear+1=m,4 3 2 1 0,rear,front,85-79,A,B,C,D,E,A,B,队列操作图示,初始状态 空队列,A B C D E入队,A B 出队,C,D,E,入队与出队,队列的特征:先进先出,再入队,将会假溢出,rear在变,front在变,85-80,队列的初始化,4 3 2 1 0,rear,front,队头指针和队尾指针均赋初值-1,顺序队列的基本运算,85-81,入队,4 3 2 1 0,4 3 2 1 0,front,rear,rear,front,顺序队列的基本运算,算法步骤:
28、1.判别队列满否 若满,则显示出错信息,停止执行; 否则,执行下一步 2.队尾指针加1 3.将元素x插入到队尾,85-82,出队,4 3 2 1 0,4 3 2 1 0,front,rear,rear,front,顺序队列的基本运算,算法步骤: 1.判别队列是否为空 若空,则显示出错信息,停止执行; 否则,执行下一步 2.队头指针加1,85-83,取队头元素,4 3 2 1 0,4 3 2 1 0,front,rear,rear,front,算法步骤: 1.判别队列是否为空 若空,则显示出错信息,停止执行; 否则,执行下一步 2.将对头元素置入x,顺序队列的基本运算,85-84,用一个带头结点
29、的单链表作为存储结构。根据队列的FIFO(First in First out )原则,它需要一个头指针和一个尾指针。其结点结构和前面的单链表相同。,图中front和rear是两个独立的指针变量,从结构性上考虑,通常把二者封装在一个结构中。,链式存储的队列(链队列),85-85,本 章 小 结,线性表、栈、队列的异同点: 相同点:逻辑结构相同,都是线性的;都可以用顺序存储或链表存储;栈和队列是两种特殊的线性表,即受限的线性表(只是对插入、删除运算加以限制)。, 运算规则不同: 线性表为随机存取; 而栈是只允许在一端进行插入和删除运算,因而是后进先出表LIFO; 队列是只允许在一端进行插入、另一端进行删除运算,因而是先进先出表FIFO。, 用途不同,线性表比较通用;堆栈用于函数调用、递归和简化设计等;队列用于离散事件模拟、操作系统作业调度和简化设计等。,不同点:,第2章结束,