数据结构讲义Word格式.docx
《数据结构讲义Word格式.docx》由会员分享,可在线阅读,更多相关《数据结构讲义Word格式.docx(102页珍藏版)》请在冰豆网上搜索。
森林和二叉树的转换(A)
遍历树和森林(A)
7.图
图的有关概念
熟练掌握图的各种存储结构
图的遍历:
深度优先、广度优先(A)
最小生成树算法(两个)及其特点(A)
拓扑排序(A)
关键路径算法(A)
最短路径算法(两个)(A,O:
时间复杂度)
8.查找表
查找的有关概念,ASL等
顺序查找(A,P)
熟练掌握有序表的折半查找算法(A,P,C)
了解索引顺序表
熟练掌握二叉排序树的概念,建立(A),查找(A,P),删除(A),计算ASL(C)
平衡二叉排序树的概念,建立(A),判断失去平衡的类型,平衡化(A),计算ASL(C)
了解B_树,B+树的概念和特点
知道键树(数字查找树)
哈希表的概念、特点、构造哈希表(A),计算ASL和装填因子α(C)
了解各种查找表的性能(O)
9.内部排序
直接插入排序(A)
折半插入排序(A,P)
希尔排序(A)
起泡排序(A)
快速排序(A,P,O)
简单选择排序(P,A,O)
堆的概念,调整成堆(A),堆排序(A,O)
归并排序(A,O)
链式基数排序(A,O)
各种排序算法的对比结论(O)
第2章绪论
一、基础知识
概念和术语(黑体字部分)。
另外,注意:
1、数据元素是数据的基本单位。
P4
2、数据项是数据不可分割的最小单位。
P5
3、数据结构及其形式定义。
四种基本结构:
①集合②线性结构③树形结构④图(网)状结构
4、数据结构的
逻辑结构(抽象的,与实现无关)
物理结构(存储结构)顺序映像(顺序存储结构)位置“相邻”
非顺序映像(链式存储结构)指针表示关系P6
5、数据类型P7
抽象数据类型(ADT)P7
ADT=(数据对象,数据关系,基本操作)
ADT细分为原子类型,固定聚合,可变聚合类型。
P8
6、算法的概念P13
7、算法的五个特征
①有穷性②确定性③可行性④输入(0个或多个)⑤输出(1个或多个)
8、算法设计的要求:
①正确性②可读性③健壮性④效率与低存储量
其中正确性的四个层次(通常要求达到C层)。
9、算法的时间复杂度P15
常见有:
O
(1),O(n),O(n2),O(log2n),O(nlog2n),O(2n)
语句频度,用归纳法计算。
10、算法的空间复杂度P17
二、算法
起泡排序。
P16
另一种形式
voidBubbleSort(DataTypea[],intn)
{
for(i=0;
i<
n-1;
i++)
for(j=0;
j<
n-i-1;
j++)
if(a[j]>
a[j+1])
a[j]<
—>
a[j+1];
}
或
for(i=1;
n;
n-i;
if(a[j]>
i++){
change=fasle;
a[j+1]){
change=true;
}
if(!
change)break;
说明:
a)考试中要求写算法时,可用类C,也可用C程序。
b)尽量书写算法说明,言简意赅。
c)技巧:
用“边界值验证法”检查下标越界错误。
如上第一个:
第二个循环条件若写作j<
n-i,则当i=0时a[j+1]会越界。
d)时间复杂度为O(n2),第3个在最好情况下(待排记录有序),时间复杂度为O(n)。
三、习题
1.1编写冒泡排序算法,使结果从大到小排列。
1.2计算下面语句段中指定语句的频度:
1)for(i=1;
=n;
for(j=i;
x++;
//@
2)i=1;
while(i<
=n)
i=i*2;
第3章线性表
一、基础知识和算法
线性表及其特点
线性表是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()函数在必要的时候自动复制原来的元素到新分配的空间中。
基本形态
顺序表空
0<
L.length<
MAXSIZE
条件L.length==0
不允许删除操作
顺序表满
条件L.length==MAXSIZE
不允许插入操作
不空也不满
可以插入,删除
基本算法——遍历
顺序访问所有元素
for(i=0;
L.length;
visit(L.elem[i]);
查找元素x
if(L.elem[i]==x)break;
if(i<
L.length)
找到;
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<
L.length)returnfalse;
x=L.elem[i-1];
L.elem[j-1]=L.elem[j];
L.length--;
//删除成功
算法分析
表2.1顺序表插入和删除算法的分析
插入
删除
基本操作
平均移动次数
移动元素
时间复杂度
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.单链表——线性表的链式存储结构之一
概念
线性链表,单链表,结点;
数据域,指针域;
头指针,头结点。
用指针表示数据之间的逻辑关系(逻辑相邻的元素物理位置不一定相邻)。
简而言之,“数据+指针”。
next
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->
//指针沿着链表向后移动
例:
打印单链表中的数据。
voidPrintLinkList(LinkListL)
p=L->
while(p!
=NULL){
print(p->
//访问:
打印数据域
//在单链表L中查找元素x
//若找到,返回指向该结点的指针;
否则返回空指针
LinkListFind(LinkListL,DataTypex)
if(p->
data==x)returnp;
//找到x
returnNULL;
//未找到
//若找到,返回该元素的位序;
否则返回0
intFind(LinkListL,DataTypex)
j=1;
data==x)returnj;
j++;
//计数器随指针改变
return0;
前一个算法的另一种写法:
while(p&
&
p->
data!
=x)
if(p&
data==x)returnp;
elsereturn0;
或者
=x)p=p->
returnp;
//为什么
查找第i个元素
LinkListGet(LinkListL,inti)
while(p&
i){
if(p&
j==i)returnp;
elsereturn0;
查找第i-1个元素
p=L;
j=0;
i-1){
j==i-1)returnp;
技巧:
画图辅助分析。
思路:
先查找第i-1个元素
若找到,在其后插入新结点
boolListInsert(LinkList&
L,inti,DataTypex)
//查找第i-1个元素p
p=L;
//若找到,在p后插入x
①
j==i-1){
s=(LinkList)malloc(sizeof(LNode));
s->
data=x;
next=p->
//①
next=s;
//②
else
returnfalse;
//插入失败
注意:
a)要让p指向第i-1个而不是第i个元素(否则,不容易找到前驱以便插入)。
b)能够插入的条件:
p&
j==i-1。
即使第i个元素不存在,只要存在第i-1个元素,仍然可以插入第i个元素。
c)新建结点时需要动态分配内存。
若检查是否分配成功,可用
if(s==NULL)exit
(1);
//分配失败则终止程序
d)完成插入的步骤:
①②。
先修改新结点的指针域。
若找到且其后存在第i个元素,则用x返回数据,并删除之
②
boolListDelete(LinkList&
L,inti,int&
x)
//若存在第i个元素,则用x返回数据,并删除之
j==i-1&
next){//可以删除
s=p->
next=s->
x=s->
data;
free(s);
a)要求p找到第i-1个而非第i个元素。
为什么?
b)能够进行删除的条件:
next。
条件中的p->
next就是要保证第i个元素存在,否则无法删除。
若写成p->
next&
j==i-1也不妥,因为此时(循环结束时)可能有p==NULL,所以必须先确定p不空。
将条件中的“大前提”放在前面。
该条件也不可以写成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));
next=NULL;
//空表
//用p指向表尾
//插入元素
scanf(x);
//插入表尾
p=s;
//新的表尾
逆序建表
//空表
//插入表头
next=L->
3.循环链表
最后一个结点的指针指向头结点。
L
同单链表。
空表:
next==L。
非空表。
与单链表的联系
判断表尾的方法不同:
单链表用p==NULL;
循环链表用p==L。
其余操作相同。
4.双向循环链表
一个结点包含指向后继(next)和指向前驱(prior)两个指针,两个方向又分别构成循环链表。
typedefstructDuLNode{
structDuLNode*prior,*next;
//两个指针
}DuLNode,*DuLinkList;
用后向指针判断L->
next==L,或者用前向指针判断L->
prior==L。
......
与单链表和循环链表的联系
最大不同:
前驱容易求得,可以向前遍历。
判断表尾的方法与循环链表相同:
p==L。
插入和删除时需要修改两个方向的指针。
插入和删除
需要修改两个方向的指针。
例如:
(见下表)
表2.2双向循环链表的插入和删除
p之后插入s
p之前插入s
删除p之后继s
删除p
s->
p->
prior=p;
next->
prior=s;
prior=p->
prior;
next=p;
prior->
s=p->
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将两个非递减有序的单链表归并成一个,仍并保持非递减有序。
第4章栈和队列
1.栈
栈,栈顶,栈底,空栈,后进先出(LIFO),入栈(Push),出栈(Pop)。
顺序栈:
栈的顺序存储结构;
链栈:
栈的链式存储结构。
2.链栈
(1)存储结构
用不带头结点的单链表实现。
(2)类型定义
(3)基本形态
/\
栈空
条件:
S==NULL
栈非空
栈满(一般不出现)
(4)基本算法
入栈Push(&
s,x)
boolPush(LinkList&
s,DataTypex)
//新建结点
p=(LinkList)malloc(sizeof(LNode));
p)returnfalse;
//插入栈顶
s=p;
出栈Pop(&
s,&
栈非空。
boolPop(LinkList&
s,DataType&
if(s==NULL)returnfals