3_1
03、判断操作序列是否合法,合法,返回true,否则返回false
bool judge(char A[])//A[]用来存放字符数组
{
int i=0;//用于扫描字符数组
int j=k=0;//用于记录入栈和出栈次数
while(A[i]!='\0')
{
switch(A[i])
{
case 'I':j++//入栈次数加1
case 'O':k++//出栈次数加1
if(k>j) printf("序列不合法!"); //扫描过程中 出栈次数大于入栈次数 则不合理
}
i++;
}
if(j!=k)//扫描结束后 入、出栈次数不等 必定不合法
{
printf("序列不合法!");
return false;
}else
{
printf("序列合法")
return true;
}
}
//处理成前缀和
//将字符数组映射为下标从1开始的数字数组 'I'对应1 'O'对应-1
for(int i=1;i<=a.size()) s[i]=s[i-1]+a[i]; //前缀和
4、设单链表的表头指针为L,结点结构由data和next两个域构成,其中data域为字符型。试设计算法判断该链表的全部n个字符是否中心对称。例如xyx,xyyx都是中心对称。
//判断中心对称 思路:借助栈的思想
//先让前n/2个元素进栈 然后将p移到与其对称处 逐一扫描比较
//注意元素个数奇偶
bool judge_Centrosymmetric(LinkList L,int n)//n代表n个元素 L带头结点
{
int i;
int s[n/2];//用于存储前n/2个元素 以便判断是否是中心对称
LNode *p=L->next;//指向首元素结点
for(i=0;i<n/2;i++)
{
s[i]=p->data;
p=p->next;
}
i--;//恢复i值
//当元素个数为奇数时
if(n%2==1) p=p->next;//绕过中心结点
while(p!=NULL&&s[i]==p->data)
{
i--;//i向前移
p=p->next;//p向后移
}
if(i==-1)
{
printf("是中心对称!");
return true;
}else
{
printf("非中心对称!");
return false;
}
}
5、设有两个栈s1,s2都采用顺序栈方式,并共享一个存储区[0,...maxsize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶向下、迎面增长的存储方式,试设计s1、s2有关入栈和出栈的操作算法。
typedef struct{
ElemType data[maxsize];
int top1,top2;//top1表示从0开始增长的指针 top2表示从maxsize增长的指针
}SqStack;
SqStack S;
void Init(SqStack &S)//栈一、二的初始化
{
S.top1=-1;
S.top2=maxsize;
}
bool Push(SqStack &S,ElemType x1,ElemType x2)//x1和x2表示栈一、二分别入栈的元素
{
if(S.top2-S.top1==1) return false;//栈满不能入栈
S.data[++S.top1]=x1;
S.data[--S.top2]=x2;
return true;
}
bool Pop(SqStack &S,ElemType &x1,ElemType &x2)//用x1和x2分别接收出栈的元素
{
if(S.top1==-1) return false;//栈一空
else
{
x1=S.data[S.top1--];
}
if(S.top2==maxsize) return false;//栈二空
else
{
x2=S.data[S.top2--];
}
return true;
}
3_2
01、若希望循环队列中的元素都得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的队列状态是‘空’还是‘满’。编写与此结构相应的入队和出队算法
//带tag的入队操作
int EnQueue(SqQueue &Q,ElemType x)
{
if(Q.rear==Q.front&&Q.tag==1) return 0;//队满
Q.data[Q.rear]=x;
Q.rear=(Q.rear+1)%MaxSize;
Q.tag=1;//可能队满 所以每次入队都要使tag置为1
return 1;
}
//带tag的出队操作
int DeQueue(SqQueue &Q,ElemType &x)
{
if(Q.rear==Q.front&&Q.tag==0) return 0;//队空
x=Q.data[Q.front];
Q.front=(Q.front+1)%MaxSize;
Q.tag=0;//可能对空 每次出队时都要使tag置0
return 1;
}
2、Q是一个队列,S是一个空栈,实现将队列中的元素逆置的方法
//思路:将队列中元素依次出队压至栈中,再将栈中元素依次弹出压入队列
bool ReverseQueue(SqQueue &Q,SqStack &S)
{
if(IsEmpty(Q)) return false;//对空
while(!IsEmpty(Q))
{
x=DeQueue(Q);
Push(S,x);
}
while(!StackEmpty(S))
{
Pop(S,x);
EnQueue(Q,x);
}
return true;
}
03、利用两个栈S1,S2来模拟一个队列,已知栈的4个运算定义如下:
Push(S,x);//元素x入栈
Pop(S,x);//S出栈并将出栈的值赋给x
StackEmpty(S);//判断栈是否空
StackOverflow(S);//判断栈是否满
如何利用栈的运算来实现该队列的三个运算(形参有读者自己设计)
EnQueue;//入队
DeQueue;//出队
QueueEmpty;//判断队是否为空
//思路:
//对S2的出栈操作用作出队,若S2空,则先将S1中的元素送入S2
//对S1中的入栈操作用作入队,若S1满,必须先保证S2空,才能将S1中的元素全部插入S2中
//入队
int EnQueue(Stack &S1,Stack &S2,ElemType e)
{
//S1栈未满
if(!StackOverflow(S1))
{
Push(S1,e);
return 1;
}
//S1栈满而S2栈空 先将S1中元素Pop至S2 S1再入栈
if(StackOverflow(S1)&&StackEmpty(S2))
{
while(!StackEmpty(S1))
{
Pop(S1,x);
Push(S2,x)
}
Push(S1,e);
return 1;
}
//S1栈满而S2栈非空 则队列满
if(StackOverflow(S1)&&!StackEmpty(S2))
{
printf("队列满!");
return 0;
}
}
//出队
void DeQueue(Stack &S1,Stack &S2,ElemType &x)
{
if(!StackEmpty(S2)) Pop(S2,x);
//S1为空 则说明队列为空
if(StackEmpty(S1))
{
printf("队列为空!");
return ;
}
//S1不为空 将S1中元素Pop至S2 S2在出队
if(!StackEmpty(S1))
{
Pop(S1,x);
Push(S2,x);
}
Pop(S2,x);
}
//判断队列为空
int QueueEmpty(Stack &S1,Stack &S2)
{
if(StackEmpty(S1)&&StackEmpty(S2))
{
printf("队列为空!");
return 1;
}
else
{
return 0;
}
}
3_3
01、假设一个算术表达式中包含圆括号、方括号和花括号3种类型的括号,编写一个算法来判别表达式中的括号是否配对,以字符‘\0’作为算数表达式的结束符。
//括号匹配
//思路:遇到左括号,压入栈中,遇到右括号,退栈,如果退栈的括号与要匹配的括号不同类,则不匹配
bool BracketsCheck(char *str,SqStack &S)
{
//InitStack(S);
int i=0;
char e;//用于接收出栈元素
while(str[i]!='\0')
{
switch(str[i])
{
case '(':
case '[':
case '{':
Push(S,str[i]);
break;
case ')':
Pop(S,e);
if(e!='(')
{
printf("括号不匹配!\n");
return false;
}
break;
case ']':
Pop(S,e);
if(e!='[')
{
printf("括号不匹配!\n");
return false;
}
break;
case '}':
Pop(S,e);
if(e!='{')
{
printf("括号不匹配!\n");
return false;
}
break;
default:
break;
}
i++;
}
if(!StackEmpty(S))
{
printf("括号不匹配!\n");
return false;
}else
{
printf("括号匹配!\n");
return true;
}
}
02、按下图所示铁道进行车厢调度(两侧车道为单向行驶道,火车调度站有一个用于调度的‘栈道’),火车调度站的入口处有n节硬座和软座车厢(分别用H和S表示)等待调度,编写算法,输出对这n节车厢进行调度的操作(即入栈和出栈操作)序列,使所有的软座车厢都被调整到硬座车厢之前。
//思路若是H,则入栈;若是S 则继续扫描下一列火车;直到'\0',最终一次出栈
//用train[]表示原始火车序列 用pass[]表示调度火车
void AdjustTrain(char *train,char *pass)
{
InitStack(S);//初始化栈
int i=0,j=0;
while(train[i]!='\0')//H-代表硬座 S-代表软座
{
if(train[i]=='H')
{
Push(S,'H');
i++;
}else//若是软座 则通过 同时i后移扫描下一列火车
{
pass[j++]=train[i++];
}
}
while(!StackEmpty(S))//将栈内的硬座依次出栈并加入通过队列
{
Pop(S,e);
pass[j++]=e;
}
}
//王道写法 -思路差不多
void Train_Arrange(char *train)
{
char *p=train,*q=train;
char c;//接收出栈火车
stack s;
InitStack(s);
while(*p)
{
if(*p=='H')//硬座 入栈
Push(s,'H');
else
*(q++)=*p;//把S调到前部
p++;//更新指针p 指向下一列火车
}
while(!StackEmpty(s))
{
Pop(s,c);
*(q++)=c;//把H接在后部
}
}
03、利用一个栈实现以下递归函数的非递归计算
//用栈来保存对应n和P(x)的值——结构体
struct stack{
int num;//保存n值
double val;//保存计算结果P(x)
}st[MaxSize];
double P(int n,double x)
{
int top=-1;//st下标
double P1=1,P2=2*x;//n=0、1时的初值
while(i=n;i>=2;i--)
{
top++;
st[top].num=i;//top:0-n-2 num:n-2
}
while(top>=0)
{
st[top].val=2*x*P1-2*(st[top].num-1)*P2;
P1=P2;
P2=st[top].val;//P1、P2迭代进行跟新
//最终结果保存在P2;
top--;
}
if(n==0)
{
return P1;
}else
{
return P2;
}
}
4、某汽车轮渡口,过江渡船每次能载10辆车过江,过江车辆分为客车类和火车类,上渡船有下列规则:同类车先到先上船;客车先于货车上船;且每上4辆客车才允许上1辆货车;若等待客车不足4辆,则以货车代替;若无货车等待,允许客车都上船,试设计一个算法模拟渡口管理
Queue q,q1,q2;//q代表渡江队列 q1代表客车队列 q2代表货车队列
void Management()
{
int i=j=0;//j代表船上车辆数
while(j<10)//以5辆车为单位来考虑
{
if(i<4&&!QueueEmpty(q1))//客车队列不空
{
Dequeue(q1,x);
Enqueue(q,x);
i++;j++;
}else if(i==4&&!QueueEmpty(q2))//上4辆客车后 检查是否有货车等待
{
//货车队列不空 则让货车上船
Dequeue(q2,x);
Enqueue(q,x);
j++;//船上车数+1
i=0;//一个'5辆'完成 置i为0
}else
{
while(i<4&&!QueueEmpty(q2))//客车队列空
{
Dequeue(q2);
Enqueue(q);
i++;j++;
}
i=0;//置i为0
}
if(QueueEmpty(q1)&&QueueEmpty(q2))//货车、客车队列都为空 跳出循环
{
j=11;
}
}
}
第四章 串
01、在字符串模式匹配的KMP算法中,求模式的next数组值的定义如下:
1)当j=1时,为什么要取next[1]=0?
2)为什么要取max{k},k最大值是多少?
3)其他情况是什么情况,为什么取next[i]=1?
答:
1)当模式串中的第一个字符与主串的当前字符比较不相等时,next[1]=0,表示模式串应右移一位,主串与当前指针后移一位,再和模式串的第一个字符比较
2)当主串的第i个字符与模式串的第j个字符失配时,主串i不回溯,则假定模式串的第k个字符与主串的第i个字符比较,k值应满足条件1<k<j且'p1 ... pk'='pj-k+1 ... pj-1',即k为模式串的下次比较位置。k值可能有多个,为了不使向右移动丢失可能的匹配,右移距离应取最小,由于j-k表示右移的距离,所以取max{k}
3)除上面两种情况外,发生失配时,主串指针i不回溯,在最坏情况下,模式串从第一个字符开始与主串的第i个字符比较