Upload
wiley
View
157
Download
5
Embed Size (px)
DESCRIPTION
第 3 单元 线性数据结构(二). 1.3 栈和队列 (P32~P46) 1.4 串和数组 (P47~P55). 1.3 栈和队列 一、栈的逻辑结构和运算. 1. 堆栈 (Stack) 概念 1) 只允许在同一端进行插入和删除操作的特殊线性表。 2) 允许进行插入和删除操作的一端称为栈顶,另一端为栈底; 3) 栈底固定,而栈顶浮动; 4) 特点:后进先出( LIFO )。 5) 空栈 : 元素个数为零的栈。. 2. 栈的基本运算. Setnull(Stack) 置栈为空; - PowerPoint PPT Presentation
Citation preview
1/53
第 3 单元 线性数据结构(二)
1.3 栈和队列 (P32~P46) 1.4 串和数组 (P47~P55)
2/53
1.3 栈和队列一、栈的逻辑结构和运算
1. 堆栈 (Stack) 概念– 1) 只允许在同一端进行插入和删除操作的特殊线性表。
– 2) 允许进行插入和删除操作的一端称为栈顶,另一端为栈底;
– 3) 栈底固定,而栈顶浮动;– 4) 特点:后进先出( LIFO )。– 5) 空栈 : 元素个数为零的栈。
3/53
2. 栈的基本运算
Setnull(Stack) 置栈为空; Empty(Stack) 判断栈是否为空; Push(Stack,x) 进栈 --- 在栈顶插入元素
x Pop(Stack) 出栈 --- 删除栈顶元素; Gettop(Stack) 取栈顶元素 顺序栈 : 采用顺序存储结构的栈 链栈 : 采用链式存储结构的栈
4/53
出栈序列 操作序列 1 2 3 s x s x s x 1 3 2 s x s s x x 2 1 3 s s x x s x 2 3 1 s s x s x x 3 2 1 s s s x x x
例 1-10
有三个元素的进栈序列是 1 , 2 , 3 。写出可能的出栈序列。
5/53
3. 与堆栈操作有关的术语
1) 栈顶指针 TOP–用来指出栈顶元素所在的位置
2) 栈空条件: top = -13) 栈满条件: top = MAXSIZE-14) 上溢 – 栈满后再进行入栈操作 , 产生上溢。
5) 下溢 –栈已空 , 再执行出栈操作,产生下溢。
6/53
二、栈的存储结构之一 : 顺序栈
1) 采用顺序存储结构的栈2) 实现 : 使用一维数组3) 栈顶位置随进栈和出栈而变化。4) C 语言描述:– #define MAXSIZE n– int stack[MAXSIZE];– int top = -1; /* 下标从 0 开始 */
7/53
栈操作举例
a1 a2 …… ana1 a2 …… an
栈底 栈顶MAXSIZE-1
TOP
1.
top=-1
A B CA B C2.
( 空栈 ) top=2 (A 、 B 、 C 进栈)
A BA B3.
top=1 (C 出栈)
4. A B C D E F
top=MAXSIZE-1( 栈满)
8/53
算法 1-8 进栈算法
– step1 判断栈满否,– 若满,显示溢出信息,停止执行– 否则,执行 step 2 ; – Step2 栈顶指针 top 上移 ( 加 1) ;– Step3 在 top 所指的位置插入元素 x 。
9/53
算法 1-8 进栈算法程序
push ( int x ) { if ( top == MAXSIZE -1 ) { printf (“栈上溢! \n” ) ; exit ( 1 ) ; } else { top ++ ; /* 栈指针加
1 */ stack[top]=x ; /* 元素 x 进栈 */ } }
10/53
算法 1-9 出栈算法
– step1 判断栈是否为空;– 若空,输出下溢信息,并停止执行;
– 否则,执行 step2 ;– step2 弹出(删除)栈顶元素; – step3 栈顶指针 top 下移 ( 减 1) 。– step4 返回栈顶元素–
11/53
算法 1-9 出栈算法程序
pop ( ){ int x; if( top = = -1 ) { printf(“ 栈下溢 \n”); exit(1);} else { x = stack [top] ; top - - ;
} return x ; }
12/53
5) 两栈共享一个栈空间
–两栈共享:两个栈底分别设在两端,栈顶指针 top1 和 top2 相对中间位置移动,栈间分界线不定。
a.
b.
c.
top1 =0 top2=MAXSIZE-1
空栈
top1 top2
栈 1 、栈 2 均有元素
top1 top2
栈满
13/53
二、栈的存储结构之二 : 链栈
1. 顺序栈的问题– 1) 最多实现 2 个栈的共享– 2) 不能用于最大空间事先不知的情况
解决方法 : 链栈
14/53
链栈存储结构
2. 链栈存储结构的 C 语言描述:– struct snode– { int data;– struct snode *link; } ;– typedef struct snode SNODE ;– SNODE *top;
链栈空: top = NULL链栈满 : t = NULL /*t 为申请的结点 申请结点失败
15/53
链栈示意图
a1a1
a2a2
a3a3
NULL 栈底
top 栈顶
…...
ai
16/53
算法 1-10 进栈操作算法
step1 申请一个链栈结点 , 若 t=NULL, 则链满 ; 否则 , 执行 step2 ;step2 在 top 所指结点之前插入新结点 , 并将 top 指向新申请的结点 t 。
17/53
算法 1-10 进栈操作程序
push(int x) { SNODE *t; t=(SNODE * )malloc(sizeof(SNODE)); if (t = = NULL ) { printf(“ 栈已满 \n”); exit(1); } else { t->data = x; t->link = top;top= t; } }
18/53
算法 1-11 出栈操作算法
step1 若链栈空,输出栈溢出信息;
否则,执行 step 2 。 step2 删除 top 所指结点,并使 top 指向被删除结点的后继结点 step3 释放被删除结点的存储空间 step4 返回栈顶元素
19/53
算法 1-11 出栈操作程序
pop( ) { SNODE *p; int x; if ( top = = NULL ) { printf(“ 栈下溢 \n” ); exit
(1); } else { p=top; top=top->link; x = p ->data ; free(p) ; } return x; }
20/53
三、队列
1. 队列概念– 1) 只允许在表的一端进行删除操作,在表的另一端进行插入的特殊线性表。
– 2) 队尾 (rear) :进行插入操作的一端– 3) 队头 (front) :进行删除操作的一端– 4) 特点:先进先出( FIFO )。
a1 a2 … an
入队插入
出队删除
front rear
21/53
2 、队列的操作
Setnull(Queue) 清空队列Empty(Queue) 判断队列是否为空Addqueue(Queue,x) 入队 ( 插入 )Delqueue(Queue) 出队 ( 删除 )Frontqueue(Queue) 取队头元素
22/53
四、队列的顺序存储
1. 定义空队列 : 用一维数组– #define MAXSIZE n– int queue[MAXSIZE] ;– int front=-1, rear=-1;
front :队头指针 ; rear :队尾指针 ;–空队列: front = rear–满队列: rear = MAXSIZE-1
23/53
2. 入队出队操作
约定: front: 总是指向队头元素的前一个位置; rear: 总是指向队尾元素的位置结果: 对任何元素,操作都一样 出队 : 入队 : front = front + 1 ; rear=rear+1; x = queue [front] ; queue[rear]=x;
front rear
a1 a2 … an
24/53
举例:顺序队列的入队、出队操作
1 )空队列2 ) A 、 B 、 C 、 D 、 E 入队
3 ) A 、 B 、 C 出队
front rear
D E D E front rear
A B C D E A B C D E front rear
入队时, rear 在变
出队时, front 在变
25/53
4 ) F 、 G 、 H 入队
5 ) D 、 E 、 F 、 G 、 H 出队,出现假“溢出”
front
front rear
D E F G H D E F G H rear
26/53
3. 假溢出
假溢出–队列是空的情况下出现的溢出。
解决方法– 1) 整个队列左移 , 费时– 2) 队列的首尾相连 -- 循环队列
目的 –队列中真正没有空位置时,才产生溢出。
27/53
4 、循环队列
1. 出队 ( 队头指针移动 )– front=(front+1)%MAX
SIZE ;等价于: – if – (front+1>= MAXSIZE)– front = 0 ;– else– front=front+1;
2. 入队 ( 队尾指针移动 )rear=(rear+1)%MAXS
IZE ;等价于:
if (rear+1>=MAXSIZE)
rear = 0;
else
rear=rear+1;
28/53
循环队列队空、队满条件
约定 :–队头指针指示的–结点不用于存储–元素 , 只作标志–即保留一个节点
队空条件– front = rear ;
队满条件– front = (rear+1) % MAXSIZE
rear
front
0
1 32
MAXSIZE -1...
0
12
...
i
reari+1
front
...MAXSIZE -1
a1
a2
a3
ai
空
满
29/53
算法 1-12: 循环队列入队算法
step1 判别队列是否已满 ;step2 队尾指针后移一个位置 , 将新结点元素值存入当前结点单元。
程序 ( 略 )
30/53
算法 1-13 循环队列出队算法
step1 判别队列是否为空 ; 若空 , 则显示‘下溢’ ;
step2 队头指针后移一个位置。step3 返回队头元素
程序 ( 略 )
31/53
五 . 队列的链式存储结构
用带头结点的单链表作为队列的链式存储结构。
C 语言描述– struct qnode – { int data ;– struct qnode * next ; } ;– typedef struct qnode QNODE ;– QNODE *front , *rear ;
32/53
链队列的表示
链队列满 : T = = NULL 没有存储空间链队列空 : front = =rear 空队列 :
非空队列 :
front rear
NULLNULL
front rear NULLNULL...an
a2a1
33/53
算法 1-14 链队列的入队算法
step1 申请建立一个新结点 T;step2 判别 T 是否为 NULL; 若是 ,表示
队列已满 ;step3 若非空 , 将 T 插入链中 , 修改
rear 指针。
34/53
链队列的入队操作
addqueue(int x) { QNODE *t; t = (QNODE*)malloc(sizeof(QNODE)); if ( t = = NULL ) { printf(” 无可用空间 \n”);exit(1);} else { rear -> next = t; rear = t; t ->data = x; t ->next = NULL ; } }
35/53
链队列的出队操作
两种情况 :–队列长度为 1, 修改头结点指针域和队尾指针。
–队列长度大于 1, 只修改头结点指针域
an NULLan NULLfrontrearQueue
Queue
frontrear
NULLNULL an ^an ^
T
Queue
Queue
frontrear
rearfront
a1 a1 an NULLan NULL
a1a1
a2 a2 ...
a2 a2 ^ ^ ... an NULLan NULL
36/53
栈的应用 ---- 例 1: 递归过程
计算 5 的阶乘( 5!=5×4×3×2×1 )– { if ( n = = 1) return (1);– else return ( n * f(n-1));– }
f(2)
f(3)
f(4)
f(5)
top f(1)=1 2*f(1) f(2)=2*f(1)
3*f(2) f(3)=3*f(2)
4*f(3) f(4)=4*f(3)
5*f(4) f(5)=5*f(4)
37/53
栈的应用 ---- 例 2: 程序的嵌套调用
– main sub1 sub2 sub3
sub2
sub1main
top
38/53
1.4 串和数组
一 . 串及其运算1. 串的概念– 1) 定义 : 特殊的线性表 , 每个数据元素仅由单个字符组成 , 如 : A="very good"
– 2) 串的长度 : 串中的字符个数– 3) 空串 : 串长度为 0– 4) 空格串 : 组成串的元素都是空格– 5) 子串 : 串中任意个连续字符组成的序列– 6) 两个串的相等 :
39/53
2. 串的基本操作
LENGTH(S) 求串 S 的长度SUBSTR(S,start,len) 求 S 的子串CONCAT(S1,S2) – S2联接在 S1末尾
INDEX(S1,S2) –确定 S2 在 S1 中的位置
REPLACE ( S1 , S2 , S3 ) –用 S3替换串 S1 中所有与串 S2 相等且不重叠的子串
40/53
二 . 串的存储结构
1. 顺序存储结构 用连续存储单元存储串的字符序列 使用字编址方式时,设 1 字 4 个字节 , 则 : (1) 非紧缩存储 : 一个字的存储单元中只存放
1 个字符。 特点:存储密度低 ,浪费空间 (2) 紧缩存储 一个单元中存放 4 个字符; 特点:节省空间
– 访问时要花费分离时间
41/53
2. 链表存储结构
(1) 结点由数据域和指针域组成 图 1-38 (2) 指针域通常两个字节 若数据域占一个字节 : 有效存储密度 =1/3 若数据域占四个字节 : 有效存储密度 =4/6=2/3
42/53
3. 堆存储结构
–堆结构 : 一种动态存储结构,定义一个很大的连续空间和相应的指针结构。
–指针用来指示串在堆中的位置–例如, a=‘BEI’ , b=‘ JING’ , c=‘’ ,
d=‘SHANGHAI’ ;串名串长 起始地址
a 3 1
b 5 4 c 0 9
d 8 9
B E I J I N G S H
A N G H A I
43/53
三 . 数组
1 、数组的定义数组是有限个数组元素的集合数组中所有元素有相同的数据类型每个数组元素值可以用数组名和一组下标值唯一的确定;
44/53
2. 数组元素之间的关系
m 行 n 列二维数组可以看作是 m 个或 n 个一维数组 :– Amxn = ((a11a12…a1n),(a21a22…a2n),..– (am1am2…amn))
– 或 : a11 a12 a1n– a21 a22 a2n
Amxn = – am1 am2 amn
...... ... ...
45/53
3. 数组的操作
两种基本的操作:–给定下标,存取相应的数组元素;–给定下标,修改相应数组元素的值。
46/53
4. 数组的顺序存储结构
无论几维数组 , 在计算机中都是按一维数组来存放。
二维数组存放通常采用两种方式:–按行优先顺序–按列优先顺序
47/53
1) 按行优先顺序存储
按行优先将数组看作若干个行向量数组中的每个元素由元素的两个下标表达式唯一的确定。
地址计算公式:– LOC(aij)=LOC(a11)+(i-1)*n+(j-1))*L
L: 每个元素所占的存储单元
48/53
2)按列优先顺序存储
将数组看作若干个列向量。 数组中的每个元素由元素的两个下标表达式唯一的确定。
地址计算公式:– LOC(aij)=LOC(a11)+((j-1)*m+(i-1))*L
L: 每个元素所占的存储单元。
49/53
5.矩阵的压缩存储
压缩的含义:–相同值的多个元素占用一个存储单元;–零元素不分配存储单元。
(1) 特殊矩阵的压缩存储–特殊矩阵 : 值相同的元素或非零元素分布有一定规律的矩阵
–压缩 : 将二维数组的元素压缩到一维数组–关键 : 两个数组的下标之间建立映象关系
50/53
例 : 对称矩阵的压缩存储
对称矩阵的元素满足: – aij = aji 1 i , j n
n*n 个元素压缩存放到 n ( n+1 )/2 个单元的一维数组中。
Aij 在一维数组中的地址为: i ( i-1 ) /2+j 当 ij LOC(aij) = j ( j-1 ) /2+i 当 i<j
51/53
对称矩阵的压缩存储
设有 A3x3矩阵 , a11 A3x3 = a21 a22 a31 a32 a33 存于一维数组 S[6] S[6]=(a11, a21,a22, a31,a32,a33) 1 2 3 4 5 6– LOC(a31)=3(3-1)/2+1= 4– LOC(a22)=2(2-1)/2+2= 3– LOC(a21)=2(2-1)/2+1= 2
52/53
常见的特殊矩阵 :–对称矩阵 存储主对角线以上 ( 下 ) 的元素
–上 ( 下 ) 三角矩阵 只存储三角阵元素;–带状矩阵 只存储带状元素;
(2) 稀疏矩阵的压缩存储– 利用三元组只存储非零元素;– 三元组 : (i,j,aij)
53/53
作业、思考题
思考题:– 试写出“在带头结点的单循环链表中求表长的算法”。
– 假设一单循环链表的长度大于 1 ,且表中即无头结点也无头指针。已知 S 为指向链表中某结点的指针。试写出删除表中结点 S 的算法。
– 假设以数组 sequ[m-1] 存放循环队列的元素,设变量 rear 和 quelen 分别为指示队尾元素位置和队中元素个数,试写出入队和出队算法。
第 1章作业: 8 、 10 、 11