数据结构期末总结

时间:2024.5.4

数据结构期末总结

您现在的位置:希赛教育首页 > 自考学院 > 数据结构与算法 > 正文

数据结构第三章(栈与队列)习题参考答案

作者:自考频道 来源:希赛教育 20xx年1月5日 发表评论 进入社区

数据结构期末总结

数据结构期末总结

数据结构期末总结

数据结构期末总结

数据结构期末总结

数据结构期末总结

一、基础知识题

3.1 设将整数 1,2,3,4依次进栈,但只要出栈时栈非空,则可将出栈操作按任何次序夹入其中,请回答下述问题:

(1)若入、出栈次序为Push(1), Pop(),Push(2),Push(3), Pop(), Pop( ),Push(4), Pop( ),则出栈的数字序列为何(这里Push(i)表示i进栈,Pop( )表示出栈)?

(2) 能否得到出栈序列1423和1432?并说明为什么不能得到或者如何得到。

(3)请分析 1,2 ,3 ,4 的24种排列中,哪些序列是可以通过相应的入出栈操作得到的。

3.2 链栈中为何不设置头结点?

答:链栈不需要在头部附加头结点,因为栈都是在头部进行操作的,如果加了头结点,等于要对头结点之后的结点进行操作,反而使算法更复杂,所以只要有链表的头指针就可以了。

3.3 循环队列的优点是什么? 如何判别它的空和满?

答:循环队列的优点是:它可以克服顺序队列的"假上溢"现象,能够使存储队列的向量空间得到充分的利用。判别循环队列的"空"或"满"不能以头尾指针是否相等来确定,一般是通过以下几种方法:一是另设一布尔变量来区别队列的空和满。二是少用一个元素的空间。每次入队前测试入队后头尾指针是否会重合,如果会重合就认为队列已满。三是设置一计数器记录队列中元素总数,不仅可判别空或满,还可以得到队列中元素的个数。

3.4 设长度为n的链队用单循环链表表示,若设头指针,则入队出队操作的时间为何? 若只设尾指针呢?

答:当只设头指针时,出队的时间为1,而入队的时间需要n,因为每次入队均需从头指针开始查找,找到最后一个元素时方可进行入队操作。若只设尾指针,则出入队时间均为

1。因为是循环链表,尾指针所指的下一个元素就是头指针所指元素,所以出队时不需要遍历整个队列。

3.5 指出下述程序段的功能是什么?

(1) void Demo1(SeqStack *S){

int i; arr[64] ; n=0 ;

while ( StackEmpty(S)) arr[n++]=Pop(S);

for (i=0, i< n; i++) Push(S, arr[i]);

} //Demo1

(2) SeqStack S1, S2, tmp;

DataType x;

...//假设栈tmp和S2已做过初始化

while ( ! StackEmpty (&S1))

{

x=Pop(&S1) ;

Push(&tmp,x);

}

while ( ! StackEmpty (&tmp) ) {

x=Pop( &tmp);

Push( &S1,x);

Push( &S2, x);

}

(3) void Demo2( SeqStack *S, int m) { // 设DataType 为int 型 SeqStack T; int i;

InitStack (&T);

while (! StackEmpty( S))

if(( i=Pop(S)) !=m) Push( &T,i); while (! StackEmpty( &T)) {

i=Pop(&T); Push(S,i);

}

}

(4)void Demo3( CirQueue *Q)

{ // 设DataType 为int 型

int x; SeqStack S;

InitStack( &S);

while (! QueueEmpty( Q ))

{x=DeQueue( Q); Push( &S,x);}

while (! StackEmpty( &s))

{ x=Pop(&S); EnQueue( Q,x );}

}// Demo3

(5) CirQueue Q1, Q2; // 设DataType 为int 型 int x, i , m = 0;

... // 设Q1已有内容, Q2已初始化过 while ( ! QueueEmpty( &Q1) )

{ x=DeQueue( &Q1 ) ; EnQueue(&Q2, x); m++;} for (i=0; i< n; i++)

{ x=DeQueue(&Q2) ;

EnQueue( &Q1, x) ; EnQueue( &Q2, x);} 答:

(1)程序段的功能是将一栈中的元素按反序重新排列,也就是原来在栈顶的元素放到栈底,栈底的元素放到栈顶。此栈中元素个数限制在64个以内。

(2)程序段的功能是利用tmp栈将一个非空栈的所有元素按原样复制到一个空栈当中去。

(3)程序段的功能是将一个非空栈中值等于m的元素全部删去。

(4)程序段的功能是将一个循环队列反向排列,原来的队头变成队尾,原来的队尾变成队头。

(5)首先指出程序可能有印刷错误,for语句中的n应为m才对。这段程序的功能是将队列1的所有元素复制到队列2中去,但其执行过程是先把队列1的元素全部出队,进入队列2,然后再把队列2的元素复制到队列1中。

二、算法设计题

3.6 回文是指正读反读均相同的字符序列,如"abba"和"abdba"均是回文,但"good"不是回文。试写一个算法判定给定的字符向量是否为回文。(提示:将一半字符入栈) 解:根据提示,算法可设计为:

//ishuiwen.h 存为头文件

int IsHuiwen( char *S)

{

SeqStack T;

int i , l;

char t;

InitStack( &T);

l=strlen(S); //求向量长度

for ( i=0; i

Push( &T, S[i]);

while( !EmptyStack( &T))

{

// 每弹出一个字符与相应字符比较 t=Pop (&T);

if( t!=S[l-i]) { return 0 ;}// 不等则返回0 i--;

}

return -1 ; // 比较完毕均相等则返回 -1 }

// 以下程序用于验证上面的算法 //以下是栈定义( 存为stack.h) //出错控制函数

#include

#include

void Error(char * message)

{

fprintf(stderr, "Error: %s\n",message); exit(1);

}

// 定义栈类型

#define StackSize 100

typedef char Datatype;

typedef struct{

Datatype data[StackSize]; int Top;

} SeqStack;

void InitStack( SeqStack *S) {

//初始化(置空栈)

S->Top=-1;

}

int EmptyStack(SeqStack *S) { //判栈空

return S->Top == -1;

}

int FullStack (SeqStack *S) { // 判栈满

return S->Top==StackSize-1; }

void Push (SeqStack *S , Datatype x) { //进栈

if(FullStack(S))

Error("Stack overflow");

S->data[++S->Top]=x;

}

Datatype Pop(SeqStack *S) { // 出栈(退栈)

if (EmptyStack( S) )

Error( "Stack underflow"); return S->data[S->Top--]; }

//取栈顶元素(略)

//----------------------------------------------- //以下是主程序

#include

#include

#include "stack.h>

#include "ishuiwen.h"

void main( )

{

char Str[100]="";

printf("输入一个字符串:\n"); scanf("%s",Str);

if( IsHuiwen(Str))

printf(" \n这个字符串是回文。");

else printf("\n这个字符串不是回文。"); }

附:肖平来信指出问题:

个人认为如题目所言,"abba"和"abdba"均是回文,但对于这两种回文需要区别对待,原算法在判断类似"abdba"的回文时,会认为其不是回文而与题意相违背!

我的编程思想是:设置一个float型的变量,用于存放字符串的长度,再利用取整函数对长度为奇数的回文进行判别,若将字符串长度附给一整型变量,那么无论该整形变量除任何整数,其结果仍然是一整数,因此必须设一实型变量!判断结束后,若是回文返回1,不是则返回0。

我的算法如下,已验证通过:

int HuiWen(char *p)

{

int i;

float t;

SeqStack S;

InitStack(&S);

t=strlen(p);

for(i=0;i<=t/2-1;i++)

Push(&S,p[i]);

if(floor(t/2)!=(t/2)) //针对"abdba"类的回文

i++;

while(p[i]!='\0')

if(Pop(&S)==p[i])

i++;

else

return(0);

return(1);

}

=================================================

也可以直接用字符指针而不用字符数组来处理,只需对算法稍作修改! 算法如下,已验证通过:

int HuiWen(char *p)

{

int i;

float t;

SeqStack S;

InitStack(&S);

t=strlen(p);

for(i=0;i<=t/2-1;i++,p++)

Push(&S,*p);

if(floor(t/2)!=(t/2)) //针对"abdba"类的回文

p++;

while(*p!='\0')

if(Pop(&S)==*p)

p++;

else

return(0);

return(1);

}

3.7 利用栈的基本操作,写一个将栈S中所有结点均删去的算法void

ClearStack( SeqStack *S),并说明S为何要作为指针参数?

解: 算法如下

void ClearStack (SeqStack *S)

{ // 删除栈中所有结点

S->Top = -1; //其实只是将栈置空

}

因为我们要置空的是栈S,如果不用指针来做参数传递,那么函数进行的操作不能对原来的栈产生影响,系统将会在内存中开辟另外的单元来对形参进行函数操作。结果等于什么也没有做。所以想要把函数操作的结果返回给实参的话,就只能用指针来做参数传递了。

3.8 利用栈的基本操作, 写一个返回S中结点个数的算法 int StackSize( SeqStack S),并说明S为何不作为指针参数?

解:算法如下:

int StackSize (SeqStack S)

{

//计算栈中结点个数

int n=0;

if(!EmptyStack(&S))

{

Pop(&S);

n++;

}

return n;

}

类似于上面的原因,我们要计算栈中元素个数就要弹出元素才能"数"得出来,那如果用指针做参数的话,就会把原来的栈中元素"弹"光,要恢复还得用别的办法给它装回去,而不用指针做参数,则可以避免对原来的栈中元素进行任何操作,系统会把原来的栈按值传递给形参,函数只对形参进行操作,最后返回元素个数就可以了。

3.9 设计算法判断一个算术表达式的圆括号是否正确配对。 (提示: 对表达式进行扫描,凡遇到'('就进栈,遇')'就退掉栈顶的'(',表达式被扫描完毕,栈应为空。

解:根据提示,可以设计算法如下:

#include

#include "stack.h"

int PairBracket( char *S)

{

//检查表达式中括号是否配对

int i;

SeqStack T; //定义一个栈

InitStack (&T);

for (i=0; i

{

if ( S[i]=='(' ) Push(&T, S[i]); //遇'('时进栈

if ( S[i]==')' ) Pop(&T); //遇')'时出栈

}

return StackEmpty(&T); // 由栈空否返回正确配对与否

}

3.10 一个双向栈S是在同一向量空间内实现的两个栈,它们的栈底分别设在向量空间的两端。 试为此双向栈设计初始化InitStack ( S ) 、入栈Push( S , i , x) 和出栈Pop( S , i )等算法, 其中i为0 或1, 用以表示栈号。

解:双向栈其实和单向栈原理相同,只是在一个向量空间内,好比是两个头对头的栈放在一起,中间的空间可以充分利用。双向栈的算法设计如下:

//双向栈的栈结构类型与以前定义略有不同

#define StackSize 100 // 假定分配了100个元素的向量空间

#define char Datatype

typedef struct{

Datatype Data[StackSize]

int top0; //需设两个指针

int top1;

}DblStack

void InitStack( DblStack *S )

{ //初始化双向栈

S->top0 = -1;

S->top1 = StackSize; //这里的top2也指出了向量空间,但由于是作为栈底,因此不会出错

}

3.11 Ackerman 函数定义如下:请写出递归算法。

[ n+1 当m=0时

AKM ( m , n ) = \{ AKM( m-1 ,1) 当m≠0 ,n=0时

[ AKM( m-1, AKM( m,n-1)) 当m≠0, n ≠ 0时

解:算法如下

int AKM( int m, int n)

{

if ( m== 0) return n+1;

if ( m<>0 && n==0 ) return AKM( m-1, 1);

if ( m<>0 && n<>0 ) return AKM( m-1, AKM( m, n-1));

}

3.12 用第二种方法 ,即少用一上元素空间的方法来区别循环队列的队空和队满,试为其设计置空队,判队空,判队满、出队、入队及取队头元素等六个基本操作的算法。 解:算法设计如下:

//存为Queue2.h文件

void InitQueue ( CirQueue *Q)

{ // 置空队

Q->front=Q->rear=0;

}

int EmptyQueue( CirQueue *Q)

{ //判队空

return Q->front==Q->rear;

}

int FullQueue( CirQueue *Q)

{ // 判队满//如果尾指针加1后等于头指针,则认为满

return (Q->rear+1)%QueueSize== Q->front;

}

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

解:算法如下:

//先定义链队结构:

typedef struct queuenode{

Datatype data;

struct queuenode *next;

}QueueNode; //以上是结点类型的定义

typedef struct{

queuenode *rear;

}LinkQueue; //只设一个指向队尾元素的指针

//linkQ.h 相应算法

void InitQueue( LinkQueue *Q)

{ //置空队:就是使头结点成为队尾元素

Q->rear = Q->rear->next;//头结点成为尾结点

Q->rear->next = Q->rear;//形成循环链表

}

int EmptyQueue( LinkQueue *Q)

{ //判队空

//当头结点的next指针指向自己时为空队

return Q->rear->next->next==Q->rear->next;

}

void EnQueue( LinkQueue *Q, Datatype x)

{ //入队

//也就是在尾结点处插入元素

QueueNode *p=(QueueNode *) malloc (sizeof(QueueNode));//申请新结点 p->data=x; p->next=NULL;//初始化结点

Q-rear->next->next=p; // 将新结点链入

p->next=Q->rear; //形成循环链表

Q->rear=p;//将尾指针移至新结点

}

Datatype DeQueue( LinkQueue *Q)

{ //出队

//把头结点之后的元素摘下

Datatype t;

QueueNode *p;

if(EmptyQueue( Q ))

Error("Queue underflow");

p=Q->rear->next->next; //将要摘下的结点

x=p->data; //保存结点中数据

Q->rear->next->next=p->next;//摘下结点p

free(p);//释放被删结点

return x;

}

肖平朋友提出看法:

仔细研究了原算法,发现存在以下几个问题:

1)虽然使用了Q->rear->next来代替头结点的表示方法,但不如直接定义头结点Q->head来的方便,而且题目也明确要求了使用头结点,在结构定义中只反映出去掉了头指针,没有反映出该链队列是否包含头结点;

2)对于入队算法,是采用头插法将新结点依次链入头结点的后面,这似乎与队列的定义相违背。队列应该在尾部入队,而不是在头部入队;

3)同上,出队操作仍然在头部进行。若顺序运行入队和出队算法,由于均在头部进行,其结果会将该队列演变成一个栈!

=================================================

我的算法如下:

typedef struct

{ QueueNode head; //去掉头指针,增加头结点!

QueueNode *rear;

}LinkQueue;

置空队:

void InitQueue(LinkQueue *Q)

{

Q->rear=Q->head;

Q->head->next=Q->rear; //形成循环空队列,尾指针指向空队列内唯一的头结点 }

判队空:

int QueueEmpty(LinkQueue *Q)

{

return Q->head->next==Q->rear;

}

入队:

void EnQueue(LinkQueue *Q)

{

QueueNode *p=(Queue *)malloc(sizeof(QueueNode));

p->data=x;

Q->rear->next=p;

p->next=Q->head;

Q->rear=p; //对于空队列,由于Q->rear=Q->head,因此第一个结点和后续结点的入队操作均一致

}

出队:

DataType DeQueue(LinkQueue *Q)

{

if(QueueEmpty(Q))

Error("Queue underflow");

DataType x;

QueueNode *p;

p=Q->head->next;

x=p->data;

Q->head->next=p->next;

if(Q->rear==p)

Q->rear=Q->head; //当最后一个结点也出队后,队列为空,尾指针重新指向头结点 free(p);

return x;

}

3.14 对于循环向量中的循环队列,写出求队列长度的公式。

解:公式如下:

Queuelen= 0 当EmptyQueue

Queuelen= rear - front 当rear>front

Queuelen= rear+QueueSize-front 当rear

Queuelen= QueueSize 当FullQueue

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

解:知道了尾指针和元素个数,当然就能知道队头元素了。算法如下:

int FullQueue( CirQueue *Q)

{

//判队满,队中元素个数等于空间大小

return Q->quelen==QueueSize;

}

void EnQueue( CirQueue *Q, Datatype x)

{

// 入队

if(FullQueue( Q))

Error("队已满,无法入队");

Q->Data[Q->rear]=x;

Q->rear=(Q->rear+1)%QueueSize;//在循环意义上的加1 Q->quelen++;

}

Datatype DeQueue( CirQueue *Q)

{

//出队

if(Q->quelen==0)

Error("队已空,无元素可出队");

int tmpfront; //设一个临时队头指针

if(Q->rear > Q->quelen)//计算头指针位置

tmpfront=Q->rear - Q->quelen;

else

tmpfront=Q->rear + QueueSize - Q->quelen;

quelen--;

return Q->Data[tmpfront];

}

//如果需要验证上面的算法,则需定义好结点类型的队列结构,以相应的变量来表示尾指针和队列长度。自己试试吧。最主要的是能够理解算法的意义和实现。

数据结构期末总结

【大 中 小】【收藏到我的希赛教育】 【发表评论】【进入社区】

数据结构期末总结

数据结构期末总结

数据结构期末总结

相关文章

·09年自考《数据结构》各章要点二[12] (2008-11-19)

·09年自考《数据结构》各章要点二[11] (2008-11-19)

·09年自考《数据结构》各章要点二[10] (2008-11-19)

·09年自考《数据结构》各章要点二[9] (2008-11-19)

·09年自考《数据结构》各章要点二[8] (2008-11-19)

·09年自考《数据结构》各章要点二[7] (2008-11-19)

·09年自考《数据结构》各章要点二[6] (2008-11-19)

·09年自考《数据结构》各章要点二[5] (2008-11-19)

·09年自考《数据结构》各章要点二[4] (2008-11-19)

·09年自考《数据结构》各章要点二[3] (2008-11-19)

数据结构期末总结

·20xx年上半年系统分析师上午第18题

·20xx年上半年网络规划设计师下午Ⅰ第3题

·20xx年上半年网络规划设计师上午第1题

·2010上半年网络管理员下午第2题

·20xx年上半年网络规划设计师上午第13-14题

·20xx年上半年网络规划设计师上午第27-28题

·2010上半年多媒体应用设计师下午第2题

·20xx年上半年系统分析师上午第60题

·2010上半年信息处理技术员上午第1题 ·20xx年上半年信息系统监理师上午第

数据结构期末总结

12题

·2010上半年软件设计师上午第23题

·2010上半年多媒体应用设计师上午第50题

博客推荐

加班费和饭碗你..

[zyihan] 深度挖掘女性职场晋升攻略

[data0204wu] 10年考研英语经典范文

[blende] 如何实施Build验证测试

数据结构期末总结

数据结构期末总结

[hanlix] 让CMMI融入我们的日常工作

[sunny_wwh] Oracle维护常用SQL语句汇总

[zljchh] 网络工程师常用英文单词和缩写翻译

关于我们 | 网站导航 | 投稿指南 | 友情链接 | 在线客服 | 用户注册 | 错误报告 | 工作机会 |

联系我们

希赛教育

数据结构期末总结

版权所有

数据结构期末总结

? 2001-2010

数据结构期末总结

湘ICP备05000393号 增值电信业务经营许可证湘B2-20070093

全国统一客服热线:400-777-1218 | 互联网违法和不良信息举报中心 | 不良信息举报信箱

更多相关推荐:
数据结构总结

第一章1、数据元素是数据的基本单位;数据项是数据的不可分割的最小单位。2、数据结构:4种基本结构为:集合,线性结构,树状结构,图状结构或网状结构DS组成:逻辑结构(结构定义中的关系描述是数据元素之间的逻辑关系)…

数据结构总结

《数据结构与算法》课程学习总结报告本学期开设的《数据结构与算法》课程已经告一段落,现就其知识点及其掌握情况、学习体会以及对该门课程的教学建议等方面进行学习总结。一、《数据结构与算法》知识点第一章是这门学科的基础…

数据结构总结

一,基础知识数据(Data):是客观事物的符号表示。在计算机科学中指的是所有能输入到计算机中并被计算机程序处理的符号的总称。数据元素(DataElement):是数据的基本单位,在程序中通常作为一个整体来进行考…

java部分数据结构总结

packagedatastructtest;importjava.io.File;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.…

数据结构总结

本学期开设的《数据结构与算法》课程已经告一段落,现就其知识点及其掌握情况、学习体会以及对该门课程的教学建议等方面进行学习总结。一、《数据结构与算法》知识点在课本的第一章便交代了该学科的相关概念,如数据、数据元素…

数据结构总结

第四章排序程序设计初步本章介绍线性表的一个主要应用——排序,讲解了排序相关的基本概念和排序算法的一般思路,包括直接插入排序、简单选择排序、冒泡排序以及静态链表插入排序,并给出了其程序设计源码,通过程序设计技巧和…

二级考试题-数据结构总结

二级C公共基础知识总结二级C公共基础知识总结数据结构与算法1算法算法:是指解题方案的准确而完整的描述。算法不等于程序,也不等计算机方法,程序的编制不可能优于算法的设计。算法的基本特征:是一组严谨地定义运算顺序的…

数据结构心得体会

心得体会数据结构是一门纯属于设计的科目它需用把理论变为上机调试在学习科目的第一节课起鲁老师就为我们阐述了它的重要性它对我们来说具有一定的难度它是其它编程语言的一门基本学科很多同学都说数据结构不好学这我深有体会刚...

数据结构中常见的排序算法总结

几种常见排序算法的比较与实现1冒泡排序BubbleSort冒泡排序方法是最简单的排序方法这种方法的基本思想是将待排序的元素看作是竖着排列的气泡较小的元素比较轻从而要往上浮在冒泡排序算法中我们要对这个气泡序列处理...

数据结构各种排序算法总结

数据结构各种排序算法总结计算机排序与人进行排序的不同计算机程序不能象人一样通览所有的数据只能根据计算机的quot比较quot原理在同一时间内对两个队员进行比较这是算法的一种quot短视quot1冒泡排序Bubb...

数据结构算法排序总结

数据结构与算法总结姓名:**学号:**班级:12计本(2)班这个学期在老师的带领下我们学习了数据结构与算法这门课程。在本次数据结构与算法的学习中最令我深刻的是关于几种排序算法的学习,所以在这里我想对我本学期所学…

数据结构(学习小结重点总结)

数据结构复习重点归纳适于清华严版教材一数据结构的章节结构及重点构成数据结构学科的章节划分基本上为概论线性表栈和队列串多维数组和广义表树和二叉树图查找内排外排文件动态存储分配对于绝大多数的学校而言外排文件动态存储...

数据结构总结(58篇)