Click here to load reader
Upload
siusan
View
111
Download
4
Embed Size (px)
DESCRIPTION
第三章 栈和队列. 2007.9. Stack and Queue. 生活中的栈与队列 计算机中的栈与队列 栈:表达式的求值、函数的递归调用 队列:打印机任务处理、 CPU 的进程处理 栈与队列的特征 LIFO(Last In First Out) FIFO(First In First Out)/FIFS(First In First Service). 第 1 节 栈. 栈的定义 栈的特征 栈的基本运算 顺序栈的实现 链式栈的实现. 1. 栈( Stack ) 的定义. - PowerPoint PPT Presentation
Citation preview
2007.9
第三章 栈和队列Stack and Queue
生活中的栈与队列
计算机中的栈与队列栈:表达式的求值、函数的递归调用队列:打印机任务处理、 CPU 的进程处理
栈与队列的特征LIFO(Last In First Out)FIFO(First In First Out)/FIFS(First In First
Service)
栈的定义栈的特征栈的基本运算顺序栈的实现链式栈的实现
第 1 节 栈
1. 栈( Stack )的定义 栈 (Stack) 是限制在表的一端进行插入和删除运算的线性表。 栈顶 (Top) 为可进行插入、删除的一端,另一端为栈底
(Bottom) 。 空栈:表中没有元素。 假设栈 S=(a1 , a2 , a3 ,… an) ,则 a1 称为栈底元素,
an 为栈顶元素。栈中元素按 a1 , a2 , a3 ,… an 的次序进栈,退栈的第一个元素应为栈顶元素。换句话说,栈的修改是按后进先出的原则进行的。因此,栈称为后进先出表( LIFO )。
3. 线性表的基本运算1.InitList(L) : 初始化 , 置表 L 为空2.ClearList(L): 将表 L 清空3.ListLength(L) : 求表 L 的长度4.Insert(L,i,Item) : 插入,在给定的线性表 L 中,将数据 Item 插入到第 i 个结点的位置。表 L 长度加 1 。5.Delete(L,i) :删除,在给定的线性表 L 中,删除第 i 个元素。表 L 的长度减 1 。6.Get(L,i) :获取表 L 中第 i 个结点的值。7.Locate(L,x) :查找定位。若线性表 L 中存在一个值为x 的结点,则返回该结点的位置,否则返回空。8.GetNext ( L , Item , p):取 Item的后继结点9.GetPrior ( L , Item , p ):取 Item 的前驱结点
顺序表的存储结构顺序表存储结构的 C 语言描述基于顺序表的运算的实现
第 2 节 线性表的顺序存储—顺序表
1. 顺序表的存储结构顺序表:把线性表的结点按逻辑顺序依次存放在一组地址连续的存储单元里。用这种方法存储的线性表简称顺序表。由于 C 语言中的一维数组也是采用顺序存储表示,故可以用数组类型来描述顺序表。
a1
a2
an
内存0
ListSize -1
备用空间
有效结点
2. 顺序表存储结构的 C 语言描述 # define ListSize 100 typedef int DataType; typedef struc{ DataType
data[ListSize]; int length; } SequenList;
/* 声明变量 */SequenList *sqlist;
a1
a2
an
01
n-1length
内存 数组下标
ListSize -1
备用空间
一个具体的例子 # define ClassSize 100
typedef struct stu{ char* num; char* name; int english; int c_languge; int data_stru;}StuType;typedef struc{ StuType
data[ClassSize]; int class_len; } class_list;class_list *soft_1;
学号 姓名 大学英语 C 语言 数据结构 …A07001 王萍 90 85 95 …A07002 马玲 80 85 90 …A07003 张兰 95 91 99 …A07004 李建 70 84 86 …A07005 黄勇 82 76 78 …
: : : : : :
学生成绩表
顺序表的地址关系 假设线性表的每个元素需占用 m 个存储单元,并以所占的第一个单元的存储地址作为数据元素的存储位置。则线性表中第 i+1 个数据元素的存储位
置 LOC( a i+1) 和第 i 个数据元素的存储位置LOC(a I ) 之间满足下列关系:
LOC(a i+1)=LOC(a i)+m
线性表的第 i 个数据元素 ai 的存储位置为: LOC(ai)=LOC(a1)+(i-1)*m
3. 基于顺序表的运算的实现1.InitList(L) : 初始化 , 置表 L 为空2.ClearList(L): 将表 L 清空3.ListLength(L) : 求表 L 的长度4.Insert(L,i,Item) : 插入,在给定的线性表 L中,将数据 Item 插入到第 i 个结点的位置。表 L长度加 1 。5.Delete(L,i) :删除,在给定的线性表 L 中,删除第 i 个元素。表 L 的长度减 1 。
6.Get(L,i) :获取表 L 中第 i 个结点的值。7.Locate(L,x) :查找定位。若线性表 L 中存在一个值为 x 的结点,则返回该结点的位置,否则返回空。8.GetNext ( L , Item , p):取 Item的后继结点9.GetPrior ( L , Item , p ):取 Item
的前驱结点
4. 顺序表插入算法的时间复杂度分析Void InsertList(Sequenlist *sqlist , int i, DataType
Item) { int j; if (i<1 || i>sqlist.length+1){ printf(“Position error”); return 0 ; } if( sqlist.length >= ListSize ) { printf(“overflow”); return 0; } for( j=sqlist.length-1; j>=i-1;
j-- )sqlist.data[ j+1]=sqlist.data[ j ]; sqlist.data[ i-1]=x; sqlist.length++;}
顺序表插入算法的时间复杂度分析时间主要耗费在: for( j=sqlist.length-1; j>=i-1; j-- ) sqlist.data[ j+1]=sqlist.data[ j ];所需移动结点的次数不仅依赖于表的长度,而且还与插入位置有关。最好:当 i=n 时,结点不需要后移,其时间复杂度O ( 1 );最坏:当 i=0 时,结点后移语句将循环执行 n 次,需移动表中所有结点,其时间复杂度 O ( n )
平均复杂度:由于插入可能在表中任何位置上进行,因此需分析算法的平均复杂度 在长度为 n 的线性表中第 i 个位置上插入一个结点,
令 Eis(n) 表示移动结点的期望值(即移动的平均次数),则在第 i 个位置上插入一个结点的移动次数为 n-I+1 。故 不失一般性,假设在表中任何位置 (1≦i≦n+1) 上插入结点的机会是均等的,则在等概率插入的情况下,
1
1
)1(n
ii inPEis
nO
ninn
Eis
nP
n
i
i
平均时间复杂度为:因此
则
若
,
2)1(
11
11:
1
1
也就是说,在顺序表上做插入运算,平均要移动表上一半结点。当表长 n 较大时,算法的效率相当低。虽然 Eis(n) 中 n 的的系数较小,但就数量级而言,它仍然是线性阶的。因此算法的平均时间复杂度为 O(n) 。问题:请你分析一下删除算法的时间复杂度。
5. 顺序表存储结构特点基本特点:逻辑上相邻的元素,物理上也是相邻的。优点
可以直接实现元素的定位,或者说可以随机存取其中的任意元素因为数据在存储结构中是连续存储的,任意元素的存储地址可由公式直接算出。
高级程序设计语言提供的数组类型可以直接定义顺序存储结构的线性表,使程序实现十分方便。
顺序存储结构的不方便之处:数据元素最大个数需预先确定,使得高级语言编译系统需预先分配相应的存储空间。插入与删除运算的效率很低。
为了保持线性表中的数据元素的顺序,在插入操作和删除操作时需移动大量数据。顺序存储结构的线性表的存储空间不便于扩充。
当一个线性表分配顺序存储空间后,如果线性表的存储空间已满,但还需要插入新的元素,则会发生“上溢”错误,会导致运算的失败或中断。
Link List
2.2 单链表
复习:关于指针的概念指针 地址即
指针 与 指针所指的变量指针相关的函数
•malloc•free
1. 单链表的存储结构线性表的逻辑结构
单链表的逻辑结构Data_1
Data_2
Data_n
^…
单链表的结点结构数据域 指针域
单链表的存储结构
……… ……
Data_2 200……. ……
Data_1 110…. ……
Data_n Null
135…… ……
…… ……
头指针 head : 165
110135
165
200
head
A07001
王萍90
85
95
A07002
马玲80
85
90
A07003
张兰95
91
99
A07004
李建70
84
86
A07005
黄勇82
76
78
NULL
一个具体的例子 学号 姓名 大学英语 C 语言 数据结构 …A07001 王萍 90 85 95 …A07002 马玲 80 85 90 …A07003 张兰 95 91 99 …A07004 李建 70 84 86 …A07005 黄勇 82 76 78 …
: : : : : :
head
一个具体的例子……… ……
A07002 马玲…
200
……. ……
A07001 王萍…
110
…. ……
A070046 … Null
135…… ……
…… ……
头指针 head : 165
110
135
165
200
学号 姓名 大学英语 C 语言 数据结构 …A07001 王萍 90 85 95 …A07002 马玲 80 85 90 …A07003 张兰 95 91 99 …A07004 李建 70 84 86 …A07005 黄勇 82 76 78 …
: : : : : :
2. 单链表存储结构的 C 语言描述顺序表的描述# define ListSize 100 typedef int DataType; typedef struc{ DataType
data[ListSize]; int length; } SequenList;
/* 声明变量 */SequenList *sqlist;
Data_1
Data_2
Data_n
^…head
typedef int DataType;
typedef struc node{
DataType data; struc node *next; } LinkList;
/* 声明变量 */LinkList *head;
一个具体的例子 # define ClassSize 100
typedef struct stu{ char* num; char* name; int english; int c_languge; int data_stru;}StuType;typedef struc{ StuType
data[ClassSize]; int class_len; } class_list;class_list *soft_1;
学号 姓名 大学英语 C 语言 数据结构 …A07001 王萍 90 85 95 …A07002 马玲 80 85 90 …A07003 张兰 95 91 99 …A07004 李建 70 84 86 …A07005 黄勇 82 76 78 …
: : : : : :
学生成绩表typedef struct stu{ char* num; char* name; int english; int c_languge; int data_stru;}StuType;typedef struc node{ StuType data; struc node *next ;} class_list;class_list
*soft_1_head;
基于单链表的运算的实现1.InitList(L) : 初始化 , 置表 L 为空2.ClearList(L): 将表 L 清空3.ListLength(L) : 求表 L 的长度4.Insert(L,i,Item) : 插入,在给定的线性表 L中,将数据 Item 插入到第 i 个结点的位置。表 L长度加 1 。5.Delete(L,i) :删除,在给定的线性表 L 中,删除第 i 个元素。表 L 的长度减 1 。
6.Get(L,i) :获取表 L 中第 i 个结点的值。7.Locate(L,x) :查找定位。若线性表 L 中存在一个值为 x 的结点,则返回该结点的位置,否则返回空。8.GetNext ( L , Item , p):取 Item的后继结点9.GetPrior ( L , Item , p ):取 Item
的前驱结点
单链表算法的时间复杂度O ( 1 ) O ( n )O ( 1 ) O ( n )
InitList(L) ClearList(L)Insert(L,i,Item) ListLength(L)Delete(L,i) Get(L,i) GetNext(L , Item , p)
Locate(L,x)
GetPrior( L , Item ,p)
单链表的建立void build( int n ) { linklist *q; char ch; int i; printf("\n input %2d data: \t",n); head=(struct link *)malloc(sizeof(struct
link)); q=head; scanf("%d",&q->data); for(i=2;i<=n;i++){ q->next=(struct link
*)malloc(sizeof(struct link)); q=q->next; scanf("%d",&q->data); } q->next=NULL; }
单链表存储结构特点基本特点:逻辑上相邻的元素,物理上不一定相邻的。优缺点
是一种动态结构,整个存储空间为多个链表共用不需预先分配空间指针占用额外存储空间不能随机存取,查找速度慢
2.3 其他形式的链表
2.3.1 循环链表循环链表是表中最后一个结点的指针指向头结点,使链表构成环状。特点:从表中任一结点出发均可找到表中其他结点,提高查找效率。
单链表的逻辑结构Data_1
Data_2
Data_n
^…
循环链表的逻辑结构Data_1
Data_2
Data_n
…
循环链表的空表head
循环链表的操作循环链表的操作与单链表基本一致 , 循环条件不同
单链表 : p->next==NULL循环链表 : p->next==head
循环链表的建立void build( int n ) { linklist *q; char ch; int i; printf("\n input %2d data: \t",n); head=(struct link *)malloc(sizeof(struct
link)); q=head; scanf("%d",&q->data); for(i=2;i<=n;i++){ q->next=(struct link
*)malloc(sizeof(struct link)); q=q->next; scanf("%d",&q->data); } q->next=head; }
讨论:如何将两个链表合并?利用单链表如何实现? P47 EX4
Data_1
Data_2
Data_n
^…
Data_1
Data_2
Data_m
^…
ha
hb
利用循环链表如何实现?表头指针与表尾指针的使用
Data_1
Data_2
Data_n
…
Data_1
Data_2
Data_m
…
ha
hb
ra
rb
2.3.2 双向循环链表
特点:方便查找任一结点的后继和前驱。
双向循环链表的逻辑结构
双向循环链表的空表head
双向链表的结点结构 prior
data
next
head
双向循环链表的 C 语言描述typedef int DataType; typedef struc Dnode{ DataType data; struc Dnode *prior,
next; } DoubleLinkList;
/* 声明变量 */DoubleLinkList *head;
prior
data
next
双向循环链表中的插入与删除void dinsertbefor(dlistnode
*p , datatype x) { dlistnode
*q=malloc(sizeof(dlistnode));
q—>data=x; q—>prior=p—>prior; q—>next=p; p—>prior—>next=q; p—>prior=q; }
void ddeletenode(dlistnode *p)
{ p–>prior–>next=p–
>next; p–>next–>prior=p–
>prior; free(p); }•与单链表的插入和删除操作不同的是,在双链表中插入和删除必须同时修改两个方向上的指针。上述两个算是法的时间复杂度均为 O(1) 。