数据结构笔记(三)栈和队列

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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值