第三章 栈、队列和数组

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个字符比较

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值