数据结构习题与解答.docx

上传人:b****1 文档编号:15179824 上传时间:2023-07-02 格式:DOCX 页数:34 大小:226.85KB
下载 相关 举报
数据结构习题与解答.docx_第1页
第1页 / 共34页
数据结构习题与解答.docx_第2页
第2页 / 共34页
数据结构习题与解答.docx_第3页
第3页 / 共34页
数据结构习题与解答.docx_第4页
第4页 / 共34页
数据结构习题与解答.docx_第5页
第5页 / 共34页
数据结构习题与解答.docx_第6页
第6页 / 共34页
数据结构习题与解答.docx_第7页
第7页 / 共34页
数据结构习题与解答.docx_第8页
第8页 / 共34页
数据结构习题与解答.docx_第9页
第9页 / 共34页
数据结构习题与解答.docx_第10页
第10页 / 共34页
数据结构习题与解答.docx_第11页
第11页 / 共34页
数据结构习题与解答.docx_第12页
第12页 / 共34页
数据结构习题与解答.docx_第13页
第13页 / 共34页
数据结构习题与解答.docx_第14页
第14页 / 共34页
数据结构习题与解答.docx_第15页
第15页 / 共34页
数据结构习题与解答.docx_第16页
第16页 / 共34页
数据结构习题与解答.docx_第17页
第17页 / 共34页
数据结构习题与解答.docx_第18页
第18页 / 共34页
数据结构习题与解答.docx_第19页
第19页 / 共34页
数据结构习题与解答.docx_第20页
第20页 / 共34页
亲,该文档总共34页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

数据结构习题与解答.docx

《数据结构习题与解答.docx》由会员分享,可在线阅读,更多相关《数据结构习题与解答.docx(34页珍藏版)》请在冰点文库上搜索。

数据结构习题与解答.docx

数据结构习题与解答

数据结构习题与解答

0.1编写冒泡排序算法,使结果从大到小排列。

voidBubbleSortDec(DataTypea[],intn)

{

for(i=0;i

change=false;

for(j=0;j

if(a[j]

swap(a[j],a[j+1]);

change=true;

}

if(notchange)break;//没有交换则完成排序

}

}

0.2计算下面语句段中指定语句的频度:

1)for(i=1;i<=n;i++)

for(j=i;j<=n;j++)

x++;//@

2)i=1;

while(i<=n)

i=i*2;//@

分析:

计算语句频度是计算时间复杂度的基础。

可以用观察和归纳进行简单的计算。

1)问题规模n执行次数

11

22+1

33+2+1

......

nn+...+2+1=n(n+1)/2

结论:

语句频度为n(n+1)/2。

2)问题规模n执行次数

11

22

32

43

......

2kk+1

结论:

语句频度为

0.1将顺序表中的元素反转顺序。

voidReverse(SqList&L)

{

for(i=0;i

<还是<=

L.elem[i]L.elem[L.length-i-1];

}

0.2在非递减有序的顺序表中插入元素x,并保持有序。

思路1:

先查找适合插入的位置i

向后移动元素(从后向前处理)

插入元素,表长加1

思路2:

从后向前查找插入位置,同时向后移动大于x的元素

插入元素,表长加1

注意:

表满时不能插入。

//顺序表结构

constintMAXSIZE=1024;

typedefstruct{

DataTypeelem[MAXSIZE];

intlength;

}SqList;

//向非递减有序的顺序表L中插入元素x,仍保持非递减有序

//插入成功返回true,否则返回false

boolOrderListInsert(SqList&L,DataTypex)

{

if(L.length==MAXSIZE)returnfalse;//表满,插入失败

//将大于x的元素后移

for(i=L.length-1;i>=0&&L.elem[i]>x;i--)

L.elem[i+1]=L.elem[i];

//插入x(因为最后执行i--,故应在i+1处)

L.elem[i+1]=x;

L.length++;

returntrue;

}

0.3删除顺序表中所有等于x的元素。

voidRemove(SqList&L,DataTypex)

{

i=0;//剩余元素个数,同时是下一个元素的插入位置

for(j=0;j

if(L.elem[j]!

=x){//复制不等于x的元素组成新表

if(i!

=j)L.elem[i]=L.elem[j];//当i==j时不必复制

i++;

}

L.length=i;//剩余元素个数

}

本算法的时间复杂度为O(n);若改用反复调用查找和删除算法,时间复杂度会达到O(n2)。

0.4编写算法实现顺序表元素唯一化(即使顺序表中重复的元素只保留一个),给出算法的时间复杂度。

思路:

设已经唯一化的序列是(a0,…,ai-1),剩余序列是(aj,…,an)。

所要做的就是在已经唯一化的序列L.elem[0..i-1]中查找L.elem[j],如果未找到则复制到L.elem[i]处。

如此重复直到剩余序列为空。

voidUnique(SqList&L)

{

if(L.length<=1)return;//空表或只有一个元素的表已经唯一化了

i=1;//开始L.elem[0..0]是唯一化序列

for(j=1;j

//在L.elem[0..i-1]中查找L.elem[j]

for(k=0;k

if(L.elem[k]==L.elem[j])break;

if(k==i){//L.elem[j]未出现过,复制到L.elem[i]处

if(j!

=i)L.elem[i]=L.elem[j];

i++;

}

}

L.length=i;//表长为i

}

以上算法的时间复杂度为O(n2)。

当然,可以反复将重复元素删除达到唯一化,时间复杂度仍是O(n2),但是与以上算法相比要移动更多元素。

0.5非递减有序的顺序表元素唯一化(参见习题0.4),要求算法的时间复杂度为O(n)。

分析:

由于该表是有序的,相等的元素必然靠在一起,不必从头开始查找,所以算法的时间复杂度可以降低。

思路:

类似习题0.4,但是查找部分只要与L.elem[i-1]比较就可以了。

voidUnique(SqList&L)

{

i=0;//开始的唯一化序列为空(

对比习题0.4思考为什么不用i=1开始)

for(j=1;j

if(L.elem[j]!

=L.elem[i-1]){//Note:

写成L.elem[j]!

=L.elem[j-1]亦可

if(j!

=i)L.elem[i]=L.elem[j];

i++;

}

L.length=i;//表长

}

0.6将单链表就地逆置,即不另外开辟结点空间,而将链表元素翻转顺序。

思路:

从链上依次取下结点,按照逆序建表的方法(参见2.000节)重新建表。

voidReverse(LinkList&L)

{

p=L->next;//原链表

L->next=NULL;//新表(空表)

while(p){

//从原链表中取下结点s

s=p;

p=p->next;

//插入L新表表头

s->next=L->next;

L->next=s;

}

}

0.7采用插入法将单链表中的元素排序。

voidInsertionSort(LinkList&L)

{

h=L->next;//原链表

L->next=NULL;//新空表

while(h){

//从原链表中取下结点s

s=h;h=h->next;

//在新表中查找插入位置

p=L;

while(p->next&&p->next->data<=s->data)

p=p->next;

//在p之后插入s

s->next=p->next;

p->next=s;

}

}

0.8采用选择法将单链表中的元素排序。

voidSelectionSort(LinkList&L)

{

p=L;

while(p->next){

//选择最小(从p->next至表尾)

q=p;//最小元素的前驱q

s=p;

while(s->next){

if(s->next->datanext->data)q=s;

s=s->next;

}

m=q->next;//找到最小m

//最小元素m插入有序序列末尾(p之后)

if(q!

=p){

q->next=m->next;//解下最小m

m->next=p->next;//插入p之后

p->next=m;

}

p=p->next;//L->next至p为有序序列

}

}

0.9将两个非递减有序的单链表归并成一个,仍并保持非递减有序。

//将非递减有序的单链表lb合并入la,保持非递减有序

//结果la中含有两个链表中所有元素,lb为空表

voidMerge(LinkList&la,LinkList&lb)

{

p=la,q=lb;

while(p->nextandq->next){

//跳过la中较小的元素

while(p->nextand(p->next->data<=q->next->data))

p=p->next;

//把lb中较小的元素插入la中

while(p->nextandq->nextand(q->next->datanext->data)){

s=q->next;

q->next=s->next;

s->next=p->next;

p->next=s;

p=s;

}

}

if(lb->next){//表lb剩余部分插入la末尾

p->next=lb->next;

lb->next=NULL;

}

}

0.1元素1,2,3,4依次入栈,不可能的出栈序列有哪些?

分析:

什么是不可能的出栈序列?

如果后入栈的数(如4)先出栈,则此前入栈元素(如1,2,3)在栈中的顺序就确定了,它们的出栈顺序一定是逆序(如3,2,1),否则就是不可能的出栈序列(如2,1,3)。

不可能的出栈序列有:

4123,4132,4213,4231,4312,3412,3142,3124。

其中后3种都含312这一不可能序列。

0.2设循环队列Q少用一个元素区分队列空和队列满,MAXSIZE=5,Q.front=Q.rear=0,画出执行下列操作时队列空和队列满的状态。

入队列a,b,c,出队列a,b,c,入队列d,e,f,g。

[fa][r][][][][fa][b][r][][][fa][b][c][r][][][fb][c][r][][][][fc][r][][][][][fr][]队列空

...[f][r][][fd][e][f][g][r][fd][e]队列满。

0.3编写算法利用栈将队列中的元素翻转顺序。

思路:

先将队列中的元素入栈,然后从栈中取出重新入队列。

voidReverse(SqQueue&Q)

{

InitStack(S);

while(!

QueueEmpty(Q)){

DeQueue(Q,x);Push(S,x);

}

while(!

StackEmpty(S)){

Pop(S,x);EnQueue(Q,x);

}

}

0.1长度为n的串的子串最多有多少个?

思路:

对子串长度归纳。

子串的长度是0,1,2,...,n,对应子串的个数分别是1(空串),n,n-1,...,1,总起来就是1+n+(n-1)+...+2+1=1+n(n+1)/2。

0.1度为k的树中有n1个度为1的结点,n2个度为2的结点,…,nk个度为k的结点,问该树中有多少个叶子结点。

分析:

分别从结点个数和分支个数考虑。

设叶子个数为n0,结点总数:

n=n0+n1+n2+...+nk,分支数目:

n-1=n1+2n2+...+knk,于是得到叶子个数

0.2有n个叶子结点的完全二叉树的高度是多少?

分析:

完全二叉树中度为1的结点至多有一个。

完全二叉树中的结点数n+(n-1)≤N≤n+(n-1)+1,即2n-1≤N≤2n,二叉树的高度是

于是,

(1)当n=2k时,

,当没有度为1的结点时;

,当有1个度为1的结点时。

(2)其他情况下,

0.3编写算法按照缩进形式打印二叉树。

voidPrintBinaryTree(BinTreebt,intindent)

{

if(!

bt)return;

for(i=0;i

print(bt->data);

PrintBinaryTree(bt->lchild,indent+1);

PrintBinaryTree(bt->rchild,indent+1);

}

0.4编写算法按照逆时针旋转90度的形式打印二叉树。

voidPrintBinaryTree(BinTreebt,intlevel)

{

if(!

bt)return;

PrintBinaryTree(bt->rchild,level+1);//旋转后先打印右子树

for(i=0;i

print(bt->data);

PrintBinaryTree(bt->lchild,level+1);

}

0.5编写算法判断二叉树是否是完全二叉树。

分析:

按层遍历完全二叉树,当遇到第一个空指针之后应该全都是空指针。

boolIsComplete(BinTreebt)

{

//按层遍历至第一个空指针

InitQueue(Q);

EnQueue(Q,bt);

while(!

QueueEmpty(Q)){

DeQueue(Q,p);

if(p){

EnQueue(Q,p->lchild);

EnQueue(Q,p->rchild);

}else

break;//遇到第一个空指针时停止遍历

}

//检查队列中剩余元素是否全部是空指针

while(!

QueueEmpty(Q)){

DeQueue(Q,p);

if(!

p)returnfalse;//不是完全二叉树

}

returntrue;//完全二叉树

}

0.6编写算法求二叉树中给定结点的所有祖先。

分析:

进行后序遍历时,栈中保存的是当前结点的所有祖先。

所以,后序遍历二叉树,遇到该结点时,取出栈中的内容即是所有祖先。

//求二叉树bt中结点xptr的所有祖先

vectorAncestors(BinTreebt,BinTreexptr)

{

stacks;stacktag;

p=bt;

while(p||!

s.empty()){

if(p){

s.push(p);tag.push

(1);

p=p->lchild;

}else{

p=s.pop();f=tag.pop();

if(f==1){

s.push(p);tag.push

(2);

p=p->rchild;

}else{

if(p==xptr){

v=s;//当前栈的内容就是xptr的所有祖先

returnv;

}

p=NULL;

}

}

}//while

returnvector();//returnanullvector

}

注:

这里为描述方便借助了C++中的某些描述方式。

0.7编写算法求二叉树中两个结点的最近的共同祖先。

思路:

用后序遍历求出两者的所有祖先,依次比较。

//求二叉树bt中两个结点q和r的最近的共同祖先

BinTreeLastAncestor(BinTreebt,BinTreeq,BinTreer)

{

stacksq,sr;

stacks;stacktag;

//求q和r的所有祖先

p=bt;

while(p||!

s.empty()){

if(p){

s.push(p);tag.push

(1);

p=p->lchild;

}else{

p=s.pop();f=tag.pop();

if(f==1){

s.push(p);tag.push

(2);

p=p->rchild;

}else{

if(p==q)sq=s;//q的所有祖先

if(p==r)sr=s;//s的所有祖先

p=NULL;

}

}

}

//先跳过不同层的祖先,然后依次比较同一层的祖先

if(sq.size()>sr.size())while(sq.size()>sr.size())sq.pop();

elsewhile(sr.size()>sq.size())sr.pop();

//求q和r的最近的共同祖先

while(!

sq.empty()and(sq.top()!

=sr.top())){//寻找共同祖先

sq.pop();sr.pop();

}

if(!

sq.empty())

returnsq.top();

else

returnNULL;

}

0.8编写算法输出以二叉树表示的算术表达式(中缀形式),要求在必要的地方输出括号。

分析:

当左孩子的优先级低于根时需要加括号,根的优先级大于右孩子时也需要加括号。

voidPrintExpression(BinTreebt)

{

if(bt==NULL)return;

if(bt->lchild==NULLandbt->rchild==NULL)

print(bt->data);//叶子结点直接打印

else{

//左子树

brackets=bt->lchildandis_operator(bt->lchild->data)

andcomp_operator(bt->lchild->data,bt->data)<0;//左孩子优先级低于根

if(brackets)print(“(“);

PrintExpression(bt->lchild);

if(brackets)print(“)”);

//根结点

print(bt->data);

//右子树

brackets=bt->rchildandis_operator(bt->lchild->data)

andcomp_operator(bt->data,bt->rchild->data)>0;//根的优先级大于右孩子

if(brackets)print(“(“);

PrintExpression(bt->rchild);

if(brackets)print(“)“);

}

}

注:

is_operator(c)判断c是否是运算符;comp_operator(a,b)比较两个运算符的优先级。

boolis_operator(charc){//判断c是否是运算符

returnc=='+'||c=='-'||c=='*'||c=='/';

}

intcomp_operator(charopl,charopr){//比较两个运算符的优先级

return(opl=='*'||opl=='/'||opr=='+'||opr=='-')?

+1:

-1;

}

0.9树采用孩子-兄弟链表存储,编写算法求树中叶子结点的个数。

分析:

树中的叶子没有孩子,即firstchild为空。

//求树t中叶子结点的个数

intLeafCount(CSTreet)

{

if(t==NULL)return0;//空树

if(t->firstchild==NULL)//没有孩子

return1+LeafCount(t->nextsibling);

else

returnLeafCount(t->firstchild)+LeafCount(t->nextsibling);

}

0.10采用孩子-兄弟链表存储树,编写算法求树的度。

分析:

度最大的结点的度数。

intDegree(CSTreet)

{

if(t==NULL)return0;

else

returnmax(Degree(t->firstchild),1+Degree(t->nextsibling));

}

0.11采用孩子-兄弟链表存储树,编写算法求树的深度。

intDepth(CSTreet)

{

if(t==NULL)return0;

else{

depchild=Depth(t->firstchild);//孩子的深度

depsibling=Depth(t->nextsibling);//兄弟的深度

returnmax(depchild+1,depsibling);//取较大者

}

}

0.12已知二叉树的前序和中序序列,编写算法建立该二叉树。

分析:

划分先序序列a=(D,(L),(R))和后序序列b=((L),D,(R)),然后对子序列(L)和(R)递归。

//根据先序序列a[si..ti]和中序序列b[sj..tj]构造二叉树

BinTreeCreateBinaryTree(Ta[],intsi,intti,Tb[],intsj,inttj)

{

if(n<=0)return0;//空树

//建立根结点

p=newBinNode(a[si]);//以a[si]为数据域建立新结点

//根据根结点划分中序序列为b[sj..k-1]和b[k+1..tj]

k=sj;

while(b[k]!

=a[si])k++;//在b[]中搜索根结点a[si]

//建立左右子树

p->lchild=CreateBinaryTree(a,si+1,si+k-sj,b,sj,k-1);//建立左子树

p->rchild=CreateBinaryTree(a,si+k-sj+1,b,k+1,tj);//建立右子树

returnp;

}

0.13树T的先根遍历序列为GFKDAIEBCHJ,后根遍历序列为DIAEKFCJHBG,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 医药卫生 > 基础医学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2