栈和队列应用

栈解题秘籍

 
  • 在顺序栈中,栈顶指针指向的是栈顶元素的上一个位置,即空位置,取栈顶元素时要取*(S.top−1)才可以。入栈时,先把元素放入栈顶位置,然后栈顶指针后移,即*S.top=e;S.top++。出栈时,栈顶指针前移,用变量暂存栈顶元素,即e=−−S.top。
  • 出栈只是栈顶指针移动,空间元素仍然存在,但下次入栈时会覆盖

  • 本书以动态分配为例,静态分配的情况处理方式不同。静态分配是使用一个固定长度的数组存储数据,然后用一个int型的变量top指向栈顶,top实际上是数组的下标。当栈空时S.top=0。入栈时,先把元素放入栈顶位置,然后栈顶指针后移,即S.data[S.top++]=e。出栈时,栈顶指针前移,用变量暂存栈顶元素,即e=S.data[−−S.top]。

  • 可以利用栈将递归程序转换为非递归。递归是利用栈实现的,因此可以利用栈将递归程序转换为非递归程序。例如,第6章二叉树的遍历,都可以用栈将递归遍历转换为非递归遍历。

 

队列解题秘籍

为了避免假溢出,顺序队列一般采用循环队列。循环队列需要注意4个问题。

  • 队空:Q.front=Q.rear   //Q.front和Q.rear指向同一个位置
  • 队满:(Q.rear+1)%Maxsize==Q.front  //Q.rear后移一位正好是Q.front
  • Q.base[Q.rear]=e;//新元素插入队尾,Q.rear=(Q.rear+1)%Maxsize;//队尾指针加1
  • 出队:e=Q.base[Q.front];//保存队头元素,Q.front=(Q.front+1)%Maxsize;//队头指针加1
  • 元素个数:(Q.rear-Q.front+Maxsize)%Maxsize

 

数制的转换

题目:将一个十进制数转换为二进制数

思路:

十进制数转换为二进制,可以采用辗转相除、取余数的方法得到

先求出的余数是二进制数的低位,后求出的余数是二进制数的高位,将得到的余数逆序输出就是所要的二进制数,即11的二进制数为1011。如何将余数逆序输出呢?逆序输出正好符合栈的先入后出性质,因此可以借助栈来实现

复杂度:

#include <iostream>
using namespace std;
typedef int ElemType;
#define Maxsize 100  //预先分配空间,这个数值根据实际需要预估确定;
typedef struct SqStack{
	ElemType *base;
	ElemType *top;
}SqStack; 

bool InitStack(SqStack &S){
	S.base=new int [Maxsize];
	if(!S.base)return false;
	S.top=S.base;
	return true;
}

bool EmptyStack(SqStack &S){
	if(S.top==S.base)return true;
	return false;
}

bool Push(SqStack &S,ElemType e){
	if(S.top-S.base==Maxsize)return false;
	*S.top=e;
	S.top++;
	return true;
}

bool Pop(SqStack &S,ElemType &e){
	if(S.top==S.base)return false;
	S.top--;
	e=*S.top;
	return true;
}

int GetTop(SqStack S){
	if(S.top!=S.base)return *(S.top-1);
	else return -1;
}

void binaryconversion(int num){
	int e;
	SqStack S;
	InitStack(S);
	while(num){
		Push(S,num%2);
		num=num/2;
	}
	while(!EmptyStack(S))//如果栈不空
    {
        Pop(S,e);//出栈
        cout<<e<<"\t";//输出栈顶元素
    }
}
int main()
{
    int n;
    cout<<"请输入一个大于0的十进制整数:"<<endl;
    cin>>n;
    binaryconversion(n);
    return 0;
}

回文判定

题目:

回文是指正读反读均相同的字符序列,如“abba”和“abcscba”均是回文,也就是说字符串沿中心线对称,但“foot”和“bed”不是回文。试写一个算法判定给定的字符串是否为回文。

解题思路:

回文是中心对称的,可以将字符串前一半入栈,然后,栈中元素和字符串后一半进行比较。即将第一个出栈元素和后一半串中第一个字符比较,若相等,则再将出栈一个元素与后一个字符比较……直到栈空为止,则字符序列是回文。在出栈元素与串中字符比较不等时,则字符序列不是回文。

复杂度:

如果字符串长度为n,将前一半入栈,后一半依次和出栈元素比较,相当于扫描了整个字符串,因此时间复杂度为O(n),使用的栈空间大小是n/2,空间复杂度也为O(n)

#include<iostream>
#include<cstring>
typedef char Elemtype;//先类型定义为char 
#include"sqstack.h"//引入自定义头文件,源码目录下名为sqstack.h的文件   

using namespace std;

bool palindrome(char *str)//判断字符串是否为回文
{
    SqStack S;//定义一个栈S
    int len,i;
    char e;
    len=strlen(str);//返回字符串长度
    InitStack(S);//初始化栈
    for(i=0;i<len/2;i++)//将字符串前一半依次入栈
        Push(S,str[i]);
    if(len%2==1)//字符串长度为奇数,跳过中心点
        i++;
    while(!Empty(S))//如果栈不空
    {
        Pop(S,e);//出栈
        if(e!=str[i])//比较元素是否相等
            return false;
        else
            i++;
    }
    return true;
}

int main()
{
    char str[20];
    cout<<"请输入一个长度小于20的字符串:"<<endl;
    cin>>str;
    if(palindrome(str))
        cout<<"该字符串是回文!"<<endl;
    else
        cout<<"该字符串不是回文!"<<endl;
    return 0;
}

双端队列

题目:设计一个数据结构,使其具有栈和队列两种特性。

解题思路:

栈是后进先出,队列是先进先出,如何具有这两种特性呢?

允许两端都可以进行入队和出队的队列,就是双端队列

结构体定义

顺序存储,静态分配空间

注意:在顺序存储中,静态分配空间采用的是一维定长数组存储数据,动态分配空间是在程序运行中使用new动态分配空间

1)前端进队时,先令Q.front前移一位,再将元素放入Q.front的位置

2)后端进队时,先将元素放入Q.rear的位置,再令Q.rear后移一位

3)从后端出队,先令Q.rear前移一位,再将Q.rear位置元素取出

4)从前端出队,先将Q.front位置元素取出,再令Q.front后移一位

特点

1)后端进、前端出或者前端进、后端出体现了先进先出的特点,符合队列的特性。

2)后端进、后端出或者前端进、前端出体现了后进先出的特点,符合栈的特性。

循环队列实现的双端队列,具有栈和队列两种性质。

基本操作

1)初始化时,头指针和尾指针置为零,双端队列为空

#include <iostream>
using namespace std;
#define Maxsize 100
typedef char ElemType;
typedef struct SqQueue{
	ElemType base[Maxsize];
	int front,rear;
}DuQueue;

void InitQueue(DuQueue &Q){
	Q.front=Q.rear=0;//队头和队尾置为0,队列为空 
} 

bool isFull(DuQueue Q){
	if((Q.rear+1)%Maxsize==Q.front)return true;
	else return false;
} 

bool isEmpty(DuQueue Q){
     if(Q.front==Q.rear)
        return true;
     else
        return false;
 }

bool push_back(DuQueue &Q,ElemType e){//尾进 
	if(isFull(Q))return false;
	Q.base[Q.rear]=e;//先放入尾部
	Q.rear=(Q.rear+1)%Maxsize;//向后移动一位 
	return true; 
}

bool pop_back(DuQueue &Q,ElemType &x){//尾出 
	if(isEmpty(Q))return false;
	Q.rear=(Q.rear-1+Maxsize)%Maxsize;//防止为负,比如rear=0时
	x=Q.base[Q.rear];
	return true; 
} 

bool push_front(DuQueue &Q,ElemType e){//头进 
	if(isFull(Q))return false;
	Q.front=(Q.front-1+Maxsize)%Maxsize; //先向前移动一位 
	Q.base[Q.front]=e; //后放入
	return true;
} 

bool pop_front(DuQueue &Q,ElemType &e){//头出 
	if(isEmpty(Q))return false;
	e=Q.base[Q.front];
	Q.front=(Q.front+1)%Maxsize;
	return true; 
} 

bool get_front(DuQueue Q,ElemType &x){//取队头数据 
	if(isEmpty(Q))return false;
	x=Q.base[Q.front];
	return true;
}

bool get_back(DuQueue Q,ElemType &x){//取队尾数据 
	if(isEmpty(Q))return false;
	x=Q.base[(Q.rear-1+Maxsize)%Maxsize];
	return true;
}

int length(DuQueue Q){
	return (Q.rear-Q.front+Maxsize)%Maxsize;
} 

void traverse(DuQueue Q){
	int temp=Q.front;
	if(isEmpty(Q)) cout<<"队列为空";
	while(temp!=Q.rear){
		cout<<Q.base[temp]<<"  ";
		temp=(temp+1)%Maxsize;
	}
	cout <<"已遍历完";
}
int main()
{
    DuQueue DuQ;
    ElemType e,x;
    cout<<"1. 初始化\n";
	cout<<"2. 头进\n";
	cout<<"3. 头出\n";
	cout<<"4. 尾进\n";
	cout<<"5. 尾出\n";
	cout<<"6. 取队头\n";
	cout<<"7. 取队尾\n";
	cout<<"8. 求长度\n";
	cout<<"9. 遍历队列\n";
	cout<<"0. 退出\n";
	int choose=-1;
	while (choose!=0)
	{
        cout<<"请选择:";
		cin>>choose;
		switch(choose)
		{
		    case 1://初始化
		        cout << "双端队列初始化..." << endl;
		        InitQueue(DuQ);
		        break;
		     case 2://头进
		         cout << "从前端进队(头进)..." << endl;
		         cout << "请输入一个字符:" << endl;
		         cin>>e;
		         push_front(DuQ,e);
                 break;
            case 3://头出
                cout <<"从前端出队(头出)..."<< endl;
                pop_front(DuQ,x);
                cout << "出队元素为" <<x<< endl;
                break;
            case 4://尾进
                cout << "从后端进队(尾进)..." << endl;
		        cout << "请输入一个字符:" << endl;
                cin>>e;
                push_back(DuQ,e);
                break;
            case 5://尾出
                 cout <<"从后端出队(尾出)..."<< endl;
                pop_back(DuQ,x);
                cout << "出队元素为" <<x<< endl;
                break;
             case 6://取队头元素
                cout <<"取队头元素..."<< endl;
                get_front(DuQ,x);
                cout << "队头元素为" <<x<< endl;
                break;
            case 7://取队尾元素
                cout <<"取队尾元素..."<< endl;
                get_back(DuQ,x);
                cout << "队尾元素为" <<x<< endl;
                break;
            case 8://求队长
                cout << "双端队列长度:"<<length(DuQ)<<endl;
                break;
            case 9://遍历
                traverse(DuQ);
                break;
        }
	}
    return 0;
}

 

 

 

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值