文档库 最新最全的文档下载
当前位置:文档库 › 第3章习题答案

第3章习题答案

第3章习题答案
第3章习题答案

习题3

1.名词解释:栈、队列、循环队列。

解:栈是只能在一端进行插入和删除操作的线性表,允许插入和删除的一端叫栈顶,另一端叫栈底。最后插入的元素最先删除,故栈也称后进先出表。

队列是允许在一端插入而在另一端删除的线性表,允许插入的一端叫队尾,允许删除的一端叫队头。最后插入的元素最先删除,故栈也称先进先出表。最先入队的元素最先删除,故队列也称先进先出表。

用常规意义下顺序存储结构的一维数组表示队列,由于队列的性质(队尾插入,队头删除),容易造成“假溢出”现象,即队尾已达到一维数组的高下标,不能再插入,然而队中元素个数小于队列的长度。循环队列是解决“假溢出”的一种方法。通常把一维数组看成首尾相接。在循环队列下,通常采用“牺牲一个存储空间”的方法解决“队满”和“队空”的判定问题。

2.如果输入序列为1,2,3,4,5,6,试问能否通过栈结构得到以下两个序列:4,3,5,6,1,2和1,3,5,4,2,6;请说明为什么不能或如何才能得到。

解:输入序列为1,2,3,4,5,6,不能得到4,3,5,6,1,2,其理由是:输出序列最后两个元素是1,2,前面四个元素(4,3,5,6)得到后,栈中元素剩下1,2,且2在栈顶,栈底元素1不可能在栈顶元素2出栈之前出栈。

得到序列1,3,5,4,2,6的过程是:1入栈并出栈;然后2和3依次入栈,3出栈,部分输出序列是1,3;紧接着4和5入栈,5,4和2依次出栈,此时输出序列为1,3,5,4,2;最后6入栈并出栈,得到最终结果序列是1,3,5,4,2,6。

3.试证明:若借助栈由输入序列1,2,…,n 得到序列1p ,2p ,…,n p (它是输入序列的一个全排列),则在输出序列中不可能出现下列情形:存在着i

解:如果i j p 的情况,则说明要将j p 压到i p 之上,也就是在j p 出栈之后i p 才能出栈。这说明,对于i

4.当函数f 递归调用自身时,函数f 内定义的局部变量在函数f 的2次调用期间是否占用同一数据区?为什么?

解:函数f 递归调用自身时,函数f 内定义的局部变量在函数f 的2次调用期间不占用同一数据区。每次调用都保留其数据区,这是由递归定义所决定的,用“递归工作栈”来实现。

5.简要叙述循环队列的数据结构,并写出其初始状态、队列空、队列满时的队头指针和队尾指针的值。 解:循环队列的数据结构略。

typedef struct{

ElemType *elem;

int front;

int rear;

}SqQueue,Q;

(1)初始状态: Q.front=Q.rear=0;

(2)队列空: Q.front=Q.rear=0;

(3)队列满: Q.front=(Q.rear+1)%MAXSIZE;

6.设一个双端队列,元素进入该队列的次序为1,2,3,4.求既不能由输入受限的双端队列得到,又不能由输出受限的双端队列得到的输出序列。

解:既不能由输入受限的双端队列得到,又不能由输出受限的双端队列得到的输出序列是:4,2,3,1。

7.简述以下算法的功能。

(1)void algo1(Stack S){

int i,n,A[255];

n=0;

while(!StackEmpty(S)){n++;Pop(S,A[n]);};

for(i=1;i<=n;i++)Push(S,A[i]);

}

(2)void algo2(Stack S,int e){

Stack T;int d;

InitStack(T);

while(!StackEmpty(S)){Pop(S,d);if(d!=e)Push(T,d);}

while(!StackEmpty(T)){Pop(T,d);Push(S,d);}

}

(3)void algo3(Queue &Q){//栈和队列的元素类型均为int

Stack S;int d;

InitStack(T);

while(!QueueEmpty(Q)){DeQueue(Q,d);Push(S,d);}

while(!StackEmpty(S)){Pop(S,d);EnQueue(Q,d);}

}

解:(1)将栈中元素逆置。

(2)将栈中的0元素删除。

(3)将队列中元素逆置。

8.试写一个算法,识别依次读入的一个以@为结束符的字符序列是否为形如“序列1&序列2”模式的字符序列。其中,序列1和序列2中不含字符@,且序列2是序列1的逆序列。

解:

int IsReverse(){//判断输入的字符串中'&'前和'&'后部分是否为逆串,是则返回1,否则返回0 SqStack s;

char c,x;

InitStack(s);

while((c=getchar())!='&')Push(s,c);

while((c=getchar())!='@'){

if(StackEmpty(s))return 0;

Pop(s,x);

if(x!=c)return 0; }

if(!StackEmpty(s))return 0;

return 1;

}

9.在火车调度站的入口处有n 节硬席或软席车厢(分别以H 和S 表示)等待调度,试写一算法,输出对这n 节车厢进行调度的操作(即入栈或出栈操作)序列,以使所有的软席车厢都被调整到硬席车厢之前。

解:typedef char SS[MAX];

void Train_arrange(SS &train){//这里用字符串train 表示火车,'H'表示硬席,'S'表示软席 SqStack s;

char *p,*q,c;

p=train;

q=train;

InitStack(s);

while(*p){

if(*p=='H')Push(s,*p);//把'H'存入栈中

else *(q++)=*p; //把'S'调到前部

p++; }

while(!StackEmpty(s)){

Pop(s,c);

*(q++)=c;//把'H'接在后部 }

}

10.试写出求递归函数)(n F 的递归算法,并消除递归:

???>?=+=0

)2/(01)(n n F n n n n F 解:

int F_recursive(int n,int &s){//递归算法

if(n<0) return ERROR;

if(n==0) s=n+1;

else{

F_recursive(n/2,s);

s=n*s; }

return OK;

}//F_recursive

typedef struct {

ElemType a;

ElemType b;

}node;

typedef struct {

node *data;

int top;//栈顶指针

int stacksize;

}SqStack;

void F_nonrecursive(int n,int &s){//非递归算法

SqStack T;

node x,t;

if(n<0) exit(0);

if(n==0) s=n+1;

else {

InitStack(T);

while(n!=0){

x.a=n;x.b=n/2;

Push(T,x);

n=x.b;

}//while

s=1;

while(!StackEmpty(T)){

Pop(T,t);

s*=t.a;

}//while

}

}//F_nonrecursive

11.试将下列递归函数改为非递归函数。

void test(int &sum){

int x;

scanf ("%d",&x);

if (x==0)sum=0;

else {test(sum);sum+=x;}

printf ("sum=%d\n",sum);

}

解:

void test(){

int x,sum=0,top=-1,s[10];

scanf("%d",&x);

while(x!=0){s[++top]=x; scanf("%d",&x);}

printf("sum=%d",sum);

while(top>-1){sum+=s[top--]; printf("sum=%d\n",sum);}

};

12.设整数列1p ,2p ,…,n p ,给出求解最大值的递归程序。

解:

int MaxValue(int a[],int n){

int max;

if(n==1)max=a[0];

else if(a[n-1]>MaxValue(a,n-1))max=a[n-1];

else max=MaxValue(a,n-1);

return max;

}

13.假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾元素结点(注意不设头指针),试编写相应的队列初始化、入队和出队的算法。

解:

(1)

void InitQueue(CirLinkList &rear){

rear=new LNode;

rear->next=rear;

}

(2)

void EnQueue(CirLinkList &rear, ElemType x){

LNode *s;

s=new LNode;

s->data=x;

s->next=rear->next;

rear->next=s;

rear=s;

}

(3)

void DnQueue(CirLinkList &rear,ElemType &x){

LNode *s;

if(rear->next==rear){printf("队空\n");exit(0);}

s=rear->next->next;//s指向队头元素

rear->next->next=s->next;//队头元素出队

x=s->data;

if(s==rear)rear=rear->next;//空队

delete s;

}

14.假设称正读和反读都相同的字符序列为“回文”,试写一个算法判别读入的一个亿@为结束符的字符序列是否是“回文”。

解:

int Test(){//判别输入的字符串是否回文序列,是则返回1,否则返回0

SqStack S;

SqQueue Q;

char c;

ElemType a,b;

InitStack(S);InitQueue(Q);

while((c=getchar())!='@'){

Push(S,c);EnQueue(Q,c); //同时使用栈和队列两种结构

}

while(!StackEmpty(S)){

Pop(S,a);

DeQueue(Q,b);

if(a!=b) return ERROR;

}

return OK;

}

15.写一算法,借助于栈将一个单链表逆序输出。

解:

void process(LinkList &L){

LNode *p;

SqStack s;

ElemType x;

p=L->next;

InitStack(s);

while (p){Push(s,p->data);p=p->next;}

while (!StackEmpty(s)){Pop(s,x);printf("%d ",x);}

}

16.假设循环队列中只设rear和length来分别指示队尾元素的位置和队中元素的个数,试给出此循环队列的队满条件,并写出相应的入队和出队算法,要求出队时需返回队头元素。

解:

typedef struct {

ElemType *base;//动态分配存储空间

int length;//队列长度

i nt rear;//尾指针,指向队列尾元素

}SqQueue;

int EnQueue(SqQueue &Q,ElemType x){ //带length域的循环队列入队算法

if(Q.length==MAX)return ERROR;//队列满

Q.rear=(Q.rear+1)%MAX;

Q.base[Q.rear]=x;

Q.length++;

return OK;

}

int DeQueue(SqQueue &Q,ElemType &x){ //带length域的循环队列出队算法 int head;

if(Q.length==0)return ERROR;//队列空

head=(Q.rear-Q.length+1)%MAX;

x=Q.base[head];

Q.length--;

return OK;

}

int InitQueue(SqQueue &Q){//构造一个空循环队列Q

Q.base=new ElemType[MAX];

if(!Q.base)exit(OVERFLOW);

Q.rear=0;

Q.length=0;

return OK;

}

相关文档