第三章 栈、队列、数组
(一)栈
03.若I表示进栈操作,O表示出栈操作,栈的初态和终态为空。假设被判定的操作序列已存入一维数组中,判断所给序列是否合法。合法返回true,非法返回false。
bool Judge(char A[]){ int push=0,pop=0; for(int i=0;A[i]!='\0';i++){ switch(A[i]){ case 'I' : push++; case 'O' : pop++; } if(pop>push) return false; } return push==pop; } |
04.设单链表的表头指针为L,结点结构为data next,data为字符型,判断该链表的全部n个字符是否中心对称。
bool JudgeSymmetry(LinkList L,int n){ int top=-1; char S[n/2]; LNode *r = L->next; for(int i=0;i<n/2;i++){ // 一半元素入栈 S[++top] = r->data; r = r->next; } if(n%2==1) // 奇数个字符-->跳过中间的字符 r = r->next; while(r!=NULL){ // 遍历后半部分并对比 if(r->data != S[top--]) return false; r = r->next; } return true; } |
05.设有两个栈s1,s2都采用顺序栈方式,并共享一个存储区[0, ... ,maxsize-1]采用栈顶相向,迎面增长的方式。设计s1,s2有关入栈、出栈的操作算法。
typedef struct{ ElemType data[MaxSize]; int top1,top2; }DSeqStack; void InitStack(DSeqStack &S){ S.top1 = -1; S.top2 = MaxSize; } bool Push(DSeqStack &S,int num,ElemType x){ if(S.top1+1 = S.top2) return false; if(num==1) S.data[++S.top1] = x; if(num==2) S.data[--S.top2] = x; return true; } bool Pop(DSeqStack &S,int num,ElemType &x){ if(num==1){ if(S.top1==-1) return false; x = S.data[S.top1--]; return true; } if(num==2){ if(S.top2==MaxSize) return false; x = S.data[S.top2++]; return true; } } |
(二)队列
01.希望循环队列中的元素都能得到利用,设置tag域,以tag的0/1区分头尾指针相同时,队列状态是空还是满,编写相应的入队出队算法。
typedef struct{ ElemType data[MaxSize]; int front,rear; bool tag; }SeqQueue; bool InitQueue(SeqQueue &Q){ Q.rear = Q.front = 0; } bool EnQueue(SeqQueue &Q,ElemType x){ if(Q.rear==Q.front && Q.tag==1) return false; Q.data[Q.rear] = x; Q.rear = (Q.rear+1)%MaxSize; Q.tag = 1; return true; } bool DeQueue(SeqQueue &Q,ElemType &x){ if(Q.rear==Q.front && Q.tag==0) return false; x = Q.data[Q.front]; Q.front = (Q.front+1)%MaxSize; Q.tag = 0; return true; } |
02.Q是一个队列,S是一个空栈,实现将队列中的元素逆置的算法。
typedef struct{ ElemType data[MaxSize]; int top; }SeqStack; typedef struct{ ElemType data[MaxSize]; int front,rear; }SeqQueue; void InitStack(SeqStack &S){ S.top = -1; } void InitQueue(SeqQueue &Q){ Q.rear = Q.front = 0; } bool Push(SeqStack &S, ElemType x){ if(S.top==MaxSize-1) return false; S.data[++S.top] = x; return true; } bool Pop(SeqStack &S,ElemType &x){ if(S.top==-1) return false; x = S.data[S.top--]; return true; } bool EnQueue(SeqQueue &Q, ElemType x){ if((Q.rear+1)%MaxSize==Q.front) // 队满 return false; Q.data[Q.rear] = x; Q.rear = (Q.rear+1)%MaxSize; return true; } bool DeQueue(SeqQueue &Q, ElemType &x){ if(Q.rear==Q.front) return false; x = Q.data[Q.front]; Q.front = (Q.front+1)%MaxSize; return true; } bool Reverse(SeqQueue &Q,SeqStack &S){ ElemType x; while(DeQueue(Q,x)) // 正常是先判空再进行操作,此处较为巧妙,合二为一。 Push(S,x); while(Pop(S,x)) EnQueue(S,x); } |
03.利用两个栈S1,S2模拟一个队列,已知栈的四个运算定义如下。Push(S,x);Pop(S,x);StackEmpty(S) ;StackOverflow(S); 如何利用栈的运算实现该队列的3个运算。Enqueue;Dequeue;QueueEmpty;
bool QueueEmpty(SeqStack S1,SeqStack S2){ return StackEmpty(S1) && StackEmpty(S2); } // 思路:S1的入栈作为入队(若S1满,保证S2为空才能全部转移到S2中) S2的出栈作为出队(出队时要把S1的元素入栈S2,S2再出栈) bool EnQueue(SeqStack &S1,SeqStack &S2,ElemType x){ ElemType temp; if(!StackOverFlow(S1)){ // S1未满 Push(S1,x); return true; }else if(StackOverFlow(S1) && StackEmpty(S2)){ // S1满 S2空 while(!StackEmpty(S1)){ Pop(S1,temp); Push(S2,temp); } Push(S1,x); return true; }else{ // S1满 S2非空 return false; } } bool DeQueue(SeqStack &S1,SeqStack &S2){ ElemType temp; if(!StackEmpty(S1) && StackEmpty(S2)){ // S1非空 S2空 while(!StackEmpty(S1)){ Pop(S1,temp); Push(S2,temp); } Pop(S2,temp); return true; }else if(!StackEmpty(S2)){ Pop(S2,temp); return true; }else{ return false; } } |
04.设计一个队列,初始时为空,入队时允许增加空间,出队后原有空间可以重复使用,整个队列占用空间只增不减,入队出队操作的时间复杂度为O(1).
typedef struct LNode{ int data; struct LNode *next; }LNode; typedef struct{ LNode *front,*rear; }LiQueue; void InitQueue(LiQueue &Q){ Q.rear = Q.front = (LNode *)malloc(sizeof(LNode)); // 预留了一个结点 Q.rear->next = Q.front; } void EnQueue(LiQueue &Q,ElemType x){ if(Q.rear->next == Q.front){ // 入队后无空余结点 Q.rear->data = x; // 创建一个空结点,以供下次入队使用 LNode *q = (LNode *)malloc(sizeof(LNode)); Q.rear->next = q; Q.rear = q; q->next = Q.front; }else{ // 有至少两个空余结点 Q.rear->data = x; Q.rear = Q.rear->next; } } bool DeQueue(LiQueue &Q,ElemType &x){ if(Q.rear==Q.front) return false; x = Q.front->data; Q.front = Q.front->next; return true; } |
(三)栈和队列的应用
01.一个算数表达式中包括()[]{}三种括号,编写算法判断表达式中括号是否配对,以字符'\0'作为算数表达式的结束值。
void BracketCheck(char *str){ Stack(S); InitStack(S); char temp; int index=0; while(str[index]!='\0'){ if(str[index]=='(' || str[index]=='[' || str[index]=='{') Push(S,str[index]); if(str[index]==')' || str[index]==']' || str[index]=='}'){ Pop(S,temp); if(str[index]==')' && temp!='(') return false; // 左、右括号单身 if(str[index]==']' && temp!='[') return false; if(str[index]=='}' && temp!='{') return false; } i++; } return StackEmpty(S); // 括号数量是否匹配 } |
02.车厢调度,在单行道中间有一个调度站,共有n节车厢,硬座记为H,软座记为S。编写算法,输出对n节车厢进行调度的操作(入栈出栈)序列,使得所有软座调整在硬座之前。
void TrainOperate(char *train){ Stack(S); InitStack(S); char *out = train; char *r = train; char temp; while(*r){ if(*r == 'H') Push(S,*r); // 硬座 --> 进栈 else *(out++) = *r; // 软座 --> 调整到前部 r++; } while(!StackEmpty(S)){ Pop(S,temp); *(out++) = temp; } } // 知识点:'\0'---false "\0"---true // 当指针p指向一个字符串时,最初一次的 *p 和 *(p++) 是相同的,都是指向第一个字符 |
03.使用一个栈实现以下递归函数的非递归计算。
Pn(x)=1 n=0 Pn(x)=2 * x n=1
Pn(x)=2 * x * P_n-1(x)-2(n-1)P_n-2(x) n>1
double Compute(int n,double x){ typedef struct{ int n; double out; }Deal; Stack(S); InitStack(S); double out_0 = 1; double out_1 = 2*x; for(int i=n;i>=2;i--) S.data[++S.top].n = i; while(S.top>=0){ S.data[top].out = 2 * x * out_1 - 2 * ((S.data[S.top].n)-1) * out_0; out_0 = out_1; out_1 = S.data[top].out; S.top--; } // n (0 1) 2 3 4 5 栈顶 <---- 栈底 // out0 out1 top // n (0 1) 2 3 4 5 栈顶 <---- 栈底 // out0 out1 top if(n==0) return 1; else if(n==1) return 2*x; else return out_1; } // 注意点:1)栈最后是空的,不能返回栈中的数据 |
04.某汽车轮渡口,船能载10辆车。车辆分为客车和货车,同类车先到先上船;客车先于货车上船,每上四辆客车才上一辆货车;若等待客车不足四辆则以货车代替;若无货车等待,允许客车都上船。
void Harbour(Queue &Ship,Queue &Car,Queue &Truck){ int sum = 0; int num_car = 0; while(sum<10){ if(!QueueEmpty(Car) && num_car<4){ // 客车先于货车上船 DeQueue(Car,x); EnQueue(Ship,x); num_car++; sum++; }else if(num_car == 4 && !QueueEmpty(Truck)){ // 每上四辆客车才上一辆货车 DeQueue(Truck,x); EnQueue(Ship,x); num_car = 0; sum++; }else if(num_car == 4 && QueueEmpty(Truck)){ // 若无货车等待,允许客车都上船 while(sum<10 && QueueEmpty(Truck)){ DeQueue(Car,x); EnQueue(Ship,x); sum++; } }else{ while(sum<10 && num_car<4 && !QueueEmpty(Truck)){ // 等待客车不足四辆则以货车代替 DeQueue(Truck,x); EnQueue(Ship,x); num_car++; sum++; } } if(QueueEmpty(Car) && QueueEmpty(Truck)) sum = 999; } } |