提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
顺序栈
typedef struct{
int top;
int data[maxSize];
}SqStack;
链栈结点
typedef struct LNode{
int data;
struct LNode *next;
}LNode;
顺序队列
typedef struct{
int front;
int rear;
int data[maxSize];
}SqQueue;
链队列
typedef struct QNode{
int data;
struct QNode *next;
}QNode;
typedef struct{
QNode *front;
QNode *rear;
}LiQueue
基本操作
一、顺序栈操作
初始化
void initStack(SqStack &st){
st.top = -1;
}
判断栈空
int isEmpty(SqStack st){
return top == -1?1 :0;
}
进栈 [上溢]
[注意边界条件!!!] 栈满 top=maxSize-1
int push(SqStack &st, int x){
if(st.top == maxSize-1)
return 0;
st.data[++st.top] = x;
return 1;
}
出栈 [下溢]
[注意边界条件!!!] 栈空 top=-1
int pop(SqStack &st, int &x){
if(top == -1)
return 0;
x = st.data[st.top--];
return 1;
}
二、链栈
初始化
void initStack(LNode *&lst){
lst = (LNode*)malloc(sizeof(LNode));
lst -> next = NULL;
}
判断栈空
void isEmpty(LNode *lst){
if(lst->next == NULL)
return 1;
return 0;
}
进栈 [头插法]
void push(LNode *&lst, int x){
LNode *p = (LNode*)malloc(sizeof(LNode));
p->data = x;
p->next = lst->next;
lst->next = p;
}
出栈
[释放结点] 栈空 lst->next=NULL
int pop(LNode *&lst, int &x){
LNode *p;
if(lst->next == NULL)
return 0;
p = lst->next;
lst = lst->next->next;
x = p->data;
free(p);
return 1;
}
三、顺序队
初始化
队空:front=rear
void initQueue(SqQueue &qu){
qu.front = qu.rear = 0;
}
判断队空
int isEmpty(SqQueue qu){
return qu.front == qu.rear;
}
进队
先移动rear,再赋值
int offer(SqQueue &qu, int x){
if((qu.rear + 1)%maxSize == qu.front){
return 0;
}
********************************
*qu.rear = (qu.rear+1)%maxSize;*
********************************
qu.data[qu.rear] = x;
return 1;
}
出队
先移动front,再赋值
int remove(SqQueue &qu, int &x){
if(qu.rear == qu.front){
return 0;
}
*********************************
*qu.front= (qu.front+1)%maxSize;*
*********************************
x = qu.data[qu.front];
return 1;
}
真题仿造
-
为了充分利用空间,顺序栈s0、s1共享一个存储区elem[0,…, maxSize-1]试设计共享栈s0、s1以及有关入栈和出栈操作的算法,假设中元素为int型。要求:
-
给出基本设计思想
[Hint] 栈顶指针相向移动
栈底设在存储区的两端,即s0栈底设在下标0处,s1栈底设在下标maxSize-1处
栈顶在0~maxSize-1的范围内变动,当两栈栈顶相遇时为栈满。 -
根据设计思想,采用C或C++语言描述算法(对于共享栈要写出其结构定义),关键之处给出注释
//共享栈栈结构体定义 typedef struct{ int top[2]; // top[0]为s0栈顶,top[1]为s1栈顶 int elem[maxSize]; }SqStack; // 入栈 int push(SqStack &st, int stNo, int x){ //stNo是栈的编号 if(st.top[0] + 1 ==st.top[1]) return 0; // 栈满后不能入栈,返回0 if(stNo == 0){ ++(st.top[0]); st.elem[st.top[0]] = x; return 1; // 入栈成功,返回1 }else if(stNo == 1){ --(st.top[1]); st.elem[st.top[1]] = x; return 1; }else return -1; // 栈编号输入有误,返回-1 } // 出栈 int pop(SqStack &st, int stNo, int &x){ if(stNo == 0 && st.top[0]!=-1){ // st0栈且不空 x = st.top[0]--; return 1; // 出栈成功,返回1 }else if( stNo == 1 && st.top[1]!=maxSize){ // st1栈且不空 x = st.top[1]++; return 1; // 出栈成功,返回1 }else return 0; // 出栈错误,返回0; }
-
-
请利用两个栈s1和s2来模拟一个队列,假设中元素为int型,栈中元素最多为 maxSize。已知的3个运算定义如下。
push(ST,x):元素x入ST栈
pop(ST,&x):ST栈顶元素出栈,赋给变量x
isEmpty(ST):判断ST栈是否为空如何利用的运算来实现该队列的3个运算: enQueue(元素入队列)、 deQueue(元素出队列) isQueueEmpty(判断队列是否为空,空返回1,不空返回0)。要求:
(1)给出基本设计思想
s1为输入栈:逐个元素进栈,模拟入队
s2为输出栈:将s1中元素退栈后逐个压入s2栈。s1最先入栈的元素在s2中处于栈顶。s2退栈,模拟出队
当s1,s2 均为空 时,队列为n空(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。
typedef struct{ int data[maxSize]; int top = -1; }SqStack; // 入队 int enQueue(SqStack &s1, SqStack &s2, int x){ int y; if(s1.top == maxSize-1){ if(!isEmpty(s2)) return 0; // s1满,s2非空,这时s1不能再入栈,返回0 else{ while(!isEmpty(s1)){ //s1满,s2空,将s1中元素逐个退栈并压入到s2中 pop(s1, y); push(s2, y); } push(s1, x); return 1; } } // s1没有满,直接入栈 push(s1, x); return 1; } //出栈 int deQueue(SqStack &s2, SqStack &s1, int &x){ if(isEmpty(s2)){ if(isEmpty(s1)) return -1; // 两个栈中均无元素,队列为空 int y; while(!isEmpty(s1)){ //s2空,s1不为空,将s1中元素逐个退栈并压入s2中 pop(s1, y); push(s2, y); } pop(s2, x); return 1; } // s2不空,直接出栈 pop(s2, x); return 1; } //判断队列是否为空 int isQueueEmpty(SqStack s1, SqStack s2){ return isEmpty(s1) && isEmpty(s2); }
基础题
-
铁路进行列车调度时,常把站台设计成栈式结构,试问:
-
设有编号为1,2,3,4,5,6的6辆列车,顺序开入栈式结构的站台,则可能的出栈序列有多少种?
f ( n ) = 1 n + 1 C 2 n n = 1 6 + 1 C 12 6 f(n)=\frac{1}{n+1}C_{2n}^{n}=\frac{1}{6+1}C_{12}^{6} f(n)=n+11C2nn=6+11C126
-
若进站的6辆列车顺序如上所述,那么是否能够得到 435612 、 326541 、 154623 、 135426 435612、326541、154623、135426 435612、326541、154623、135426的出站序列?如果不能,说明为什么不能如果能,说明如何得到(写出进栈或出栈的序列)
不能得到:435612,154623
因为若在4,3,5,6之后再将1,2出栈,则1,2必须一直在栈中,此时1先进栈,2后进栈,2应在1的上面,不可能先于1,2。同理。
-
-
试证明:若借助可由输入序列1,2,3,…,得到一个输出序列p1,p2,p3,…pn(它是输入序列的某一种排列),则在输出序列中不可能出现以下情况:存在i,j,k,使得pj<pk<pi(提示用反证法)
必要性:
当i<j<k时,进栈顺序时i,j,k,这3个元素的出栈的相对顺序时pi,pj,pk。当较大的数首先出栈时,那些较小的数都是降序压在栈内的。这些数不可能正序出栈充分性:
如果pj<pk<pi成立,表明当i<j<k时各元素进栈、出栈后的相对顺序 为pj,pk,pi
当j<k时,pj<pk,表明pj必须在pk进栈之前就出栈,否则pj就被压在pk下面了
当i<k时,pk<pi,表明pi是先于pk进栈的
综上所述可知,这与正确的出栈顺序pi<pj<pk相矛盾 -
假设以I和O分别表示入栈和出栈操作。若栈的初态和终态均为空,入栈和出栈的操作序列可表示为仅由I和O组成的序列,则称可以操作的序列为合法序列,否则称为非法序列
-
试指出判别给定序列是否合法的一般规则
- 给定序列中,I的个数和O的个数相等
- 从给定序列的开始到给定序列的任一位置,I的个数要大于或等于O的个数
-
两个不同的合法序列(对两个具有同样元素的输入序列)能否得到相同的输出元素序列?如能得到,请举例说明
可以得到相同的输出元素序列
例如:输入元素为A,B,C,则两个输入序列A,B,C和B,A,C均可得到输出元素序列A,B,C。对于输入 序列A,B,C,使用IOIOIO操作序列;对于输入序列B,A,C,使用IIOOIO操作序列 -
写出一个算法,判定所给的操作序列是否合法。若合法,返回1,否则返回0(假定被判定的操作序列已存入一维char型数组ch[]中,操作序列以“\0”为结束符)
int judge(char ch[]){ int i=0; int I=0,O=0; while(ch[i]!='\0'){ if(ch[i]=='I') ++I; if(ch[i]=='O') ++O; if(O>I) return 0; ++i; } if(I!=0) return 0; else return 1; }
-
-
有5个元素,其入栈次序为A,B,C,D,E,在各种可能的出栈次序中,以元素C,D最先出栈(C第一个且D第二个出栈)的次序有哪几个?
-
写出下列中缀表达式的后缀形式(单目运算操作,如!A的后缀表达式为A!)
-
A*B*C
A B*C *
-
-A + B - C + D
A-B+C-D+
-
C-A*B
CAB*-
-
(A+B) * D + E/(F + A * D) + C
AB+D * EFAD * +/+C+
-
(A&&B)||(!(E>F))
AB&& EF>! ||
-
(!( A&& ( ! ( ( B<C ) || ( C>D )))))||(C<E)
这里是引用
-