}
a[i]=t;∥将原第一元素放到最终位置。
}
[算法讨论]本算法时间复杂度为O(n)。
算法只是按题目要求把正负数分开,如要求统计负数和大于等于零的个数,则最后以t来定。
如t为负数,则0至i共i+1个负数,n-1-i个正数(包括零)。
另外,题目并未提及零的问题,笔者将零放到正数一边。
对此问题的扩充是若元素包含正数、负数和零,并要求按负数、零、正数的顺序重排线性表,统计负数、零、正数的个数。
第3章栈和队列
1.假设以数组A[m]存放循环队列的元素,其头尾指针分别为front和rear,则当前队列中的元素个数为()。
A.(rear-front+m)%mB.rear-front+1C.(front-rear+m)%mD.(rear-front)%m
2.若用一个大小为6的数组来实现循环队列,且当前rear和front的值分别为0和3,当从队列中删除一个元素,再加入两个元素后,rear和front的值分别为多少?
()
A.1和5B.2和4C.4和2D.5和1
3.栈的特点是(①),队列的特点是(②),栈和队列都是(③)。
若进栈序列为1,2,3,4则(④)不可能是一个出栈序列(不一定全部进栈后再出栈);若进队列的序列为1,2,3,4则(⑤)是一个出队列序列。
①,②:
A.先进先出B.后进先出C.进优于出D.出优于进
③:
A.顺序存储的线性结构B.链式存储的线性结构
C.限制存取点的线性结构D.限制存取点的非线性结构
④,⑤:
A.3,2,1,4B.3,2,4,1C.4,2,3,1D.4,3,2,1F.1,2,3,4G.1,3,2,4
4.算术表达式求值的流程,其中OPTR为算术符栈,OPND为操作数栈,precede(oper1,oper2)是比较运算符优先级别的函数,operate(opnd1,oper,opnd2)为两操作数的运算结果函数。
(#表示运算起始和终止符号)
FUNCTIONexp_reduced:
operandtype;
INITSTACK(OPTR);PUSH(OPTR"#");INITSTACK(OPND);read(w);
WHILENOT((w='#’)AND(GETTOP(OPTR)='#'))DO
IFNOTwinopTHENPUSH(OPND,w);
ELSECASEprecede(GETTOP(OPTR),w)OF
'<':
[
(1)_______;read(w);]
'=':
[
(2)_______;read(w);];
'>':
[theta:
=POP(OPTR);b:
=POP(OPND);a:
=POP(OPND);(3)_______;]
ENDC;
RETURN(GETTOP(OPND));
ENDF;
作业
1.如果用一个循环数组q[0..m-1]表示队列时,该队列只有一个队列头指针front,不设队列尾指针rear,而改置计数器count用以记录队列中结点的个数。
(1)编写实现队列的三个基本运算:
判空、入队、出队
(2)队列中能容纳元素的最多个数是多少?
2.设表达式以字符形式已存入数组E[n]中,‘#’为表达式的结束符,试写出判断表达式中括号(‘(’和‘)’)是否配对的C语言描述算法:
EXYX(E);(注:
算法中可调用栈操作的基本算法。
)
3.请利用两个栈S1和S2来模拟一个队列。
已知栈的三个运算定义如下:
PUSH(ST,x):
元素x入ST栈;POP(ST,x):
ST栈顶元素出栈,赋给变量x;Sempty(ST):
判ST栈是否为空。
那么如何利用栈的运算来实现该队列的三个运算:
enqueue:
插入一个元素入队列;dequeue:
删除一个元素出队列;queue_empty:
判队列为空。
(请写明算法的思想及必要的注释)
答案:
1.typedefstruct
{elemtpq[m];
intfront,count;//front是队首指针,count是队列中元素个数。
}cqnode;//定义类型标识符。
(1)判空:
intEmpty(cqnodecq)//cq是cqnode类型的变量
{if(cq.count==0)return
(1);elsereturn(0);//空队列}
入队:
intEnQueue(cqnodecq,elemtpx)
{if(count==m){printf(“队满\n”);exit(0);}
cq.q[(cq.front+count)%m]=x;//x入队
count++;return
(1);//队列中元素个数增加1,入队成功。
}
出队:
intDelQueue(cqnodecq)
{if(count==0){printf(“队空\n”);return(0);}
printf(“出队元素”,cq.q[cq.front]);
x=cq.q[cq.front];
cq.front=(cq.front+1)%m;//计算新的队头指针。
return(x)
}
(2)队列中能容纳的元素的个数为m。
队头指针front指向队头元素。
2.[题目分析]判断表达式中括号是否匹配,可通过栈,简单说是左括号时进栈,右括号时退栈。
退栈时,若栈顶元素是左括号,则新读入的右括号与栈顶左括号就可消去。
如此下去,输入表达式结束时,栈为空则正确,否则括号不匹配。
intEXYX(charE[],intn)
//E[]是有n字符的字符数组,存放字符串表达式,以‘#’结束。
本算法判断表达式中圆括号是否匹配。
{chars[30];//s是一维数组,容量足够大,用作存放括号的栈。
inttop=0;//top用作栈顶指针。
s[top]=‘#’;//‘#’先入栈,用于和表达式结束符号‘#’匹配。
inti=0;//字符数组E的工作指针。
while(E[i]!
=‘#’)//逐字符处理字符表达式的数组。
switch(E[i])
{case‘(’:
s[++top]=‘(’;i++;break;
case‘)’:
if(s[top]==‘(’{top--;i++;break;}
else{printf(“括号不配对”);exit(0);}
case‘#’:
if(s[top]==‘#’){printf(“括号配对\n”);return
(1);}
else{printf(“括号不配对\n”);return(0);}//括号不配对
default:
i++;//读入其它字符,不作处理。
}
}//算法结束。
[算法讨论]本题是用栈判断括号匹配的特例:
只检查圆括号的配对。
一般情况是检查花括号(‘{’,‘}’)、方括号(‘[’,‘]’)和圆括号(‘(’,‘)’)的配对问题。
编写算法中如遇左括号(‘{’,‘[’,或‘(’)就压入栈中,如遇右括号(‘}’,‘]’,或‘)’),则与栈顶元素比较,如是与其配对的括号(左花括号,左方括号或左圆括号),则弹出栈顶元素;否则,就结论括号不配对。
在读入表达式结束符‘#’时,栈中若应只剩‘#’,表示括号全部配对成功;否则表示括号不匹配。
另外,由于本题只是检查括号是否匹配,故对从表达式中读入的不是括号的那些字符,一律未作处理。
再有,假设栈容量足够大,因此入栈时未判断溢出。
3.[题目分析]栈的特点是后进先出,队列的特点是先进先出。
所以,用两个栈s1和s2模拟一个队列时,s1作输入栈,逐个元素压栈,以此模拟队列元素的入队。
当需要出队时,将栈s1退栈并逐个压入栈s2中,s1中最先入栈的元素,在s2中处于栈顶。
s2退栈,相当于队列的出队,实现了先进先出。
显然,只有栈s2为空且s1也为空,才算是队列空。
(1)intenqueue(stacks1,elemtpx)
//s1是容量为n的栈,栈中元素类型是elemtp。
本算法将x入栈,若入栈成功返回1,否则返回0。
{if(top1==n&&!
Sempty(s2))//top1是栈s1的栈顶指针,是全局变量。
{printf(“栈满”);return(0);}//s1满s2非空,这时s1不能再入栈。
if(top1==n&&Sempty(s2))//若s2为空,先将s1退栈,元素再压栈到s2。
{while(!
Sempty(s1)){POP(s1,x);PUSH(s2,x);}
PUSH(s1,x);return
(1);//x入栈,实现了队列元素的入队。
}
(2)voiddequeue(stacks2,s1)
//s2是输出栈,本算法将s2栈顶元素退栈,实现队列元素的出队。
{if(!
Sempty(s2))//栈s2不空,则直接出队。
{POP(s2,x);printf(“出队元素为”,x);}
else//处理s2空栈。
if(Sempty(s1)){printf(“队列空”);exit(0);}//若输入栈也为空,则判定队空。
else//先将栈s1倒入s2中,再作出队操作。
{while(!
Sempty(s1)){POP(s1,x);PUSH(s2,x);}
POP(s2,x);//s2退栈相当队列出队。
printf(“出队元素”,x);
}
}//结束算法dequue。
(3)intqueue_empty()
//本算法判用栈s1和s2模拟的队列是否为空。
{if(Sempty(s1)&&Sempty(s2))return
(1);//队列空。
elsereturn(0);//队列不空。
}
[算法讨论]算法中假定栈s1和栈s2容量相同。
出队从栈s2出,当s2为空时,若s1不空,则将s1倒入s2再出栈。
入队在s1,当s1满后,若s2空,则将s1倒入s2,之后再入队。
因此队列的容量为两栈容量之和。
元素从栈s1倒入s2,必须在s2空的情况下才能进行,即在要求出队操作时,若s2空,则不论s1元素多少(只要不空),就要全部倒入s2中。
第5章数组和广义表
1.稀疏矩阵压缩存储后,必会失去随机存取功能。
()
2.数组是同类型值的集合。
()
3.数组可看成线性结构的一种推广,因此与线性表一样,可以对它进行插入,删除等操作。
()
4.一个稀疏矩阵Am*n采用三元组形式表示,若把三元组中有关行下标与列下标的值互换,并把m和n的值互换,则就完成了Am*n的转置运算。
()
5.二维以上的数组其实是一种特殊的广义表。
()
6.广义表的取表尾运算,其结果通常是个表,但有时也可是个单元素值。
()
7.若一个广义表的表头为空表,则此广义表亦为空表。
()
8.广义表中的元素或者是一个不可分割的原子,或者是一个非空的广义表。
()
9.所谓取广义表的表尾就是返回广义表中最后一个元素。
()
10.一个广义表可以为其它广义表所共享。
()
11.设二维数组A[-20..30,-30..20],每个元素占有4个存储单元,存储起始地址为200.如按行优先顺序存储,则元素A[25,18]的存储地址为__
(1)_;如按列优先顺序存储,则元素A[-18,-25]的存储地址为__
(2)_。
12.已知二维数组A[1..10,0..9]中每个元素占4个单元,在按行优先方式将其存储到起始地址为1000的连续存储区域时,A[5,9]的地址是:
_______。
13.设数组A[0..8,1..10],数组中任一元素A[i,j]均占内存48个二进制位,从首地址2000开始连续存放在主内存里,主内存字长为16位,那么
(l)存放该数组至少需要的单元数是_______;
(2)存放数组的第8列的所有元素至少需要的单元数是_______;
(3)数组按列存储时,元素A[5,8]的起始地址是_______。
答案:
1.对
2.错误。
数组是具有相同性质的数据元素的集合,数据元素不仅有值,还有下标。
因此,可以说数祖是元素值和下标构成的偶对的有穷集合。
3.错误。
数组在维数和界偶确定后,其元素个数已经确定,不能进行插入和删除运算。
4.错误。
稀疏矩阵转置后,除行列下标及行列数互换外,还必须确定该元素转置后在新三元组中的位置。
5.对
6.错误。
广义表的取表尾运算,是非空广义表除去表头元素,剩余元素组成的表,不可能是原子。
7.错误。
广义表的表头就是广义表的第一个元素。
只有非空广义表才能取表头。
8.错误。
广义表中元素可以是原子,也可以是表(包括空表和非空表)。
9.错误。
广义表的表尾,指去掉表头元素后,剩余元素所组成的表。
10.对
11.
(1)9572
(2)1228
12.1196
13.
(1)270
(2)27(3)2204
第6章树和二叉树
1.一棵树高为K的完全二叉树至少有()个结点。
A.2k–1B.2k-1–1C.2k-1D.2k
2.对二叉树的结点从1开始进行连续编号,要求每个结点的编号大于其左、右孩子的编号,同一结点的左右孩子中,其左孩子的编号小于其右孩子的编号,可采用()次序的遍历实现编号。
A.先序B.中序C.后序
D.从根开始按层次遍历
3.在下列存储形式中,哪一个不是树的存储形式?
()
A.双亲表示法B.孩子链表表示法
C.孩子兄弟表示法D.顺序存储表示法
4.二叉树的先序遍历和中序遍历如下:
先序遍历:
EFHIGJK;中序遍历:
H