收藏 分享(赏)

第01章概论.ppt

上传人:kpmy5893 文档编号:7183430 上传时间:2019-05-09 格式:PPT 页数:116 大小:806KB
下载 相关 举报
第01章概论.ppt_第1页
第1页 / 共116页
第01章概论.ppt_第2页
第2页 / 共116页
第01章概论.ppt_第3页
第3页 / 共116页
第01章概论.ppt_第4页
第4页 / 共116页
第01章概论.ppt_第5页
第5页 / 共116页
点击查看更多>>
资源描述

1、数据结构,第1章 概论,1.1 数据结构 1.2 数据类型和抽象数据类型 1.3 算法和算法分析,1.1数据结构,一.为什么要学习数据结构,1. 计算机所处理的数据已不再是单纯的数值数据,而更多的是非数值数据。2.需要处理的数据并不是杂乱无章的,它们有一定内在的联系。,某电信公司的市话用户信息表格如下图所示:,每一行称为一个结点,1.数据:计算机的处理对象 2.数据元素(结点):数据的基本单位.初等类型组合类型 3.数据结构(1) 数据的逻辑结构(2) 数据的存储结构 (3) 数据的运算集合数据结构就是指按一定的逻辑结构组成的一批数据,使用某种存储结构将这批数据存储于计算机中,并在这些数据上定

2、义了一个运算集合。,二.基本概念,三.数据的逻辑结构,1.定义 :数据的逻辑结构是数据和数据之间所存在的逻辑关系,它可以用一个二元组 B=(K,R) 来表示,其中K是数据、即结点的有限集合;R是集合K上关系的有限集合,这里的关系是从集合K到集合K的关系,这里一般只涉及到一个关系的逻辑结构。,例如,有5个人,分别记为a,b,c,d ,e,其中a是b的父亲,b是c的父亲,c是d的父亲,d是e的父亲,如果只讨论他们之间所存在的父子关系,则可以用下面的二元组形式化地予以表达。B=(K,R)其中:K=a,b,c,d,eR=rr=, ,逻辑结构的图形表示方式,对K中的每个结点ki用一个方框表示,而结点之间

3、的关系用带箭头的线段表示,这5人之间的逻辑结构用图形的方式表达如下图 所示。,若kiK,kjR, r,则称ki是kj的相对于关系r的前驱结点,kj是ki的相对于关系r的后继结点,因为一般只讨论具有一种关系的逻辑结构,即R=r,所以简称ki是kj前驱,kj是ki的后继。如果某个结点没有前驱结点,称之为开始结点;如果某个结点没有后继结点,称之为终端结点;既不是开始结点也不是终端结点的结点称为内部结点。,2.数据的逻辑结构的分类(4种):(1)集合(2)线性结构(3)树形结构(4)图形结构,四.数据的存储结构,1.定义:数据在计算机中的存储方式称为数据的存储结构。,2.数据的存储结构分类(4种),(

4、1) 顺序存储顺序存储通常用于存储具有线性结构的数据。将逻辑上相邻的结点存储在连续存储区域M的相邻的存储单元中,使得逻辑相邻的结点一定是物理位置相邻。,例:对于一个数据结构B=(K,R) 其中K=k1,k2,k3,k4,k5,k6,k7,k8,k9R=r r=, 它的顺序存储方式如图所示,(2) 链式存储链式存储方式是给每个结点附加一个指针段,一个结点的指针所指的是该结点的后继的存储地址,因为一个结点可能有多个后继,所以指针段可以是一个指针,也可以是多个指针。,例,数据的逻辑结构B=(K,R)其中 K=k1,k2,k3,k4,k5 R=rR=, 这是一个线性结构,它的链式存储如图所示。,(4)

5、 散列存储散列存储的思想是构造一个从集合K到存储区域M的一个函数h,该函数的定义域为K,值域为M,K中的每个结点ki在计算机中的存储地址由h(ki)确定。,五.数据的运算集合,一般而言,数据的运算包括插入、删除、检索、输出、排序等。 插入:在一个结构中增加一个新的结点。 删除:在一个结构删除一个结点。 检索:在一个结构中查找满足条件的结点。 输出:将一个结构中所有结点的值打印、输出。 排序:将一个结构中所有结点按某种顺序重新排列。,一.数据的抽象经历了三个发展阶段:,1.2数据类型和抽象数据类型,从无类型的二进制数到基本数据类型的产生,从基本数据类型到用户自定义类型的产生,从用户自定义类型到抽

6、象数据类型的出现,二.数据类型,数据类型(或简称类型)反映了数据的取值范围以及对这类数据可以施加的运算。,三.抽象数据类型,抽象数据类型是与表示无关的数据类型,是一个数据模型及定义在该模型上的一组运算。对一个抽象数据类型进行定义时,必须给出它的名字及各运算的运算符名,即函数名,并且规定这些函数的参数性质。一旦定义了一个抽象数据类型及具体实现,程序设计中就可以像使用基本数据类型那样,十分方便地使用抽象数据类型。,四.抽象数据类型的描述和实现,用面向对象的程序设计语言”类”来实现,抽象数据类型描述的一般形式如下: ADT 抽象数据类型名称 数据对象:数据关系:操作集合:操作名1:操作名n: ADT

7、抽象数据类型名称,1.3 算法和算法分析,一.算法,1.定义:求解问题方法和步骤.,2算法具有五个基本特征: 有穷性,算法的执行必须在有限步内结束。 确定性,算法的每一个步骤必须是确定的无二义性的。 输入, 算法可以有0个或多个输入。 输出, 算法一定有输出结果 可行性,算法中的运算都必须是可以实现的。,二.算法的时间和空间复杂性,1.用途:评价一个算法的优劣. 2.算法的时间复杂性:采用算法执行过程中其基本操作的执行次数,采用数量级的形式来表示. T(n)=O(f(n),下面的表格给出了一些具体函数的O()的表示,如图所示。,例1.(a) +x; s=0; +x 的频度为1(b) for (

8、i=1; i=n; +i)+x; s+=x; +x的频度为n(c) for (j=1;j=n;+j)for (k=1;k=n;+k) +x; s+=x; +x的频度为n2,例2. i=1; while(i=n)i=i*3;解:T(n)=O(log3n),算法的时间复杂性不仅和问题的规模大小有关,还与问题数据的初始状态有关。这样就有了算法在最好、最坏以及在平均状态下的时间复杂性的概念。 算法在最好情况下的时间复杂性是指算法计算量的最小值。 算法在最坏情况下的时间复杂性是指算法计算量的最大值。 算法的平均情况下的时间复杂性是指算法在所有可能的情况下的计算量经过加权计算出的平均值。,3.算法的时间复

9、杂度该算法所耗费的存储空间,用数量级的形式表示. S(n)=O(f(n),2.1 线性表 2.2 顺序表 2.3 栈 2.4 队列,第2章 线性表及其顺序存储,2.1线性表,线性表是一个线性结构,它是一个含有n0个结点的有限序列,对于其中的结点,有且仅有一个开始结点没有前驱但有一个后继结点,有且仅有一个终端结点没有后继但有一个前驱结点,其它的结点都有且仅有一个前驱和一个后继结点。一般地,一个线性表可以表示成一个线性序列:k1,k2,kn,其中k1是开始结点,kn是终端结点。,一.顺序表的定义,线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存

10、储单元中。,存储结构要体现数据的逻辑结构,顺序表的存储结构中,内存中物理地址相邻的结点一定具有顺序表中的逻辑关系。,2.2顺序表,顺序表的存储结构如下图所示:,如顺序表的每个结点占用len个内存单元,用location (ki)表示顺序表中第i个结点ki所占内存空间的第1个单元的地址。则有如下的关系location (ki+1) = location (ki) +lenlocation (ki) = location(k1) + (i-1)*len,二.顺序表的实现,用C语言中的数组存储顺序表。C语言中数组的下标是从0开始的,为了方便,将顺序表中各结点的序号改为和对应数组元素的下标序号一致。这

11、样,一个长度为n的顺序表可以表示为: k0, k1, k2, , kn-1,顺序表的存储结构的C语言描述如下:#define MAXSIZE 100typedef int datatype;typedef structdatatype aMAXSIZE;int size;sequence_list;,顺序表的几个基本操作的具体实现 :,1.顺序表的初始化-置空表,void init_sequence_list(sequence_list *slt)slt-size=0; 算法2.1顺序表的初始化-置空表,2.在顺序表后部进行插入操作void insert_sequence_list(seque

12、nce_list *slt,datatype x)if(slt-size=MAXSIZE)printf(“顺序表是满的!“);exit(1); slt-aslt-size=x; slt-size=slt-size+1; 算法2.2在顺序表后部进行插入操作,3. 打印顺序表的各结点值,void print_sequence_list(sequence_list slt)int i;if(slt.size=0) printf(“n顺序表是空的!“);elsefor(i=0;islt.size;i+) printf(“%5d“,slt.ai); 算法2.3打印顺序表的各结点值,3.判断顺序表是否为空

13、 /*空返回0,否则1*/,int is_empty_sequence_list(sequence_list slt)if(slt.size=0 )return 0;elsereturn 1; 算法2.4判断顺序表是否为空,4. 查找顺序表中值为x的结点位置,int find_num_sequence_list(sequence_list slt,datatype x)int i=0;while(slt.ai!=x 算法2.5查找顺序表中值为x的结点位置,5. 取得顺序表中第i个结点的值,datatype get_data_pos(sequence_list slt,int i)if(i=sl

14、t.size)printf(“n指定位置的结点不存在!“);exit(1);return slt.ai; 算法2.6 取得顺序表中第i个结点的值,6.顺序表的插入运算 将一个值为x的结点插入到顺序表的第i个位置0in,即将x插入到ki-1和ki之间,如果i=n,则表示插入到表的最后,一般地可表示为:插入前:k0, k1, , ki-1, ki, , kn-1插入后:k0, k1, , ki-1,x, ki, , kn-1,插入过程的图示见下图:,/*/ /* 在顺序表的position位置插入值为x的结点 */ /* 文件名seqlinse.c, 函数名insert_pos_sequence_

15、list() */ /*/,void insert_pos_sequence_list(sequence_list *slt,int position, datatype x) int i;if(slt-size=MAXSIZE)printf(“n顺序表是满的!没法插入!“);exit(1);if(positionslt-size)printf(“n指定的插入位置不存在!“);exit(1);for(i=slt-size;iposition;i-) slt-ai=slt-ai-1;slt-aposition=x;slt-size+; 算法2.7在顺序表的position位置插入值为x的结点,算

16、法2.7中,所花费的时间主要是元素后移操作,对于在第i个位置上插入一个新的元素,需要移动(n-i)个元素,设在第i个位置上插入一个元素的概率为pi,且在任意一个位置上插入元素的概率相等,即p0=p1=p2=pn=1/n+1,则在一个长度为n的顺序表中插入一个元素所需的平均移动次数为:,即在长度为n的顺序表中插入一个元素平均需要移动表中的一半元素。该算法的时间复杂度为O(n)。,7. 顺序表的删除操作 是指删除顺序表中的第i个结点,0in-1,一般地可表示为:删除前:k0, k1, , ki-1, ki, ki+1, , kn-1删除后:k0, k1, , ki-1, ki+1, , kn-1,

17、删除过程的图示见下图 :,删除操作的具体实现见算法2.8,/*/ /* 删除顺序表中第position位置的结点 */ /* 文件名seqldele.c, 函数名delete_pos_sequence_list() */ /*/,void delete_pos_sequence_list(sequence_list *slt,int position)int i;if(slt-size=0)printf(“n顺序表是空的!“);exit(1);if(position=slt-size)printf(“n指定的删除位置不存在!“);exit(1);for(i=position;isize-1;i

18、-) slt-ai=slt-ai+1;slt-size-; 算法2.8删除顺序表中第position位置的结点,要删除顺序表中的第i个结点,则需要称动(n-i-1)个元素,设删除表中第i个结点的概率为qi,且在表中每一个位置删除的概率相等,即: q0=q1=qn-1=1/n则在一个长度为n的顺序表中删除一个结点的平均移动次数为:,这表明,在一个长为n的顺序表中删除一个元素平均需要移动表中大约一半的元素。该算法的时间复杂度为O(n)。,思考题: 1.在值为x的前插入一个值y 2.删除值为x的点,2.3 栈,一.栈 的定义,栈是一种特殊的线性表,对于这种线性表规定它的插入运算和删除运算均在线性表的

19、同一端进行,进行插入和删除的那一端称为栈顶,另一端称为栈底。栈的插入操作和删除操作也分别简称进栈和出栈。,如果栈中有n个结点k0, k1, k2, , kn-1,k0为栈底,kn-1是栈顶,则栈中结点的进栈顺序为k0, k1, k2, , kn-1,而出栈的顺序为kn-1, kn-2, , k1, k0。如图所示。,栈具有后进先出或先进后出(FILO,First In Last Out)的性质,二.顺序栈及其实现,栈的实现方式一般有两种:顺序存储和链式存储。,1.顺序栈: 栈的顺序存储方式就是在顺序表的基础上对插入和删除操作限制它们在顺序表的同一端进行。设一个足够大的一维数组存储栈,数组中下标

20、为0的元素就是栈底,对于栈顶,设一个整数top指示它。设定top所指的位置是下一个将要插入的结点的存储位置,这样,当top=0时就表示是一个空的栈。一个栈的几种状态以及在这些状态下栈顶指针top和栈中结点的关系如下图所示。,栈的顺序存储结构的C语言描述如下:#define MAXSIZE 100typedef int datatype;typedef structdatatype aMAXSIZE;int top;sequence_stack;,2.顺序存储栈的几个基本操作的具体实现,(1) 栈(顺序存储)初始化void init_sequence_stack(sequence_stack *

21、st)st-top=0; 算法2.9栈(顺序存储)初始化,(2) 判断栈(顺序存储)是否为空 /*空为1,否则0*/int is_empty_stack(sequence_stack st)if(st.top=0)return 1;elsereturn 0; 算法2.10判断栈(顺序存储)是否为空,(3) 取得栈顶(顺序存储)结点值datatype get_top(sequence_stack st)if (st-top=0)printf(“n栈是空的!”);elsereturn st.ast.top-1; 算法2.11取得栈顶(顺序存储)结点值,栈(顺序存储)的插入操作 void push(

22、sequence_stack *st,datatype x)if(st-top=MAXSIZE)printf(“nThe sequence stack is full!“);exit(1);st-ast-top=x;st-top+; 算法2.12 栈(顺序存储)的插入操作,(5)栈(顺序存储)的删除操作 void pop(sequence_stack *st)if(st-top=0)printf(“nThe sequence stack is empty!“);exit(1);st-top-; 算法2.13栈(顺序存储)的删除操作,三.栈的应用之一-括号匹配,设一个表达式中可以包含三种括号:小

23、括号、中括号和大括号,各种括号之间允许任意嵌套,如小括号内可以嵌套中括号、大括号,但是不能交叉。举例如下: () 正确的 () 正确的 () 正确的 () 不正确的() 不正确的 在自左向右扫描一个表达式时,后遇到的开括号比先遇到的开括号更加期待有一个闭括号与之匹配。,算法思想: (1)从左向右逐个扫描表达式,当字符不是字符串结束标志时:如果是左括号,放入栈中;如果是右括号,取栈顶元素比较:若栈不空且匹配, 删栈顶后继续扫描;否则(不匹配或空),返回0; (2)若是字符串结束标志:栈空,则匹配,返回1;否则,返回0; 判断表达式括号是否匹配的具体实现见算法2.14:,int match_kuo

24、hao(char c) /*匹配返回1,否则0*/int i=0;sequence_stack s;s.top=0; while(ci!=#) /*#是字符串结束标志*/switch(ci)case :case : case (: s.atop=ci; s.top+; break;,case : if(s.top!=0/*栈空则匹配,否则不匹配*/ 算法2.14判断表达式括号是否匹配,四.栈的应用之二-算术表达式求值,2.4 队列,一. 队列,队列是一种特殊的线性表,它的特殊性在于队列的插入和删除操作分别在表的两端进行。插入的那一端称为队尾,删除的那一端称为队首。队列的插入操作和删除操作也分别

25、简称进队和出队。,对于一个队列: k0, k1, k2, , kn-1 如果k0那端是队首,kn-1那端是队尾,则k0是这些结点中最先插入的结点,若要做删除操作,k0将首先被删除,所以说,队列是具有“先进先出”(FIFO,First In First Out)特点的线性结构。,二.顺序队列及其实现,队列的顺序存储在C语言中可以用一维数组表示,为了标识队首和队尾,需要附设两个整数front和rear,front指示的是队列中最前面,即队首结点在数组中元素的下标,rear指示的是队尾结点在数组中元素的下标的下一个位置,也就是说rear指示的是即将插入的结点在数组中的下标。,队列的几种状态 :,队列

26、的顺序存储结构的C语言描述如下: #define MAXSIZE 100typedef int datatype;typedef structdatatype aMAXSIZE;int front;int rear;sequence_queue;,顺序存储队列的几个基本操作的具体实现 :,1.队列(顺序存储)初始化void init_sequence_queue(sequence_queue *sq)sq-front=sq-rear=0; 算法2.20队列(顺序存储)初始化,2.判断队列(顺序存储)是否为空 int is_empty_sequence_queue(sequence_queue

27、sq)if(sq.front=sq.rear)return 1;else return 0; 算法2.21判断队列(顺序存储)是否为空,打印队列(顺序存储)的结点值void print_sequence_queue(sequence_queue sq)int i;if(sq.rear=sq.front)printf(“n顺序队列是空的!“);elsefor(i=sq.front;isq.rear;i+) printf(“%5d“,sq.ai); 算法2.22打印队列(顺序存储)的结点值,4.队列(顺序存储)的插入操作void insert_sequence_queue(sequence_que

28、ue *sq,datatype x)int i;if(sq-rear=MAXSIZE)printf(“n顺序循环队列是满的!“);exit(1);sq-asq-rear=x;sq-rear=sq-rear+1; 算法2.24队列(顺序存储)的插入操作,队列(顺序存储)的删除操作 void delete_sequence_queue(sequence_queue *sq)if(sq-front=sq-rear)printf(“n顺序队列是空的!不能做删除操作!“); exit(1);sq-front+; 算法2.25队列(顺序存储)的删除操作,在队列的几种状态图的(e)状态中,队列是一种队满状态

29、,将不能再插入新的结点,而实际上数组的前部还有许多空的位置。为了充分地利用空间,可以将队列看作一个循环队列,在数组的前部继续作插入运算,这就是循环队列。,下标,三.顺序循环队列及其实现,为了有效利用空间,将顺序存储的队列想象为一个环状,把数组中的最前和最后两个元素看作是相邻的,这就是循环队列。,循环队列的几种状态表示 :,插入:sq-rear=(sq-rear+1)%MAXSIZE; 删除:sq-front=(sq-front+1)%MAXSIZE;,在(b)状态中,如果再插入一个新的结点,则数组空间将被全部占用,队列已满,且rear=front,而在(c)状态中,若删除一个结点队列成为空队列

30、,此时也有rear=front,这就是说循环队列满与空的条件都是rear=front。,解决方法是牺牲一个数组元素的空间,即若数组的大小是MAXSIZE,则该数组所表示的循环队列最多允许存储MAXSIZE-1个结点。这样,循环队列满的条件是 (rear+1)%MAXSIZE=front 循环队列空的条件是 rear=front,循环队列的插入操作的实现 :,void insert_sequence_cqueue(sequence_queue *sq,datatype x)int i;if(sq-rear+1)%MAXSIZE=sq-front)printf(“n顺序循环队列是满的!无法进行插入

31、操作!“);exit(1);sq-asq-rear=x;sq-rear=(sq-rear+1)%MAXSIZE; 算法2.27循环队列(顺序存储)的插入操作,循环队列(顺序存储)的删除操作 void delete_sequence_cqueue(sequence_queue *sq)if(sq-front=sq-rear)printf(“n循环队列是空的!无法进行删除!“); exit(1);sq-front=(sq-front+1)%MAXSIZE; 算法2.28循环队列(顺序存储)的删除操作,总结:,第3章 线性表的链式存储,3.1 链式存储 3.2 单链表 3.3 带头结点的单链表 3.

32、4 循环单链表 3.5 双链表 3.6 链式栈 3.7 链式队列,3.1链式存储,在链式存储方式下,实现中除存放一个结点的信息外,还需附设指针,用指针体现结点之间的逻辑关系。如果一个结点有多个后继或多个前驱,那么可以附设相应个数的指针,一个结点附设的指针指向的是这个结点的某个前驱或后继。,线性结构中,每个结点最多只有一个前驱和一个后继,设定更关心它的后继,在存储时除了存放该结点的信息外,只要附设一个指针,该指针指向它的后继结点的存放位置。每个结点的存储形式是:,例,数据的逻辑结构B=(K,R) 其中 K=k1,k2,k3,k4,k5 R=rR=, 是一个线性结构,它的链式存储如图所示,为了清晰

33、,左图可以更简洁地用下图表示。,3.2 单链表,一.定义:单链表是线性表链式存储的一种形式,其中的结点一般含有两个域,一个是存放数据信息的info域,另一个是指向该结点的后继结点的存放地址的指针域next。一个单链表必须有一个首指针指向单链表中的第一个结点。,二.单链表的实现,单链表结构的C语言描述如下:typedef int datatype;typedef struct link_nodedatatype info;struct link_node *next;node;,单链表的插入过程见下图所示 :,删除操作见下图所示:,链式存储的插入和删除操作比顺序存储方便,但不能随机访问某个结点!

34、,3.3带头结点单链表,一.带头结点单链表,二.带头结点单链表的实现,head指示的是头结点,它不是存储数据结构中的实际结点,第一个实际的结点是head-next指示的。,1.建立一个空的带头结点单链表 node *init_hlink_list()node *head;head=(node*)malloc(sizeof(node);head-next=NULL;return head; 算法3.10建立一个空的带头结点单链表,2.输出带头结点单链表中各个结点的值void print_hlink_list(node *head)node *p;p=head-nextif(p=NULL) pri

35、ntf(“n带头结点单链表是空的!“);elseprintf(“n带头结点的单链表各个结点的值为:n“);while(p!=NULL) printf(“%5d“,p-info);p=p-next; 算法3.11输出带头结点单链表中各个结点的值,3.在带头结点单链表中查找一个值为x的结点 node *find_num_hlink_list(node *head,datatype x)node *p;p=head-nextwhile(p!=NULL 算法3.12在带头结点单链表中查找一个值为x的结点,4.带头结点单链表中查找第i个结点 node *find_pos_hlink_list(node

36、*head,int i)int j=0;node *p=head;if(inext;j+;return p; /*返回结果,i=0时,p指示的是头结点*/ 算法3.13在带头结点单链表中查找第i个结点,带头结点单链表的插入过程见图3.7 :,5.在带头结点单链表中值为y的结点后插入一个值为x的结点,void insert_x_after_y(node *head,datatype x,datatype y) node *p,*q ;q=head-next;while(q!=NULL /*插入*/ ,6.在第i个结点后插入一个值为x的新结点,void insert_x_after_i(node

37、*head,datatype x, int i) node *q=head,*p ; int j=0;if(inext; j+; /*查找*/ if(q=NULL) printf(“n没有找到!“); exit(1); /*找不到退出*/p=(node*)malloc(sizeof(node); p-info=x; /*动态生成结点*/ p-next=q-next; q-next=p; /*插入*/ ,思考:,1。在值为y的结点前面插入结点x 2。创建一个带头结点的单链表,带头结点单链表的删除过程见图3.8。,7.在带头结点单链表中删除一个值为x的结点 void delete_num_hlin

38、k_list(node *head,datatype x)node *pre=head,*q; /*pre指向头结点*/q=head-next; /*q指向第一个实际结点*/while(q!=NULL /*释放空间*/ 算法3.17在带头结点单链表中删除一个值为x的结点,3.4 循环单链表,一。定义 单链表从表中的某个结点开始,只能访问到这个结点及其后面的结点,不能访问到它前面的结点,除非再从首指针指示的结点开始访问。希望从表中的任意一个结点开始,都能访问到表中的所有其它结点,设置表中最后一个结点的指针域指向表中的第一个结点,这种链表称为循环单链表。,二.循环单链表的实现,对于一个循环单链表,

39、若首指针为head,表中的某个结点p是最后一个结点的特征应该是p-next=head。,3.5 双链表,一. 双链表的定义,链表中每个结点有一个指针域指向它的后继结点,再增设一个指针域指向它的前驱结点,这就构成了双链表。,双链表的结点包括三个域,一个是存放数据信息的info域,另外两个是指针域,这里用llink和rlink表示,llink指向它的前驱结点,rlink指向它的后继结点。,双链表的一般情形如图所示:,3.5.2 双链表的实现,双链表结构的C语言描述如下: typedef int datatype;typedef struct dlink_nodedatatype info;stru

40、ct dlink_node *llink,*rlink;dnode;,1.双链表插入过程如下图所示:,2.双链表删除操作图示 :,3.6 链式栈,一. 链式栈,栈的链式存储称为链式栈。链式栈就是一个特殊的单链表,对于这特殊的单链表,它的插入和删除规定在单链表的同一端进行。链式栈的栈顶指针一般用top表示,链式栈如下图所示。,二. 链式栈的实现,1.取得链式栈的栈顶结点值 datatype get_top(node *top)if(top=NULL) printf(“n链式栈是空的!“);exit(1);return(top-info); .2.判断栈是否为空 int empty_link_st

41、ack(node *top)if(top=NULL) return 0;else return 1;,3. 输出链式栈中各个结点的值void print_link_stack(node *top)node *p;p=top;if(p=NULL) printf(“n链式栈是空的!“);exit(1);while(p!=NULL) printf(“%5d“,p-info);p=p-next; 算法3.41 输出链式栈中各个结点的值,4.向链式栈中插入一个值为x的结点 node *push_link_stack(node *top,datatype x)node *p;p=(node*)malloc

42、(sizeof(node); p-info=x; /*动态生成结点*/p-next=top; /*插入(1)*/top=p; /*插入(2)*/return top; 算法3.42向链式栈中插入一个值为x的结点,5.删除链式栈的栈顶结点 node *pop_link_stack(node *top)node *q;if(top=NULL) printf(“n链式栈是空的!“); return NULL;q=top; /*指向被删除的结点(1)*/top=top-next; /*删除栈顶结点(2)*/free(q);return top; 算法3.43 删除链式栈的栈顶结点,3.7 链式队列,一

43、.链式队列,队列的链式存储称为链式队列。链式队列就是一个特殊的单链表,对于这种特殊的单链表,它的插入和删除规定在单链表的不同端进行。链式队列的队首和队尾指针分别用front和rear表示,链式队列如下图所示。,二.链式队列的实现:,链式队列的结点定义和单链表一样。队列必须有队首和队尾指针,因此增加定义一个结构类型,其中的两个域分别为队首和队尾指针。其定义如下: typedef structnode *front,*rear; /*定义队首与队尾指针*/queue;,1.建立一个空的链式队列 queue *init_link_queue() /*建立一个空的链式队列*/queue *qu;qu=

44、(queue*)malloc(sizeof(queue); /*分配空间*/qu-front=NULL; /*队首指针设置为空*/qu-rear=NULL; /*队尾指针设置为空*/return qu; 算法3.44建立一个空的链式队列,2. 取得链式队列的队首结点值datatype get_first(queue qu)if(qu.front=NULL) printf(“n链式队列是空的!“);exit(1);return(qu.front-info); 算法3.47取得链式队列的队首结点值,链式队列的插入过程图示见下图:,3. 向链式队列中插入一个值为x的结点 void insert_li

45、nk_queue(queue *qu,datatype x) node *p;p=(node*)malloc(sizeof(node); p-info=x; p-next=NULL; /*生成结点*/if (qu-front=NULL) qu-front=qu-rear=p; /*空时插入*/ else qu-rear-next=p; qu-rear=p; /*不空时插入*/ 算法3.48向链式队列中插入一个值为x的结点,链式队列的删除过程图示见下图:,4.删除链式队列中队首结点 void delete_link_queue(queue *qu) node *q;if(qu-front=NULL) printf(“空”);exit(1); /*判空*/q=qu-front; /*q指向队首结点(1)*/qu-front=q-next; /*队首指针指向下一个结点(2)*/free(q); /*释放原队首结点空间*/ 算法3.49删除链式队列中队首结点,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报