线性表 教案.docx
- 文档编号:12595061
- 上传时间:2023-04-20
- 格式:DOCX
- 页数:16
- 大小:69.01KB
线性表 教案.docx
《线性表 教案.docx》由会员分享,可在线阅读,更多相关《线性表 教案.docx(16页珍藏版)》请在冰豆网上搜索。
线性表教案
线性表
【教学目的】:
1、了解数据结构的概念
2、掌握时间复杂度的概念和计算方法
【教学方法】:
理论教学
【教学课时】:
2课时(复习)
【教学内容】:
一、基础知识和算法
线性表及其特点
线性表是n个数据元素的有限序列。
线性结构的特点:
①“第一个”②“最后一个”③前驱④后继。
1.顺序表——线性表的顺序存储结构
特点
a)逻辑上相邻的元素在物理位置上相邻。
b)随机访问。
类型定义
简而言之,“数组+长度”。
constintMAXSIZE=线性表最大长度;
typedefstruct{
DataTypeelem[MAXSIZE];
intlength;
}SqList;
注:
a)SqList为类型名,可换用其他写法。
b)DataType是数据元素的类型,根据需要确定。
c)MAXSIZE根据需要确定。
如
constintMAXSIZE=64;
d)课本上的SqList类型可在需要时增加存储空间,在上面这种定义下不可以。
(这样做避免了动态内存分配,明显减少了算法的复杂程度,容易理解。
而且,原来Pascal版本的《数据结构》(严蔚敏)就是这样做的。
)
e)课本上的SqList类型定义中listsize表示已经分配的空间大小(容纳数据元素的个数)。
当插入元素而遇到L.length==L.listsize时,用realloc(L.elem,L.listsize+增量)重新分配内存,而realloc()函数在必要的时候自动复制原来的元素到新分配的空间中。
基本形态
顺序表空
条件L.length==0
不允许删除操作
顺序表满
条件L.length==MAXSIZE
不允许插入操作
不空也不满
可以插入,删除
基本算法——遍历
顺序访问所有元素
for(i=0;i visit(L.elem[i]); 查找元素x for(i=0;i if(L.elem[i]==x)break; if(i 找到; else 未找到; 插入算法ListInsert(&L,i,x) 前提: 表不满 合理的插入范围: 1≤i≤L.length+1 注: 位序i在C/C++中对应于下标i-1。 步骤 第i至最后所有元素后移一个元素 在第i个位置插入元素x 表长增1 算法 boolListInsert(SqList&L,inti,DataTypex){ if(L.length==MAXSIZE||i<1||i>L.length+1)returnfalse;//失败 //元素后移 for(j=L.length-1;j>=i-1;j--)//这里j为下标,从L.length-1到i-1 L.elem[j+1]=L.elem[j];//若作为位序,有如何修改? //插入x L.elem[i-1]=x; //表长增1 L.length++; returntrue;//插入成功 } 删除算法ListDelete(&L,i,&x) 前提: 表非空 合理的删除范围: 1≤i≤L.length 步骤 取出第i个元素 第i个元素之后的元素向前移动一个位置 表长减1 算法 boolListDelete(SqList&L,inti,DataType&x) { if(L.length==0||i<1||i>L.length)returnfalse;//失败 x=L.elem[i-1]; for(j=i;j L.elem[j-1]=L.elem[j]; L.length--; returntrue;//删除成功 } 算法分析 表2.1顺序表插入和删除算法的分析 插入 删除 基本操作 平均移动次数 移动元素 移动元素 时间复杂度 O(n) O(n) 尾端操作 插入第n+1个元素,不移动 删除第n个元素,不移动 插入、删除需移动大量元素O(n);但在尾端插入、删除效率高O (1)。 其他算法 InitList(&L),ClearList(&L) L.length=0; ListEmpty(L) returnL.length==0; ListLength(L) returnL.length; GetElem(L,i,&e) e=L.elem[i-1]; 2.单链表——线性表的链式存储结构之一 概念 线性链表,单链表,结点;数据域,指针域;头指针,头结点。 特点 用指针表示数据之间的逻辑关系(逻辑相邻的元素物理位置不一定相邻)。 类型定义 简而言之,“数据+指针”。 typedefstructLNode{ DataTypedata; structLNode*next; }LNode,*LinkList; 基本形态 带头结点的单链表的基本形态有: 单链表空 条件: L->next==0 单链表不空 条件: L->next! =0 基本算法(遍历) 顺序访问所有元素 借助指针,“顺藤摸瓜”(沿着链表访问结点)。 p=L->next;//注意起始位置的考虑 while(p! =NULL){//判表尾,另外(p! =0)或(p)均可 visit(p->data);//访问: 可以换成各种操作 p=p->next;//指针沿着链表向后移动 } 例: 打印单链表中的数据。 voidPrintLinkList(LinkListL) { p=L->next; while(p! =NULL){ print(p->data);//访问: 打印数据域 p=p->next; } } 查找元素x //在单链表L中查找元素x //若找到,返回指向该结点的指针;否则返回空指针 LinkListFind(LinkListL,DataTypex) { p=L->next; while(p! =NULL){ if(p->data==x)returnp;//找到x p=p->next; } returnNULL;//未找到 } //在单链表L中查找元素x //若找到,返回该元素的位序;否则返回0 intFind(LinkListL,DataTypex) { p=L->next;j=1; while(p! =NULL){ if(p->data==x)returnj;//找到x p=p->next;j++;//计数器随指针改变 } return0;//未找到 } 前一个算法的另一种写法: p=L->next; while(p&&p->data! =x) p=p->next; if(p&&p->data==x)returnp; elsereturn0; 或者 p=L->next; while(p&&p->data! =x)p=p->next; returnp;//为什么 查找第i个元素 LinkListGet(LinkListL,inti) { p=L->next;j=1; while(p&&j p=p->next;j++; } if(p&&j==i)returnp; elsereturn0; } 查找第i-1个元素 p=L;j=0; while(p&&j p=p->next;j++; } if(p&&j==i-1)returnp; elsereturn0; 插入算法ListInsert(&L,i,x) 技巧: 画图辅助分析。 思路: 先查找第i-1个元素 若找到,在其后插入新结点 boolListInsert(LinkList&L,inti,DataTypex) { //查找第i-1个元素p p=L;j=0; while(p&&j p=p->next;j++; } //若找到,在p后插入x if(p&&j==i-1){ s=(LinkList)malloc(sizeof(LNode)); s->data=x; s->next=p->next;//① p->next=s;//② returntrue;//插入成功 } else returnfalse;//插入失败 } 注意: a)要让p指向第i-1个而不是第i个元素(否则,不容易找到前驱以便插入)。 b)能够插入的条件: p&&j==i-1。 即使第i个元素不存在,只要存在第i-1个元素,仍然可以插入第i个元素。 c)新建结点时需要动态分配内存。 s=(LinkList)malloc(sizeof(LNode)); 若检查是否分配成功,可用 if(s==NULL)exit (1);//分配失败则终止程序 d)完成插入的步骤: ①②。 技巧: 先修改新结点的指针域。 删除算法ListDelete(&L,i,&x) 思路: 先查找第i-1个元素 若找到且其后存在第i个元素,则用x返回数据,并删除之 boolListDelete(LinkList&L,inti,int&x) { //查找第i-1个元素p p=L;j=0; while(p&&j p=p->next;j++; } //若存在第i个元素,则用x返回数据,并删除之 if(p&&j==i-1&&p->next){//可以删除 s=p->next;//① p->next=s->next;//② x=s->data; free(s); returntrue; } else returnfalse; } 注意: a)要求p找到第i-1个而非第i个元素。 为什么? b)能够进行删除的条件: p&&j==i-1&&p->next。 条件中的p->next就是要保证第i个元素存在,否则无法删除。 若写成p->next&&j==i-1也不妥,因为此时(循环结束时)可能有p==NULL,所以必须先确定p不空。 技巧: 将条件中的“大前提”放在前面。 该条件也不可以写成p->next&&p&&j==i-1,因为先有p! =0才有p->next,上式颠倒了这一关系。 c)释放结点的方法。 free(s); d)完成删除的步骤: ①②。 建立链表的两种方法 思路: 建立空表(头结点); 依次插入数据结点(每次插入表尾得(a1,a2,…,an),每次插入表头得(an,…,a2,a1))。 顺序建表 voidCreateLinkList(LinkList&L,intn) { //建立空表 L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//空表 p=L;//用p指向表尾 //插入元素 for(i=0;i scanf(x); s=(LinkList)malloc(sizeof(LNode)); s->data=x; //插入表尾 s->next=p->next; p->next=s; p=s;//新的表尾 } } 逆序建表 voidCreateLinkList(LinkList&L,intn) { //建立空表 L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//空表 //插入元素 for(i=0;i scanf(x); s=(LinkList)malloc(sizeof(LNode)); s->data=x; //插入表头 s->next=L->next; L->next=s; } } 3.循环链表 特点 最后一个结点的指针指向头结点。 类型定义 同单链表。 基本形态 空表: L->next==L。 非空表。 与单链表的联系 判断表尾的方法不同: 单链表用p==NULL;循环链表用p==L。 其余操作相同。 4.双向循环链表 特点 一个结点包含指向后继(next)和指向前驱(prior)两个指针,两个方向又分别构成循环链表。 类型定义 typedefstructDuLNode{ DataTypedata; structDuLNode*prior,*next;//两个指针 }DuLNode,*DuLinkList; 基本形态 空表: 用后向指针判断L->next==L,或者用前向指针判断L->prior==L。 非空表。 与单链表和循环链表的联系 最大不同: 前驱容易求得,可以向前遍历。 判断表尾的方法与循环链表相同: p==L。 插入和删除时需要修改两个方向的指针。 插入和删除 需要修改两个方向的指针。 例如: (见下表) 表2.2双向循环链表的插入和删除 p之后插入s p之前插入s 删除p之后继s 删除p s->next=p->next; p->next=s; s->prior=p; s->next->prior=s; s->prior=p->prior; p->prior=s; s->next=p; s->prior->next=s; s=p->next; p->next=s->next; p->next->prior=p; p->prior->next=p->next; p->next->prior=p->prior; 5.顺序表与单链表的比较 表2.3顺序表和单链表的比较 顺序表 单链表 以地址相邻表示关系 用指针表示关系 随机访问,取元素O (1) 顺序访问,取元素O(n) 插入、删除需要移动元素O(n) 插入、删除不用移动元素O(n)(用于查找位置) 总结: 需要反复插入、删除,宜采用链表;反复提取,很少插入、删除,宜采用顺序表。 二、习题 2.1将顺序表中的元素反转顺序。 2.2在非递减有序的顺序表中插入元素x,并保持有序。 2.3删除顺序表中所有等于x的元素。 2.4编写算法实现顺序表元素唯一化(即使顺序表中重复的元素只保留一个),给出算法的时间复杂度。 2.5非递减有序的顺序表元素唯一化(参见习题2.4),要求算法的时间复杂度为O(n)。 2.6将单链表就地逆置,即不另外开辟结点空间,而将链表元素翻转顺序。 2.7采用插入法将单链表中的元素排序。 2.8采用选择法将单链表中的元素排序。 2.9将两个非递减有序的单链表归并成一个,仍并保持非递减有序。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 线性表 教案 线性