1.栈和队列的定义和特点
1.1 栈的定义和特点
栈是一种后进先出的线性表,仅限在表尾进行插入或删除操作。表尾端称为栈顶,表头端称为栈底。不含元素的空表称为空栈。
1.2队列的定义和特点
队列是一种先进先出的线性表。队列中允许插入的一端称为队尾,允许删除的一段称为对头。
2.栈的表示和操作的实现
2.1 顺序栈的表示和实现
顺序栈的存储结构
#define MAXSIZE 100
typedef struct
{
SElemType *base; //栈底指针
SElemType *top; //栈顶指针
int stacksize; //栈可用的最大容量
}SqStack;
1.初始化
Status InitStack(SqStack &S)
{
//构造一个空栈S
S.base=new SElemType[MAXSIZE]; //为顺序栈动态分配一个最大容量为MAXSIZE的数组空间
if(!S.base) exit(OVERFLOW); //存储分配失败
S.top=S.base; //top初始为base,空栈
S.stacksize=MAXSIZE; //stacksize置为栈的最大容量MAXSIZE
return OK;
}
2.入栈
Status Push(SqStack &S,SElemType e)
{
//插入元素e为新的栈顶元素
if(S.top-S.base==S.stacksize) return ERROR; //栈满
*S.top++=e; //元素e压入栈顶,栈顶指针加1
return OK;
}
3.出栈
Status Pop(SqStack &S,SElemType &e)
{
//删除S的栈顶元素,用e返回其值
if(S.top==S.base) return ERROR; //栈空
e=*--S.top; //栈顶指针减1,将栈顶元素赋给e
return OK;
}
4.取栈顶元素
SElemType GetTop(SqStack S)
{
//返回S的栈顶元素,不修改栈顶指针
if(S.top!=S.base) //栈非空
return *(S.top-1); //返回栈顶元素的值,栈顶指针不变
}
2.2 链栈的表示和实现
链栈的存储结构
typedef struct StackNode
{
ElemType data;
struct StackNode *next;
}StackNode,*LinkStack;
1.初始化
Status InitStack(LinkStack &S)
{
//构造一个空栈S,栈顶指针置空
S=NULL;
return OK;
}
2.入栈
Status Push(LinkStack &S,SElemType e)
{
//在栈顶插入元素e
p=new StackNode; //生成新结点
p->data=e; //将新结点数据域置为e
p->next=S; //将新结点插入栈顶
S=p; //修改栈顶指针为p
return OK;
3.出栈
Status Pop(LinkStack &S,SElemType &e)
{
//删除S的栈顶元素,用e返回其值
if(S==NULL) return ERROR; //栈空
e=S->data; //将栈顶元素赋给e
p=S; //用p临时保存栈顶元素空间,以备释放
S=S->next; //修改栈顶指针
delete p; //释放原栈顶元素的空间
return OK;
4.取栈顶元素
SElemType GetTop(LinkStack S)
{
//返回S的栈顶元素,不修改栈顶指针
if(S!=NULL) //栈非空
return S->data; //返回栈顶元素的值,栈顶指针不变
3.栈与递归
遍历输出链表中各个结点的递归算法
void TraverseList(LinkList p)
{
if(p==NULL) return; //递归终止
else
{
cont<<p->data<<endl; //输出当前结点的数据域
TraverseList(p->next); //p指向后继结点继续递归
}
}
Hanoi塔问题的递归算法
void Hanoi(int n,char A,char B,char C)
{
//将塔座A上的n个圆盘按规则搬到C上,B做辅助
if(n==1) move(A,1,C); //将编号为1的圆盘从A移到C
else
{
Hanoi(n-1,A,C,B); //将A上编号为1至n-1的圆盘移到B,C做辅助塔
move(A,n,C); //将编号为n的圆盘从A移到C
Hanoi(n-1,B,A,C); //将B上编号为1至n-1的圆盘移到C,A做辅助塔
}
}
4.队列的表示和操作的实现
4.1 循环队列——队列的顺序表示和实现
队列的顺序存储结构
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef struct
{
QElemType *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
}SqQueue;
1.初始化
Status InitQueue(SqQueue &Q)
{
//构造一个空队列Q
Q.base=new QElemType[MAXQSIZE]; //为队列分配一个最大容量为MAXSIZE的数组空间
if(!Q.base) exit(OVERFLOW); //存储分配失败
Q.front=Q.rear=0; //头指针和尾指针置为零,队列为零
return OK;
}
2.求队列长度
int QueueLength(SqQueue Q)
{
//返回Q的元素个数,即队列的长度
return (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE;
}
3.入队
Status EnQueue(SqQueue &Q,QElemType e)
{
//插入元素e为Q的新的队尾元素
if((Q.rear+1)%MAXQSIZE==Q.front) //尾指针在循环意义上加1后等于头指针,表明队满
return ERROR;
Q.base[Q.rear]=e; //新元素插入队尾
Q.rear=(Q.rear+1)%MAXQSIZE; //队尾指针加1
return OK;
}
4.出队
Status DeQueue(SqQueue &Q,QElemType &e)
{
//删除Q的队头元素,用e返回其值
if(Q.front==Q.rear) return ERROR; //队空
e=Q.base[Q.front]; //保存队头元素
Q.front=(Q.front+1)%MAXQSIZE; //队头指针加1
return OK;
}
5.取队头元素
SElemType GetHead(SqQueue Q)
{
//返回Q队头元素,不修改队头指针
if(Q.front!=Q.rear)
return Q.base[Q.front];
}
4.2 链队——队列的链式表示和实现
队列的链式存储结构
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
1.初始化
Status InitQueue(LinkQueue &Q)
{
//构造一个空队列Q
Q.front=Q.rear=new QNode; //生成新结点作为头结点,队头和队尾指针指向此结点
Q.front->next=NULL; //头结点的指针域置空
return OK;
}
2.入队
Status EnQueue(LinkQueue &Q,QElemType e)
{
//插入元素e为Q的新的队尾元素
p=new QNode; //为入队元素分配结点空间,用指针p指向
p->data=e; //将新结点数据域置为e
p->next=NULL; Q.rear->next=p; //将新结点插入到队尾
Q.rear=p; //修改队尾指针
return OK;
}
3.出队
Status DeQueue(LinkQueue &Q,QElemType &e)
{
//删除Q的队头元素,用e返回其值
if(Q.front==Q.rear) return ERROR; //若队列空,则返回ERROR
p=Q.front->next; //p指向队头元素
e=p->data; //e保存队头元素的值
Q.front->next=p->next; //修改头指针
if(Q.rear==p) Q.rear=Q.front; //如果最后一个元素被删,队尾指针指向头结点
delete p; //释放原队头元素的空间
return OK;
}
4.取队头元素
SElemType GetHead(LinkQueue Q)
{
//返回Q的队头元素,不修改队头指针
if(Q.front!=Q.rear) //队列非空
return Q.front->next->data; //返回队头元素的值,队头指针不变
}
5.案例分析与实现
数制的转换
void conversion(int N)
{
//对于任意一个非负十进制数,打印输出与其等值的八进制数
InitStack(S); //初始化空栈S
while(N) //当N非零时,循环
{
Push(S,N%8); //把N与8求余得到的八进制数压入栈S
N=N/8; //N更新为N与8的商
}
while(!StackEmpty(S)) //当栈S非空时,循环
{
Pop(S,e); //弹出栈顶元素e
cout<<e; //输出e
}
}
括号匹配的检验
Status Matching()
{
//检验表达式中所含括号是否正确匹配,如果匹配,则返回true,否则返回false
//表达式以“#”结束
InitStack(S); //初始化空栈
flag=1; //标记匹配结果以控制循环及返回结果
cin>>ch; //读入第一个字符
while(ch!='#'&&flag) //假设表达式以“#”结尾
{
switch(ch)
{
case '['||'(': //若是左括号,则将其压入栈
Push(S,ch);
break;
case ')': //若是“)”,则根据当前栈顶元素的值分情况考虑
if(!StackEmpty(S)&&GetTop(S)=='(')
Pop(S,x); //若栈非空且栈顶元素是“(”,则正确匹配
else flag=0; //若栈空或栈顶元素不是“(”,则错误失败
break;
case ']': //若是“]”,则根据当前栈顶元素的值分情况考虑
if(!StackEmpty(S)&&GetTop(S)=='[')
Pop(S,x); //若栈非空且栈顶元素是“[”,则正确匹配
else flag=0; //若栈空或栈顶元素不是“[”,则错误匹配
break;
} //switch
cin>>ch; //继续读入下一个字符
} //while
if(StackEmpty(S)&&flag) return true; //匹配成功
else return false; //匹配失败
}
表达式求值
char EvaluateExpression()
{
//算术表达式求值的算符优先算法,设OPTR和OPND分别为运算符栈和操作数栈
InitStack(OPND); //初始化OPND栈
InitStack(OPTR); //初始化OPTR栈
Push(OPTR,'#'); //将表达式起始符“#”压入OPTR栈
cin>>ch;
while(ch!='#'||GetTop(OPTR)!='#') //表达式没有扫描完毕或OPTR的栈顶元素不为“#”
{
if(!In(ch)) //ch不是运算符则进OPND栈
{
Push(OPND,ch);
cin>>ch;
}
else
switch(Precede(GetTop(OPTR),ch)) //比较OPTR的栈顶元素和ch的优先级
{
case '<':
Push(OPTR,ch);v //当前字符ch压入OPTR栈,读入下一字符ch
cin>>ch;
break;
case '>':
Pop(OPTR,theta); //弹出OPTR栈顶的运算符
Pop(OPND,b); //弹出OPND栈顶的两个运算符
POP(OPND,a);
Push(OPND,Operate(a,theta,b)); //将运算结果压入OPND栈
break;
case '=': //OPTR的栈顶元素是“(”且ch是“)”
Pop(OPTR,x); //弹出OPTR栈顶的“(”,读入下一个字符ch
cin>>ch;
break;
} //switch
} //while
return GetTop(OPND); //OPND栈顶元素即为表达式求值结果
}
舞伴问题
跳舞者个人信息
typedef struct
{
char name[20]; //姓名
char sex; //性别,‘F’表示女性,‘M’表示男性
}Person;
队列的存储结构
#define MAXQSIZE 100 //队列可能达到的最大长度
typedef struct
{
Person *base; //队列中数据元素类型为Person
int front; //头指针
int rear; //尾指针
}SqQueue;
SqQueue Mdancers,Fdansers; //分别存放男士和女士入队者的队列
void DancePartner(Person dancer[],int num)
{
//结构数组dancer中存放跳舞的男女,num是跳舞的人数
InitQueue(Mdancers); //男士队列初始化
InitQueue(Fdancers); //女士队列初始化
for(i=0;i<num;i++)
{
p=dancer[i];
if(p.sex=='F') EnQueue(Fdancers,p); //插入女队
else EnQueue(Mdancers,p); //插入男队
}
cout<<"The dancing partners are:\n";
while(!QueueEmpty(Fdancers)&&!QueueEmpty(Mdancers))
{
//依次输出男女舞伴的姓名
DeQueue(Fdancers,p); //女士出队
cout<<p.name<<" "; //输出出队女士姓名
DeQueue(Mdancers,p); //男士出队
cout<<p.name<<endl; //输出出队男士姓名
}
if(!QueueEmpty(Fdancers)) //女士队列非空,输出队头女士的姓名
{
p=GetHead(Fdancers); //取女士队头
fout<<"The first woman to get a partner is: "<<p.name<<endl;
}
else if(!QueueEmpty(Mdancers)) //男士队列非空,输出队头男士的姓名
{
p=GetHead(Mdancers); //取男士队头
cout<<"The first man to get a partner is: "<<p.name<<endl;
}
}