第三章 栈、队列与数组
3.1 栈
3.1.03
假设以I和O分别表示入栈和出栈操作。栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,称可以操作的序列为合法序列,否则称为非法序列。(已存入一维数组中)
bool judge(char a[])
{
int i = 0, cnt = 0;
while(a[i]!='\0')
{
if(a[i]=='I') cnt++;
else if(a[i]=='O') cnt--;
if(cnt<0) return false;// too much in
}
if(cnt!=0) return false;
return true;
}
3.1.04
单链表,表头指针L,结点结构data和next,判断n个字符是否中心对称。
//用头插法先把前半部分颠覆,然后慢慢存,空间复杂度应该是O(1),时间复杂度为O(n)
typedef struct LinkList{
ElemType data;
LNode *next;
}LNode,*LinkList;
bool symmetry(LinkList &L)
{
LNode *p, *q, *r;
LinkList M = (LinkList)malloc(sizeof(LNode));
M->next == NULL;
p = M;
q = L->next;
r = q->next;
for(int i = 0; i<n/2; i++){
q->next = M->next;
M->next = q;
q = r;
r = r->next;
}
//now it's (an/2,...,a2,a1),and q points to the late half part of chain which includes mid
if(n%2==1) L->next = r;
else L->next = q;
p = M->next;
q = L->next;
while(q!=NULL)
{
if(p->data == q->data){
p = p->next;
q = q->next;
}
else return false;
}
return true;
}
//标准答案是存入栈的,因为这一章是栈而且还是得学,我再复现一下
int dc(LinkList L, int n)
{
int i;
LNode *p;
char s[n/2];
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--;
p = p->next;
}
if(i==-1)//空栈
return 1;
else return 0;
}
3.1.05
设有两个栈S1,S2都采用顺序栈方式,并且共享一个存储区[O…maxsize-1],为了尽量利用空间,减少溢出的可能,可采用栈顶相向,迎面增长的存储方式。
// define inn
#define maxsize 100
#define ElemType int
typedef struct{
ElemType stack[maxsize];
int num[2];//record the point of inn
}stack;
stack k;
k.num[0] = -1;
k.num[1] = maxszie;
int push(ElemType data, int inn_num)
{
if(inn_num>1||inn_num<0) return -1; //over bundary
if(num[0]-num[1]<=1){
printf("full!"); //毫无意义
return -1;
}
switch(i){
case 0: k.stack[++num[0]]=data; return 1; break;
case 1: k.stack[--num[1]]=data; return 1; break;
}
return 0;
}
ElemType pop(int i)
{
if(i<0||i>1) exit(-1);
switch(i){
case 0:
if(num[0] == -1){
printf("empty!");
return -1;
}
else return k.stack[num[0]--];
break;
case 1:
if(num[1] == maxsize){
printf("empty!");
return -1;
}
else return k.stack[num[1]++];
}
return 0;
}
后记
return与exit之我见
看到答案里有用exit的return -1的情况,感觉很迷惑,return -1理论上指的也是错误返回,exit(0)是正常退出,但是他越界等错误,应该exit(-1)差不多,后来查了查,如果出现这种错误,说明程序彻底错了,这个时候就应该exit(0)(我感觉用什么数字都可以)正常结束一整个程序而不是这个function。如果是栈空等基本操作的时候就会返回return -1,但是返回0是正常还是1是正常也是很多元化,我的评价是没啥区别,凑合凑合都能用。
3.2 队列
3.2.01
若希望循环队列中的元素都能得到利用,则需设置一个标志域tag,并以tag的值为0或1来区分队头指针front和队尾指针rear相同时的队列状态是“空”还是“满”。试编写与此结构相应的入队和出队算法。
#define MaxSize 50
typedef struct{
int tag;
int front, rear;
int data[MaxSIze];
}Queue;
int EnQueue(Queue &L, ElemType x)
{
if(Q.front == Q.rear && Q.tag == 1) exit(-1);
Q.rear = (Q.rear+1)%MaxSize;
Q.tag = 0;
return 1;
}
int DeQueue(Queeu &L, ElemType &x)
{
if(Q.rear==Q.front && Q.tag == 0) exit(-1);
x = Q.data[Q.front];
Q.front = (Q.front+1)%MaxSize;
Q.tag = 0;
return 1;
}
3.2.03
利用两个栈S1,S2来模拟一个队列,已知栈的4个运算定义如下:
Push(S,x);//元素x入栈
Pop(S,x) ;//S出栈并将出栈的值赋给x
StackEmpty(S) ;//判断栈是否为空
StackOverflow(S) ;// 判断栈是否满
如何利用栈的运算来实现该队列的3个运算(形参根据要求自己设计)?
Enqueue ;//将元素x入队
Dequeue ;//出队,并将出队元素存储在x中
QueueEmpty;/ /判断队列是否为空
思路:woc这也太难了,利用两个栈S1和S2来模拟一个队列,当需要向队列中插入一个元素时,用S1来存放已经输入的元素,需要出队的时候用S2执行操作。感觉有点像倒筒子,这题真的出的稀烂!
void Enqueue(Stack &S1, Stack &S2, ElemType x)
{
if(!StackOveflow(S1)){
Push(S1,x);
return 1;
}
if(StackOverFlow(S1)&&!StackEmpty(S2)){
exit(-1);//队列满
}
while(!StackEmpty(S1)){
Pop(S1,x);
Push(S2,x);
}
Push(S1,x);
return 1;
}
void DeQueue(Stack &S1, Stack &S2, ElemType &x)
{
if(!StackEmpty(S2)) Pop(S2,x);
else if(StackEmpty(S1)){
printf("队列为空");
return -1;
}
else{
while(!StackEmpty(S1)){
Pop(S1,x);
Push(S2,x);
}
Pop(S2,x);
}
}
int QueueEmpty(Stack &S1, Stack&S2)
{
if(StackEmpty(S1)&&StackEmtpy(S2)) return 1;
return 0;
}
3.3 栈和队列的应用
3.3.01
假设一个算数表达式中包含圆括号、方括号和花括号3种类型的括号,编写一个算法来判别表达式中的括号是否配对,以字符’\0’作为结束符
bool match(char a[])
{
InitStack(S);
int i = 0;
while(str[i]!='\0'){
switch(str[i]){
case '(': Push(S,'('); break;
case '[': Push(S,'['); break;
case '{': Push(S,'{'); break;
case ')': Pop(S,e); if(e!='(') return false; break;
case ']': Pop(S,e); if(e!='[') return false; break;
case '}': Pop(S,e); if(e!='{') return false; break;
default: break;
}
i++;
}
if(!IsEmpty(S)){
printf("不匹配捏");
return false;
}
else{
printf("匹配");
return true;
}
}
3.3.02
按下图所示铁道进行车厢调度(注意,两侧铁道均为单向行驶道,火车调度站有一个用于调度的“栈道”), 火车调度站的入口处有n节硬座和软座车厢(分别用H和S表示)等待调度,试编写算法,输出对这n节车厢进行调度的操作(即入栈或出栈操作)序列,以使所有的软座车厢都被调整到硬座车厢之前。
void sort(char a[])
{
char *q = a, tmp;
InitStack(S);
int i = 0;
while(a[i]!='H'&&a[i]!='S'){
if(a[i]=='H') push(S,a[i]);
else *(q++)= a[i];
i++;
}
while(!StackEmpty(s)){
Pop(S,tmp);
*(q++) = tmp;
}
}
3.3.04
某汽车轮渡口,过江渡船每次能载 10 辆车过江。过江车辆分别为客车类和货车类,上船有如下规定:同类车先到先上船,客车先于货车上渡船,且每上 4 辆客车,才允许上一辆货车;若等待客车不足 4 辆则以货车代替;若无货车等待则允许客车都上船。设计一个算法模拟渡口管理。
Queue q;//ferry
Queue q1;//passenger
Queue q2;//trunk
void manage_port() //p代表车列
{
int i=0, j=0;
while(j<10){
if(!QueueEmpty(q1)&&i<4){
DeQueue(q1, x);
EnQueue(q, x);
i++;
j++;
}
else if(!QueueEmpty(q2)&&i==4){
DeQueue(q2, x);
EnQueue(q, x);
j++;
i = 0;
}
else{ //passenger line is not full
while(j<10&&i<4&&!QueueEmpty(q2)){
DeQueue(q2, x);
EnQueue(q, x);
i++;
j++;
}
i = 0;
}
if(QueueEmpty(q1)&&QueueEmpty(q2)) j = 11;
}
}