数据结构复习要点.docx
《数据结构复习要点.docx》由会员分享,可在线阅读,更多相关《数据结构复习要点.docx(24页珍藏版)》请在冰豆网上搜索。
数据结构复习要点
A—熟练掌握B—理解C—了解
第一章:
绪论
1.基本概念:
包括数据的逻辑结构、数据的存储结构和数据的相关运算。
C
四类数据组织结构:
集合、线性表、树形、图状结构C
数据的存储方式:
顺序存储和链式存储。
B
2.算法和分析
算法的特征、时间复杂度的分析和常见的时间复杂度增长率排序、空间复杂度B
本章重点:
分析算法时间复杂度
例1.下面关于算法说法错误的是()
A.算法最终必须由计算机程序实现
B.为解决某问题的算法同为该问题编写的程序含义是相同的
C.算法的可行性是指指令不能有二义性D.以上几个都是错误的
D
例2.以下那一个术语与数据的存储结构无关?
()
A.栈B.哈希表C.线索树D.双向链表
A.
例3..求下段程序的时间复杂度:
voidmergesort(inti,intj){
intm;
if(i!
=j){
m=(i+j)/2;
mergesort(i,m);
mergesort(m+1,j);
merge(i,j,m);}
}
其中mergesort()用于对数组a[n]归并排序,调用方式为mergesort(0,n-1);,merge()用于两个有序子序列的合并,是非递归函数,时间复杂度为
。
解:
分析得到的时间复杂度的递归关系:
为merge()所需的时间,设为cn(c为常量)。
因此
令
,有
有
第二章:
线性表
1.线性表的基本运算:
…..C
2.线性表的顺序存储(利用静态数组或动态内存分配)。
相应的表示与操作A
3.线性表的链式存储。
相应的表示与操作。
包括循环链表、双向链表。
A
4.顺序存储与链式存储的比较:
基于时间的考虑--分别适用于静态的和动态的操作:
比如静态查找和插入删除);基于空间的考虑--…….B
这也适用于后面用两种方式存储的其他数据结构。
★本章重点:
很熟悉顺序表,单链表、双链表,循环链表的基本操作;并学会在各种链表上进行一些算法设计(与基本操作类似的操作或组合),请仔细复习。
例4.假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。
请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表。
[题目分析]因为两链表已按元素值递增次序排列,将其合并时,均从第一个结点起进行比较,将小的链入链表中,同时后移链表工作指针。
该问题要求结果链表按元素值递减次序排列。
故在合并的同时,将链表结点逆置。
voidUnion(LinkListla,LinkListlb)
∥la,lb分别是带头结点的两个单链表的头指针,链表中的元素值按递增序排列,本算法将两链表合并成一个按元素值递减次序排列的单链表。
{pa=la->next;pb=lb->next;∥pa,pb分别是链表la和lb的工作指针
la->next=null; ∥la作结果链表的头指针,先将结果链表初始化为空。
while(pa!
=null&&pb!
=null)∥当两链表未访问结束
if(pa->data<=pb->data)
{q=pa->next; ∥将pa的后继结点暂存于q。
pa->next=la->next; ∥将pa结点链于结果表中,同时逆置。
la->next=pa;
pa=q; ∥恢复pa为当前待比较结点。
}
else{
q=pb->next;∥将pb的后继结点暂存于q。
pb->next=la->next;∥将pb结点链于结果表中,同时逆置。
la->next=pb;
pb=q;∥恢复pb为当前待比较结点。
}
while(pa!
=null)∥将la表的剩余部分链入结果表,并逆置。
{q=pa->next;pa->next=la->next;la->next=pa;pa=q;}
while(pb!
=null)
{q=pb->next;pb->next=la->next;la->next=pb;pb=q;}
}∥算法Union结束。
注意:
(1)此处q用作暂存后继结点,操作后pa或pb还回原指向位置;这与我们原来不改变pa或pb的指向,增加一个q=pa或pb作为摘取结点进行添加操作起到的作用一样。
(2)此处要完成逆序插入操作故用头插法(基于头指针la或lb),注意尾插法(附设一个尾指针,基于该指针插入)的可完成顺序插入。
(注意:
逆序另一种方式也要掌握!
)
练习:
练习题2编程1——6
7.判断带头结点双向循环链表L是否对称相等.
8.设计一个算法判断单链表(带头结点)是否是递增的(注意比排序算法应该简单,链表排序也要会实现)
9.设计一个算法判断有序表A是否是有序表B的子集(即表A中的元素在B中)。
(思考:
如果递归程序怎么写?
)
第三章:
栈与队列
1.两种特殊线性表:
分别有后进先出、先进先出的特性。
B
2.栈的顺序表示与实现(利用静态数组或动态内存分配)A
注意栈顶指针的初始位置不同,进出栈,栈空栈满的实现语句有差别!
举例:
若定义
typedefstruct{
SElemType*base;
SElemType*top;
intstacksize;//当前栈能使用的最大容量
}SqStack;
SqStacks;
top的初始值指向栈底,即top=base;
栈空条件:
s.top==s.base此时不能出栈
栈满条件:
s.top-s.base>=s.stacksize
进栈操作:
*s.top++=e;或*s.top=e;s.top++;
退栈操作:
e=*--s.top;或s.top--;e=*s.top
若定义:
typedefstruct{
SElemTypebase[MAXSIZE];
inttop;
}SqStack;
SqStacks;
top的初始值为0时:
栈空条件:
s.top==0此时不能出栈
栈满条件:
s.top>=MAXSIZE
进栈操作:
s.base[s.top++]=e;
退栈操作:
e=s.base[--s.top]
top的初始值为-1时:
栈空条件:
s.top==-1此时不能出栈
栈满条件:
s.top>=MAXSIZE-1
进栈操作:
s.base[++s.top]=e;
退栈操作:
e=s.base[s.top--]
3.栈的链式表示与实现B(对比顺序栈,实质不带头结点的链表在头指针处插入和删除)
4.队列的顺序表示与实现—循环队列A
设两个指针:
Q.front指向队列头元素;Q.rear指向队列尾元素的下一个位置
注意队中若Q.rear指向队列尾元素,进出队,实现语句有差别!
初始状态(空队列):
Q.front=Q.rear=0
队头指针进1:
Q.front=(Q.front+1)%MAXSIZE
队尾指针进1:
Q.rear=(Q.rear+1)%MAXSIZE;
队列初始化:
Q.front=Q.rear=0;
队空条件:
Q.front==Q.rear;
队满条件:
(Q.rear+1)%MAXSIZE==Q.front
队列长度:
(Q.rear-Q.front+MAXSIZE)%MAXSIZE
6.队列的链式表示与实现B
本章重点:
顺序栈的初始条件、操作,循环队列的初始条件、操作
本章难点:
栈的设计与使用,队列的设计与使用(主要结合后面树和图中的应用复习)
例5.链栈与顺序栈比起来优势在于。
没有预设容量的限制
例6.计算算术表达式的值时,可用两个栈作辅助工具。
对于给出的一个表达式,从左向右扫描它的字符,并将操作数放入栈S1中,运算符放入栈S2中,但每次扫描到运算符时,要把它同S2的栈顶运算符进行优先级比较,当扫描到的运算符的优先级不高于栈顶运算符的优先级时,取出栈S1的栈顶和次栈顶的两个元素,以及栈S2的栈顶运算符进行运算将结果放入栈S1中(得到的结果依次用T1、T2等表示)。
为方便比较,假设栈S2的初始栈顶为®(®运算符的优先级低于加、减、乘、除中任何一种运算)。
现假设要计算表达式:
A-B*C/D+E/F。
写出栈S1和S2的变化过程。
步骤
栈S1
栈S2
输入的算术表达式(按字符读入)
初始
®
A-B*C/D+E/F®
1
A
®
A-B*C/D+E/F®
2
A
®-
-B*C/D+E/F®
3
AB
®-
B*C/D+E/F®
4
AB
®-*
*C/D+E/F®
5
ABC
®-*
C/D+E/F®
6
AT1(注:
T1=B*C)
®-/
/D+E/F®
7
AT1D
®-/
D+E/F®
8
AT2(注:
T2=T1/D)
T3(注:
T3=A-T2)
®-
®+
+E/F®
9
T3E
®+
E/F®
10
T3E
®+/
/F®
11
T3EF
®+/
F®
12
T3T4(注:
T4=E/F)
T5(注:
T5=T3+T4)
®+
®
®
例7.将两个栈存入数组V[1..m]应如何安排最好?
这时栈空、栈满的条件是什么?
,入栈和出栈的操作是什么?
分析:
为了增加内存空间的利用率和减少溢出的可能性,由两个栈共享一片连续的空间时,应将两栈的栈底分别设在内存空间的两端,这样只有当两栈顶指针相邻(即值之差的绝对值为1时才产生溢出。
设栈S1和栈S2共享向量V[1..m],初始时,栈S1的栈顶指针top0=0,栈S2的栈顶指针top1=m+1,当top0=0为栈S1空,top1=m+1为栈S2空;当top0=0并且top1=m+1时为两栈全空。
当top1-top0=1时为栈满。
入栈核心操作S1:
V[++top0]=x1;S2:
V[--top1]=x2
出栈核心操作S1:
x1=V[top0--];S2:
x2=V[top1++]
例8.如果用一个循环数组base[0..MAX-1]表示队列时,该队列只有一个队列头指针front,不设队列尾指针rear,而改置计数器count用以记录队列中结点的个数。
(1)编写实现队列的三个基本运算:
判空、入队、出队
(2)队列中能容纳元素的最多个数是多少
typedefstruct
{ElemTypebase[MAX];
intfront,count;//front是指向队头元素针,count是队列中元素个数。
}CQueue;//定义类型标识符。
(1)判空:
intEmpty(CQueueq)//q是CQueue类型的变量
{if(q.count==0)return
(1);
elsereturn(0);//空队列
}
入队:
intEnQueue(CQueueq,ElemTypex)
{if(q.count==MAX){printf(“队满\n”);exit(0);}
q.base[(q.front+q.count)%MAX]=x;//x入队
q.count++;return
(1);//队列中元素个数增加1,入队成功。
}
出队:
intDelQueue(CQueueq,ElemType&x)
{if(q.count==0){printf(“队空\n”);return(0);}
x=q.base[q.front];
q.front=(q.front+1)%MAX;//计算新的队头指针
q.count--;
return
(1);
}
(2)队列中能容纳的元素的个数为MAX。
第四章:
串
1.串的基本概念C
2.串的顺序表示与实现(两种存储方式)A特别的模式匹配算法之KMP算法B
本章重点:
串的定长顺序存储和堆分配存储、掌握一些常规的串操作(自己会用和会编写)
本章难点:
串的模式匹配快速算法(KMP)
例9.串的定长顺序存储缺点在于存在情况。
截断
例10.已知u=‘xyxyxyxxyxy’;t=‘xxy’;
ASSIGN(s,u);
ASSIGN(v,SUBSTR(s,INDEX(s,t),LEN(t)+1));
ASSIGN(m,‘ww’)
求REPLACE(s,v,m)=________。
‘xyxyxywwy’
例11.14.设字符串S=‘aabaabaabaac',P=‘aabaac'
(1)给出S和P的next值和nextval值;
(2)若S作主串,P作模式串,试给出利用BF算法和KMP算法的匹配过程。
.
(1)
(1)p的next与nextval值分别为012123和002003。
(2)利用BF算法的匹配过程:
第一趟匹配:
aabaabaabaac
aabaac(i=6,j=6)
第二趟匹配:
aabaabaabaac
aa(i=3,j=2)
第三趟匹配:
aabaabaabaac
a(i=3,j=1)
第四趟匹配:
aabaabaabaac
aabaac(i=9,j=6)
第五趟匹配:
aabaabaabaac
aa(i=6,j=2)
第六趟匹配:
aabaabaabaac
a(i=6,j=1)
第七趟匹配:
aabaabaabaac
利用KMP算法的匹配过程:
第一趟匹配:
aabaabaabaac
aabaac(i=6,j=6,nextval(j)=3)
第二趟匹配:
aabaabaabaac
(aa)baac(i=9,j=6)
第三趟匹配:
aabaabaabaac
(成功)(aa)baac(i=13,j=7)
例12.一般串定位函数Index(S,T,pos),设S的串长为n,T的串长为m,则最坏时间复杂度;而改进的Index_KMP(S,T,pos)时间复杂度为。
第五章:
数组和广义表
1.数组的存储结构:
以行为主序、以列为主序的地址映像函数B
2矩阵的压缩存储:
(1)特殊阵:
包括对称阵、三角阵、带状阵(利用其特性压缩存储到一维数组)B
(2)稀疏阵利用的是三元组顺序表来表示B用十字链表表示C(本次考试不做要求)
3.广义表定义与存储表示B(本次考试不做要求)
本章重点:
地址映像函数的计算(包括数组和特殊矩阵)
例13.已知n阶下三角矩阵A(即当i
答:
n阶下三角矩阵元素A[i][j](1<=i,j<=n,i>=j)。
第1列有n个元素,第j列有n-j+1个元素,第1列到第j-1列是等腰梯形,元素数为(n+(n-j+2)(j-1)/2,而aij在第j列上的位置是为i-j+1。
所以n阶下三角矩阵A按列存储,其元素aij在一维数组B中的存储位置k与i和j的关系为:
k=(n+(n-(j-1)+1)(j-1)/2+(i-j+1)=(2n-j)(j-1)/2+i
第六章:
二叉树与树
1.二叉树的定义和性质:
B
几个特殊的二叉树:
满二叉树、完全二叉树、二叉排序树、平衡二叉树B
2.二叉树的顺序存储:
C
3.二叉树的链式存储:
用二叉链表表示与实现A
4.二叉树的遍历:
先(中、后)序遍历及应用,相应递归算法和非递归算法A
5.线索化二叉树(利用二叉链表n+1空指针域来存放某遍历下指向该结点的直接前驱或直接后继,使得蕴含更多信息)B
6.二叉树的应用:
算术表达式,霍夫曼树(最优二叉树),判定树B
7.树的定义和存储表示:
…..B
8.树和森林和二叉树的转换B
9.树与森林的遍历B
★本章重点:
很熟悉二叉树(在二叉链表表示下)的基本操作的递归算法和遍历的非递归算法,请仔细复习。
本章难点:
二叉树(含排序树、平衡树)的递归算法和非递归算法。
线索化二叉树及相应操作,重在理解,不考编程!
例14.引入二叉线索树的目的是()
A.将非线性序列转化成某种线性序列;加快查找结点的前驱或后继的速度
B.为了能在二叉树中方便的进行插入与删除
C.为了能方便的找到双亲D.使二叉树的遍历结果唯一
A
例15.二叉链表在线索化后,仍不能有效求解的问题是()。
A.前(先)序线索二叉树中求前(先)序后继B.中序线索二叉树中求中序后继
C.中序线索二叉树中求中序前驱D.后序线索二叉树中求后序后继
D
例16.在平衡二叉树中插入一个结点后造成了不平衡,设最低的不平衡结点为A,并已知A的左孩子的平衡因子为-1右孩子的平衡因子为0,则应作()型调整以使其平衡。
(平衡因子=左子树深度-右子树深度)
A.LL(单向右旋)B.LR(先左后右双向旋转)
C.RL(先右后左双向旋转)D.RR(单向左旋)
B
例17.一棵非空的二叉树其先序序列和后序序列正好相反,画出这棵二叉树的形状。
先序序列是“根左右”后序序列是“左右根”,可见对任意结点,若至多只有左子女或至多只有右子女,均可使前序序列与后序序列相反,图示如下:
例18:
已知二叉树结点结构如下:
用C语言表示
typedefstructBiNode{
ElemTypedata;
structBiNode*lchild,*rchild;
intval;
}BiNode,*BiTree;
其中val域表示该结点的子孙(含孩子结点)的个数。
开始时,val域值均为0,T为指向某二叉树根结点的指针。
请写算法填写该二叉树中每个结点的val域。
递归算法如下:
intwriteVal(BiNode*root)
{if(root==NULL) root->val=0;
elseif(root->lchild==NULL&&root->rchild==NULL)
root->val=1;
else
root->val=writeVal(root->lchild)+writeVal(root->rchild);
returnroot->val;
}
例19.编写一个算法,将指针S所指的结点插入到根结点指针为T的二叉排序树中,若已存在则不再插入返回0;否则返回1。
(递归的算法见教材)
intInsert_BST(BiTree&T,BiTNodeS)
{BiTreep,q;//p指向当前访问的结点
if(!
T)T=S;
else{p=T;
while(p)
{q=p;//q指向p结点的双亲结点
if(S->data.keydata.key)p=p->lchild;
elseif(S->data.key>p->data.key)p=p->rchild;
elsep=NULL;
}
if(S->data.key==q->data.key)return0;
if(S->data.keydata.key)q->lchild=S;
elseq->rchild=S;
}
return1;
}
例20.编写一个算法,计算平衡二叉树中所有结点的平衡因子
解:
计算一个结点*bt的bf的值递归模型如下:
f(bt):
bt->bf 不存在 当bt==NULL
f(bt):
bt->bf=0当bt->lchild==NULL&&bt->rchild=NULL
f(bt):
bt->bf=bt的右子树的高度-左子树的高度 其它情况
可选用先序的方式统计出各个结点的平衡因子
如何求高度呢?
递归模型如下:
f(bt):
0 不存在 当bt==NULL
f(bt):
1当bt->lchild==NULL&&bt->rchild=NULL
f(bt):
bt的左子树和右子树的高度的最大值+1 其它情况
intHeight(BSTNode*bt){//求树的高度
intmax1,max2;
if(bt==NULL)return0;
elseif(bt->lchild==NULL&&bt->rchild=NULL)return1;
else{
max1=Height(bt->lchild);
max2=Height(bt->rchild);
returnmax1>max2?
max1+1:
max2+1;
}
}
voidCountbf(BSTNode*&bt){//求所有结点的bf
if(bt!
=NULL){
if(bt->lchild==NULL&&bt->rchild=NULL){
bf->bf=0;
}
else{
Countbf(bt->lchild);
Countbf(bt->rchild);
bt->bf=Height(bt->rchild)-Height(bt->lchild);
}
}
}
实质上可以将上面求bf和求高度合二为一。
intCountbf1(BSTNode*&bt){//求所有结点的bf,返回对应结点高度值
intmax1,max2;
if(bt==NULL)return0;
if(bt->lchild==NULL&&bt->rchild=NULL){
bf->bf=0;
return1;
}
else{
max1=Height(bt->lchild);
max2=Height(bt->rchild);
bt->bf=max2-max1;
returnmax1>max2?
max1+1:
max2+1;
}
}
例21.设给出一段报文:
CASTCASTSATATATASA;字符集合是{C,A,S,T},各个字符出现的频度(次数)是W={2,7,4,5};试设计赫夫曼编码,画出赫夫曼树。
若给每个字符以等长编码A:
00T:
10C:
01S:
11;试说明赫夫曼编码比此方案的优越之处。
(编码最短)
解答见ppt
练习
1.设计一个算法,删除该二叉树,释放所有结点
2.设计一算法判断二叉链表存储的二叉树是否结构对称(左右子树结点结构对称相同)
3.试写出复制一棵二叉树的算法。
二叉树采用标准链接结构。
4.习题六 编程(除打星号的部分)
5.设计一个算法,寻找二叉树中满足特定数值x的第一个结点(相应的变形:
寻找最小值,寻找父结点,寻找兄弟)
6.设计一个算法,统计二叉树中满足特定数值x结点的个数(相应的变形:
统计度为0,1,2的结点)
第七章图
1.图的定义、基本概念: