数据结构综合应用题⑩
试证明:若借助栈可由输入序列1,2,3,…n得到一个输出序列p1,p2,p3,…pn(它是输入序列的某一种排列),则在输出序列中不可能出现以下情况:存在i
1)必要性。按照题意,当i
当i
假设以I和O分别表示入栈和出栈操作。若栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,则称可以操作的序列为合法序列,否则称为非法序列。
1)试指出判别给定序列是否合法的一般规则
**解析:**通常有两条规则,第一条是给定序列中,I的个数和O的个数相等,第二条是从序列的开始到给定的序列中的任一位置,1的个数要≥O的个数。
2)两个不同的合法序列(对两个具有同样元素的输入序列)能否得到相同的输出元素序列?如果能得到,请举例。
解析:
可以。
例如,输入元素为ABC,则两个输入序列ABC和BAC都可以得到输出元素序列ABC。对于输入序列ABC,我们可以用IOIOIO操作序列;对于输入序列BAC,我们使用IIOOIO操作序列。
3)写出一个算法,判定所给的操作序列是否合法。若合法,返回1,否则返回0(假定被判定的操作序列已存入一维char型数组ch【】中,操作序列以“\0”为结束符)
解析:
由1)中分析可以写出以下代码:
{
int i=0;
int I=0,O=0;//I和O分别为字符“I”和“O”的个数
while(ch[i]!='\0')
{
if(ch[i]!='I')
++I;
if(ch[i]=='O')
++O;
if(O>I)
return 0;//扫描过程中出现O的个数>I的情况,则一定不合法
++i;
}
if(I!=O)
return 0;//I的总数和O不相等,不合法,返回0
else
return 1;//合法返回1
}
数据结构综合应用题12
假设以带头结点的循环链表表示队列,并且只设一个指针指向队尾结点,但不设头指针,请写出相应的入队列和出队列算法。
解析:
此题是链队基本操作的扩展,知道尾指针后,要实现元素入队,则直接用链表的插入操作即可。要实现出队操作,用尾指针找出头结点和开始结点,然后进行删除。要注意,尾指针始终指向终端结点,并且当删除结点后,队列为空时,必须特殊处理。
1)入队
void enQueue(LNode *&rear,int x)
/*rear是带头结点的循环链队的尾指针,本算法将元素x插入到队尾*/
{
LNode *s=(LNode*)malloc(sizeof(LNode));//申请结点空间
s->data=x;
s->next=rear->next;//将s结点链入队尾
rear->next=s;
rear=s;//rear指向新队尾
}
2)出队
int deQueue(LNode *&rear,int &x)
/*rear时带头结点的循环链队的尾指针,x接收出队元素,操作成功返回1,否则返回0*/
{
LNode *s;
if(rear->next==rear)
return 0;
else
{
s=rear->next->next;//s指向开始结点
rear->next->next=s->next;//队头元素出队
x=s->data;
if(s==rear)//如果元素出队后队列为空,则需要特殊处理
rear=rear->next;//将rear指向头结点
free(s);//释放队结点空间
return 1;//操作成功,返回1
}
}
数据结构综合应用题13
如果允许在循环队列的两端都可以进行插入和删除操作,要求:
1)写出循环队列的类型定义
解析:
用一维数组data[0,…,maxsize-1]实现循环队列,其中maxsize是队列长度。设置头指针front和尾指针rear,约定front指向队头元素的前一位置,rear指向队尾元素。定义满足front==rear
队空。从队尾删除元素,则rear向着方向小的下标行走。因此,当满足rear==(front-1+maxsize)%maxsize时队满。
队列的结构体定义:
typedef struct
{
int data[maxsize];//假设maxsize为已定义的常量
int front,rear;
}cycqueue;
2)分别写出从队尾删除和从队头插入的算法
①出队算法:
int deQueue(cycqueue &Q,int &x)
/*本算法实现从队尾删除,若删除成功,用x接纳删除元素,返回1,否则返回0*/
{
if(Q.front==Q.rear)
return 0;
else
{
x=Q.data[Q.rear];
Q.rear=(Q.rear-1+maxsize)%maxsize;//修改队尾指针
return 1;//出队成功,返回1
}
}
②入队算法:
int enQueue(cycqueue &Q,int x)
/*本算法实现从队头插入元素*/
{
if(Q.rear==(Q.front-1+maxsize)%maxszie)
return 0;
else
{
Q.data[Q.front]=x;//x入队列
Q.front=(Q.front-1+maxsize)%maxsize;//修改队头指针
return 1;
}
}
说明:本题算法中用到了一个操作:
Q.front=(Q.front-1+maxsize)%maxsize,
如果把这一句放在一个循环中,front指针沿着maxsize-1,maxsize-2,…,2,1,0,maxsize-1,maxsize-2的无限循环数行走,这个操作和Q.front=(Q.front+1)%maxsize;实现的效果正好相反,这两个程序设计题目中是常用的。
数据结构综合应用题14
设计一个循环队列,用front和rear分别作为队头和队尾指针,另外用一个标志tag表示队列是空还是不空,约定当tag为0时对空,当tag为1时队不空,这样就可以用front==rear
作为队满的条件要求,设计队列的结构和相关基本运算算法(队列元素为int型)
解析:
本题为循环队列基本算法操作的扩展。在队列结构体定义中加入tag,用tag判断队列是否为空,用front==rear判断是否队满。具体过程如下:
1)队列的结构体定义:
typedef struct
{
int data[maxsize];//假设maxsize为已定义的常量
int front,rear;
int tag;
}Queue;
//定义一个队列
Queue qu;
2)队列的各要素
qu.tag=0;
qu.front=qu.rear;//初始时
qu.front==qu.rear&&qu.tag==0;//对空条件
qu.front==qu.rear&&qu.tag==1;//队满条件
3)算法实现
void initQueue(Queue &qu)//初始化队列
{
qu.front=qu.rear=0;
qu.tag=0;
}
int isQueueEmpty(Queue qu)//判断队是否为空
{
if(qu.front==qu.rear&&qu.tag==0)
return 1;
else
return 0;
}
int QueueFull(Queue qu)//判断是否队满
{
if(qu.front==qu.rear&&qu.tag==0)
return 1;
else
return 0;
}
int enQueue(Queue &qu,int x)//元素进队
{
if(QueueFull(qu)==1)
return 0;
else
{
qu.rear=(qu.rear+1)%maxsize;
qu.data[qu.rear]=x;
qu.tag=1;//只要进队就把tag设置为1
return 1;
}
}
int deQueue(Queue &qu,int &x)//元素出队
{
if(isQueueEmpty(qu)==1)
return 0;
else
{
qu.front=(qu.front+1)%maxsize;
x=qu.data[qu.front];
qu.tag=0;//只要有元素出队,就把tag设置为0
return 1;
}
}
说明:对于tag值的设置,初始时一定为0,插入成功后应设置为1,删除成功后,应设置为0,因为只有在插入操作后,队列才有可能满,在删除操作后,队列才有可能空。tag的值再配合上front==rear这一句的判断就能正确区分队满与对空。
数据结构综合应用题15
编写一个算法,将一个非负的十进制整数N转换为一个二进制数。
解析:
int BaeTrans(int N)
{
int i,result=0;
int stack[maxsize],top=-1;
//定义并初始化栈,其中maxsize是已定义的常量,其大小足够处理本题数据
while(N!=0)
{
i=N%2;
N=N/2;
stack[++top]=i;
}
while(top!=-1)
{
i=stack[top];
--top;
result=result*10+i;
}
return result;
}
数据结构综合应用题16
试编写一个算法,检查一个程序中的花括号,方括号和圆括号是否配对,若全部配对,则返回1,否则返回0,对于程序中出现的一对单引号或者双引号内的字符不进行括号配对检查。39为单引号的ASCII值,34为双引号的ASCII值,单引号或双引号若要出现必须成对出现。
假设stack是已经定义的顺序栈结构体,可以直接调用元素进栈、出栈,取栈顶元素,判断栈空的函数定义如下:
void push(stack &S,char ch);
void pop(stack &S,char &ch);
void getTop(stack S,char &ch);
int isEmpty(stack S);//若栈S空,则返回1,否则返回0
解析:
在算法中,扫描程序中的每一个字符,当扫描到每个左花括号,左方括号,左圆括号时,令其进栈;当扫描到右花括号,右方括号,右圆括号时,则检查栈顶是否为相应的左括号,若是则做退栈处理,若不是则表明了语法错误,返回0.当扫描程序文件结尾后,若栈为空,则表明没有发现括号配对错误,返回1.否则表明栈中还有未配对的括号,返回0.另外,对于一对单引号或双引号内的字符不进行括号配对检查。代码如下:
int bracketsCheck(char f[])//对由字符数组f所存字符串中的文本进行括号配对检查
{
stack S;char ch;//定义一个栈
char* p=f;
while(*p!='\0')//顺序扫描串中的每一个字符
{
if(*p==39)
{
++p;//跳过第一个单引号
while(*p!=39)//39为单引号的ASCII值
++p;
++p;//跳过最后一个单引号
}
else if(*p==34)//双引号内的字符不参与配对比较
{
++p;//跳过第一个双引号
while(*p!=34)//34为双引号的ASCII值
++p;
++p;//跳过最后一个双引号
}
else
{
switch(*p)
{
case '{':
case '[':
case '(':push(S,*p);//出现左括号{[(进栈
break;
case '}':getTop(S,ch);
if(ch=='{')
pop(S,ch);//栈顶的左花括号出栈
else
return 0;
break;
case']':getTop(S,ch);
if(ch=='[')
pop(S,ch);//栈顶的左方括号出栈
else
return 0;
break;
case')':getTop(S,ch);
if(ch=='[')
pop(S,ch);//栈顶的左圆括号出栈
else
return 0;
}
++p;
}
}
if(isEmpty(S))
return 1;
else
return 0;
}