算法与数据结构勘误表.docx
- 文档编号:7438254
- 上传时间:2023-01-24
- 格式:DOCX
- 页数:66
- 大小:249.06KB
算法与数据结构勘误表.docx
《算法与数据结构勘误表.docx》由会员分享,可在线阅读,更多相关《算法与数据结构勘误表.docx(66页珍藏版)》请在冰豆网上搜索。
算法与数据结构勘误表
《算法与数据结构》勘误表
一、目录
原:
1.1《数据结构》的基本概念与学习方法
改为:
1.1《数据结构》的基本概念
二、第一章
1、P1
原:
1.1《数据结构》的基本概念与学习方法
改为:
1.1《数据结构》的基本概念
2、P2
原:
例1.3:
制定教学计划
算法:
各课程间的先后关系
改为:
例1.3:
制定教学计划
算法:
教学计划的制定规则和各课程间的先后关系
3、P3
原:
作为例子,下面根据表1.1构造一些典型的数据结构。
改为:
作为例子,下面根据表1.1构造一些典型的数据结构。
其中,用职工号代表数据元素(职工)
4、P9
原:
算法1.2:
矩阵相加
matrixadd(inta[][n],intb[][n],intc[][n],intn)
改为:
算法1.2:
矩阵相加
matrixadd(inta[][n],intb[][n],intc[][n])
5、P10
原:
程序段5:
voidbubble_sort(inta[],intn)
{
/*将a中整数序列重新排列成自小至大*/
/*有序的整数序列。
*/
for(i=n-1,change=TRUE;i>1&&change;--i)
改为:
程序段5:
voidbubble_sort(inta[],intn)
{
/*将a中整数序列重新排列成自小至大有序的整数序列。
*/
for(i=n-1,change=TRUE;i>0&&change;--i)
6、P10倒数4行
原:
若输入数据所占空间只取决与问题本身,和算法无关,则只需要分析除输入和程序之外的额外空间。
若所需额外空间相对于输入数据量来说是常数,则称此算法为原地工作。
若所需存储量依赖于特定的输入,则通常按最坏情况考虑。
改为:
因为输入数据所占空间只取决与问题本身,和算法无关,所以只需要分析除输入和程序之外的额外空间。
若所需额外空间相对于输入数据量来说是常数,则称此算法为原地工作。
若所需所需额外空间依赖于特定的输入,则通常按最坏情况考虑。
7、P14图1.9
原:
改为:
8、P16图1.10
原:
改为:
9、P16
原:
例如:
int*p1,*p2,a;
p1=&q;p2=p1;/*此时,a既是p1的对象,又是p2的对象*/
改为:
例如:
int*p1,*p2,a;
p1=&a;p2=p1;/*此时,a既是p1的对象,又是p2的对象*/
10、P16
原:
例如:
intA[4],*p;p=A;p++
改为:
例如:
intA[4],*p;
p=A;p++;
11、P18图1.12
原:
改为:
12、P19
原:
2.自定义函数的使用步骤:
根据用户自定义函数的要求,在程序中先要定义一个需完成的功能子函数,然后在主调函数模块中对被调函数进行类型说明,最后才能调用该自定义函数,也就是:
定义、说明、调用,三个步骤。
改为:
2.自定义函数的使用步骤:
根据用户自定义函数的要求,在程序中先要定义一个完成特定功能的子函数,然后在主调函数模块中对被调函数进行类型说明,最后才能调用该自定义函数,也就是:
定义、说明、调用,三个步骤。
13、P20
原:
(3)函数语句:
函数调用作为一个函数的实参。
如:
m=max(a,max(b,c));
改为:
(3)函数参数:
函数调用作为一个函数的实参。
如:
m=max(a,max(b,c));
14、P22图1.15
原:
改为:
15、P25倒数6行
原:
本课程是计算机专业的核心课程之一,不仅有很强的理论性,而且有很强的实践性。
改为:
算法与数据结构这门课程不仅有很强的理论性,而且有很强的实践性。
三、第二章
1、P29
原:
⒉⒈2线性表的运算
对线性表可进行的运算种类繁多,在实际应用中,当线性表作为一个操作对象时,所需进行的操作种类不一定相同,不同的操作集合将构成不同的抽象数据类型。
改为:
⒉⒈2线性表的运算
2、P32算法2.2
原:
算法2.2:
intinsert(sqlist*L,inti,elemtypex)
/*L为sqlist顺序表类型指针变量,i为插入元素的位序号,x为插入元素的值*/
{intj;
if((*L).len=maxlen)/*判断线性表的存储空间是否已满*/
{printf(“溢出!
/n”);
return0;
}
else
if((i<1)||i>(*L).len+1))/*检查i值是否超出所允许的范围*/
{printf(“插入位置不正确/n”);
return0;
}
else
{for(j=(*L).len-1;j=i-1;j--)
/*将第i个元素和它后面的所有元素均后移一个位置*/
(*L).v[j+1]=(*L).v[j];
(*L).v[i-1]=x;/*将新的元素写入到空出的下标为i-1的位置上*/
(*L).len=(*L).len+1;/*线性表的长度增加1*/
Return
(1);
}
}
改为:
算法2.2:
intinsert(sqlist*L,inti,elemtypex)
/*L为sqlist顺序表类型指针变量,i为插入元素的位序号,x为插入元素的值*/
{intj;
if((*L).len==maxlen)/*判断线性表的存储空间是否已满*/
{printf(“溢出!
/n”);
return0;
}
else
if((i<1)||i>(*L).len+1))/*检查i值是否超出所允许的范围*/
{printf(“插入位置不正确/n”);
return0;
}
else
{for(j=(*L).len-1;j>=i-1;j--)
/*将第i个元素和它后面的所有元素均后移一个位置*/
(*L).v[j+1]=(*L).v[j];
(*L).v[i-1]=x;/*将新的元素写入到空出的下标为i-1的位置上*/
(*L).len=(*L).len+1;/*线性表的长度增加1*/
Return
(1);
}
}
3、P34算法2.3
原:
算法2.3:
intdelete(sqlist*L,inti,elemtype*y)
/*L为sqlist顺序表类型指针变量,i为删除元素的位序号,删除元素的值通过y代出*/
{intj;
if((i<1)||(i>(*L).len))/*判断i值是否超出所允许的范围*/
{printf(“删除位置不正确/n”);
return(0);
}
else
{*y=(*L).v[i-1];/*把第i个元素赋给*y*/
for(j=i;j<(*L).len;j++)
/*把第i个元素后的所有元素依次向前移动一个位置*/
((*L).v[j-1]=(*L).v[j];
(*L).len=(*L).len-1;/*线性表长度减1*/
return
(1);
}
}
改为:
算法2.3:
intdelete(sqlist*L,inti,elemtype*y)
/*L为sqlist顺序表类型指针变量,i为删除元素的位序号,删除元素的值通过y代出*/
{intj;
if((i<1)||(i>(*L).len))/*判断i值是否超出所允许的范围*/
{printf(“删除位置不正确/n”);
return(0);
}
else
{*y=(*L).v[i-1];/*把第i个元素赋给*y*/
for(j=i;j<(*L).len;j++)
/*把第i个元素后的所有元素依次向前移动一个位置*/
(*L).v[j-1]=(*L).v[j];
(*L).len=(*L).len-1;/*线性表长度减1*/
return
(1);
}
}
4、P37算法2.5:
原:
算法2.5:
typedefcharelemtype;/*指定elemtype为char类型*/
Lnodecreat()/*表头插入法,建立单链表,通过函数返回头指针*/
{lnode*h,*p;
elemtypex;
h=(lnode*)mallod(sizeof(lnode));/*建立一个头结点*/
h->next=NULL;/*使头结点的指针域为空*/
while(ch=getchar())!
=‘\n’)
{p=(lnode*)mallod(sizeof(lnode));/*建立一个新结点p*/
p->data=ch;/*将ch赋给p的数据域*/
p->next=h->next;/*改变指针状况*/
h->next=p;/*h的直接后继是p*/
}
return(h);
}
改为:
算法2.5:
typedefcharelemtype;/*指定elemtype为char类型*/
Lnode*creat()/*表头插入法,建立单链表,通过函数返回头指针*/
{Lnode*h,*p;
elemtypex;
h=(Lnode*)malloc(sizeof(Lnode));/*建立一个头结点*/
h->next=NULL;/*使头结点的指针域为空*/
while((ch=getchar())!
=‘\n’)
{p=(Lnode*)malloc(sizeof(Lnode));/*建立一个新结点p*/
p->data=ch;/*将ch赋给p的数据域*/
p->next=h->next;/*改变指针状况*/
h->next=p;/*h的直接后继是p*/
}
return(h);
}
5、P38算法2.6:
原:
算法2.6:
typedefcharelemtype;
Lnode*creat()/*表尾插入法,建立单链表,通过函数返回头指针*/
{lnode*h,*p,*t;
elemtypex;
h=(lnode*)mallod(sizeof(lnode));
h->next=NULL;
t=h;
while(ch=getchar())!
=’\n’)
{p=(lnode*)mallod(sizeof(lnode));
p->data=ch;
p->next=NULL;
t->next=p;
t=p;/*t始终指向最后一个元素*/
}
return(h);
}
改为:
算法2.6:
typedefcharelemtype;
Lnode*creat()/*表尾插入法,建立单链表,通过函数返回头指针*/
{lnode*h,*p,*t;
elemtypex;
h=(Lnode*)malloc(sizeof(Lnode));
h->next=NULL;
t=h;
while((ch=getchar())!
=’\n’)
{p=(Lnode*)malloc(sizeof(Lnode));
p->data=ch;
p->next=NULL;
t->next=p;
t=p;/*t始终指向最后一个元素*/
}
return(h);
}
6、P47图2.20
原:
(a)以列序为主序;(b)以行序为主序
图2.20二维数组的两种存储方式
改为:
(a)以行序为主序;(b)以列序为主序
图2.20二维数组的两种存储方式
7、P48
原:
改为:
8、P51算法2.16
原:
算法2.16:
matzzjz(mat*a)
{intam.bn.col;
mat*b;/*转置后的矩阵b*/
b=(mat)malloc(sizeof(mat));
b.nu=a.mu;b.mu=a.nu;b.tu=a.tu;/*a,b矩阵行、列交换*/
bn=0;
for(col=1;col<=a.nu;col++)/*按a的列序转置*/
for(am=1;am<=a.tu;am++)/*扫描整个三元组表*/
if(a.data[am].j==col)/*列号为col是转置*/
{b.data[bn].i=a.data[am].j;
b.data[bn].j=a.data[am].i;
b.data[bn].v=a.data[am].v;
bn++;/*b.data中的结点序号加1*/
}
returnb;/*返回转置矩阵的指针*/
}
该算法的主要耗费时间是在col和am的两重循环中,所以算法的时间复杂度为O(nu.tu),(nu表示a.nu,tu表示a.tu),即和A的列数与非零元素的个数的乘积成正比。
改为:
算法2.16:
mat*zzjz(mat*a)
{intam,bn,col;
mat*b;/*转置后的矩阵b*/
b=(mat)malloc(sizeof(mat));
b.nu=a.mu;b.mu=a.nu;b.tu=a.tu;/*a,b矩阵行、列交换*/
bn=1;
for(col=1;col<=a.nu;col++)/*按a的列序转置*/
for(am=1;am<=a.tu;am++)/*扫描整个三元组表*/
if(a.data[am].j==col)/*列号为col是转置*/
{b.data[bn].i=a.data[am].j;
b.data[bn].j=a.data[am].i;
b.data[bn].v=a.data[am].v;
bn++;/*b.data中的结点序号加1*/
}
returnb;/*返回转置矩阵的指针*/
}
该算法的主要耗费时间是在col和am的两重循环中,所以算法的时间复杂度为O(nu*tu),(nu表示a.nu,tu表示a.tu),即和A的列数与非零元素的个数的乘积成正比。
9、P51
原:
2.行逻辑链接的顺序表
行逻辑链接的顺序表这种表示方法对实现两个矩阵相乘具有优越性。
矩阵的乘法,即矩阵C=A×B,其中有Am1×n1,Bm2×n2,当n1=m2时
Cm1×n2=Am1×n1×Bm2×n2
矩阵乘法的定义为:
1≤i≤m1,1≤j≤n2
其经典算法是:
for(i=1;i<=m1;++i)
for(j=1;j<=n2;++j)
{c[i][j]=0;
for(k=1;k<=n1;++k)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
}
此算法的时间复杂度为O(m1*n1*n2)。
在经典算法中,不论aik和bkj的值是否为零都要作一次乘法。
在稀疏矩阵的乘法中,零元素较多,为了避免这种无效操作,可以利用三元组表作为稀疏矩阵的存储结构。
这样,就不能套用以上的经典算法。
关于稀疏矩阵的乘法请大家参考有关资料进一步理解。
改为:
2.行逻辑链接的顺序表
为了方便某些矩阵运算,常常在按行优先存储的三元组表中,加入一个行表来记录稀疏矩阵中美行的非零元素在三元组表中的起始位置。
当将行表作为三元组表的一个新增属性加以描述时,我们就得到了稀疏矩阵的另一个顺序存储结构:
行逻辑链接的顺序表。
其类型描述为:
#defineMAX<最大可能的非零元素个数>+1
#defineMAXROW<最大可能的稀疏矩阵行数>+1
typedefstruct
{inti,j;
elemtypev;
}node;
typedefstruct
{intmu,nu,tu;
nodedata[MAX];
intrpot[MAXROW];/*行表,应保证mu<=MAXROW*/
}matrow;
显然有:
行逻辑链接的顺序表这种表示方法对实现两个矩阵相乘具有优越性。
关于稀疏矩阵的乘法请大家参考有关资料进一步理解。
10、P52图2.27
原:
改为:
11、P56
原:
算法2.20:
Lnode*hb(Lnode*pa,Lnode*pb)
改为:
算法2.20:
Lnode*hb(Lnode*pa,Lnode*pb)/*pa,pb为不带头结点的单链表头指针*/
12、P57
原:
一个一元多项式用一个带头结点的单链表来表示,每个结点表示多项式的一项,由三个域组成:
系数域、指数域、指针域。
结点类型定义如下:
typedefstructnode
{intcoef,exp;
structnode*next;
}JD;
coef为系数域;exp为指数域;JD为结点类型名。
改为:
一个一元多项式用一个带头结点的单链表来表示,每个结点表示多项式的一项,由三个域组成:
系数域、指数域、指针域。
增加指数域可以解决因指数不连续、变化大等原因而浪费空间的问题。
结点类型定义如下:
typedefstructnode
{intcoef,exp;
structnode*next;
}JD;
coef为系数域;exp为指数域,且链表中exp指数域的值递增;JD为结点类型名。
四、第三章
1、P62
原:
栈的基本操作除了在栈顶进行插入或删除外,还有栈的初始化、判空及读栈顶元素等。
下面给出栈的抽象数据类型的定义:
规格说明⒊1ADTStack
数据元素可以是各种类型的元素,只要同属一个数据对象即可;
结构数据元素之间呈线性关系。
假设栈中有n个元素(a1,a2,...,an),则对每一个元素ai(i=1,2,...,n-1)都存在关系
操作
INISTACK(S)初始化操作。
设置一个空栈S。
EMPTY(S)判栈空函数。
若S为空栈,函数值为“true”,否则为“false”。
SIZE(S)求栈深函数。
函数值为栈中当前的元素个数。
TOP(S)读栈顶元函数。
若栈S不空,函数值为栈顶元素,否则为空元素NULL。
PUSH(S,x)进栈操作。
将元素x插入栈S中,使x成为栈S的栈顶元素。
POP(S)出栈函数。
若栈S不空,函数值为栈顶元素,且从栈中删除当前栈顶元素,否则函数值为空元素NULL。
CLEAR(S)栈置空操作。
不论栈S是否为空栈,将S置为空栈。
我们建议读者按照规格说明⒊1将栈的抽象数据类型设计成为单元(UNIT),便于后面的使用。
栈的数据元素类型可以在调用过程内定义。
这里我们先看一个简单的栈的应用的例子。
改为:
栈的基本操作:
INISTACK(S)初始化操作。
设置一个空栈S。
EMPTY(S)判栈空函数。
若S为空栈,函数值为1,否则为0。
SIZE(S)求栈深函数。
函数值为栈中当前的元素个数。
TOP(S)读栈顶元函数。
若栈S不空,函数值为栈顶元素,否则为空元素NULL。
PUSH(S,x)进栈操作。
将元素x插入栈S中,使x成为栈S的栈顶元素。
POP(S)出栈函数。
若栈S不空,函数值为栈顶元素,且从栈中删除当前栈顶元素,否则函数值为空元素NULL。
CLEAR(S)栈置空操作。
不论栈S是否为空栈,将S置为空栈。
这里我们先看一个简单的栈的应用的例子。
2、P62
原:
由题意可知,我们可以用一个栈来保存所有的余数,当商为0时则让栈里的所有余数出栈则可以得到正确的二进制数,算法可描述如下:
voidconversion(){
StackS;
intn;
InitStack(&S);
printf("Inputanumbertoconvert:
\n");
scanf("%d",&n);
if(n<0){
printf("\nThenumbermustbeover0.");
return;
}
if(n==0)Push(S,0);
while(n!
=0){
Push(S,n%2);
n=n/2;
}
printf("theresultis:
");
while(!
StackEmpty(*S)){
printf("%d",Pop(S));
}
}
}
改为:
由题意可知,我们可以用一个栈来保存所有的余数,当商为0时则让栈里的所有余数出栈则可以得到正确的二进制数。
利用上述栈的基本操作,十进制转换为二进制的算法可描述如下:
voidconversion(){
StackS;
intn;
InitStack(S);
printf("Inputanumbertoconvert:
\n");
scanf("%d",&n);
if(n<0){
printf("\nThenumbermustbeover0.");
return;
}
if(n==0)Push(S,0);
while(n!
=0){
Push(S,n%2);
n=n/2;
}
printf("theresultis:
");
while(!
StackEmpty(S)){
printf("%d",Pop(S));
}
}
}
3、P63
原:
由栈的定义以及栈的实例,我们很容易想到用一个数组或类似的结构来存出它。
栈的顺序存储结构,简称顺序栈(sequentialstack)。
它是利用一组地址连续的存储单元依次存放从栈底到栈顶的数据元素,通常用一维数组存放栈的元素。
同时设“指针”top指示栈顶元素的当前位置。
(注意,top并不是指针型变量,只是整型变量,它指示栈顶元素在数组中的位置)。
空栈的top值为零。
在C语言中,顺序栈的类型说明如下:
typedefstruct{
intmaxsize;
elemtpelem[maxsize];
inttop;
}sqstacktp
设s为sqstacktp型变量,即s表示一个顺序栈。
图⒊2说明了这个顺序栈的几种状态。
(a)表示顺序栈为栈空,s.top=0;(b)表示栈中只含一个元素A,s.top=1,在(a)的基础上用进栈操作PUSH(s,A)可以得到这种状态;(c)表示在(b)的基础上将元素B、C依次进栈后的状态,s.top=3;(d)表示在(c)状态下将元素C退栈后的情况,s.top=2,由执行一次POP(s)得到;(e)表示栈中有五个元素,s.top=maxsize-1,这种状态称为栈满,此时若有元素进栈则将产生“数组越界”的错误,称为栈上溢。
(a)(b)(c)(d)(e)
图⒊2顺序栈的几种状态
因此,s.top=0表示空栈,出栈和读栈顶元之前应判断栈是否为空。
s.top=maxsize-1表示栈满,进栈之前应判断是否栈满。
改为:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 数据结构 勘误表
![提示](https://static.bdocx.com/images/bang_tan.gif)