【栈和队列】栈和队列的基本应用(C++版)

栈和队列的应用非常之广,只要问题满足后进先出和先进先出原则,均可使用栈和队列作为其数据结构。

(注意:在下面的代码中,我直接使用C++标准库提供的模板stack和queue,如果您用C语言,则要用前面介绍的方法自己实现stack和queue)

栈的应用

数制转换:

将一个非负的十进制整数N转换为另一个等价的基为B的B进制数的问题,很容易通过"除B取余法"来解决。

【例】将十进制数13转化为二进制数。

解答:按除2取余法,得到的余数依次是1、0、1、1,则十进制数转化为二进制数为1101。

分析:由于最先得到的余数是转化结果的最低位,最后得到的余数是转化结果的最高位,因此很容易用栈来解决。

具体算法如下:

#include <STACK>	//C++中使用栈要包含的头文件
using namespace std;//这个也是要加的

void conversion(int N,int B)
{//假设N是非负的十进制整数,输出等值的B进制数

	stack<int> S;		//创建一个元素类型为int型的空栈
	while(N)
	{
		S.push(N%B); //将转换后的数值,从底位到高位开始入栈
		N=N/B;
	}
	while(!S.empty())//栈非空时退栈输出
	{
		printf("%d",S.top());	//打印栈顶元素
		S.pop();	//将栈顶元素出栈
	}
}

int main()
{
	conversion(10,2);
}

表达式求值:

表达式求值是程序设计语言编译中的一个最基本的问题。我们讨论一种简单直观的方法“算法优先级法”

算术四则运算的规则

  1. 从左到右
  2. 先乘除后加减
  3. 先括号内,后括号外

相继出现的两个运算符优先级如下图:

【例】4 + 2*3 -10/5 每一步的计算顺序应该是:

4 + 2*3 -10/5 = 4 + 6 - 10/5 = 10 - 10/5 = 10 - 2 = 8

算法步骤:(我们假设表达式以字符‘#’结尾)

(1)首先,创建空运算符栈OPTR,将表达式起始符‘#’压入栈底,创建空操作数栈OPND

(2)依次读入表达式中的每个字符,若是操作数则进操作数栈,若是运算符则和运算符栈顶的运算符比较优先级后,做如下相应操作:

1.如果栈顶的运算符优先级较低,则把新的运算符压入OPTR;执行(2)

2.如果栈顶的运算符优先级较高,则将其 和 操作数栈的两个栈顶元素 退栈,计算3个元素组成的表达式的值,再压入操作数栈,然后继续判断;

3.如果栈顶的运算符优先级相等(除了#符外,只有‘(’和‘)’是相等的),则将‘(’出栈;执行(2)

(3)直到整个表达式求值完毕(即OPTR栈顶元素和当前读入的字符均为‘#’)

具体算法实现:

#include <iostream>
#include <stack>//C++中使用栈要包含的头文件

using namespace std;

//符号数组
char symbol[7] = {'+', '-', '*', '/', '(', ')', '#'};  

//栈内元素的优先级
int in[7] = {3, 3, 5, 5, 1, 6, 0};  

//栈外元素的优先级
int out[7] = {2, 2, 4, 4, 6, 1, 0};  

/*
 * 通过符号字符获取它的数组下标
 */
int get(char c)
{
    switch(c)
    {
    case '+':
        return 0;
    case '-':
        return 1;
    case '*':
        return 2;
    case  '/':
        return 3;
    case '(':
        return 4;
    case ')':
        return 5;
    case '#':
        return 6;
    default:
        return 6;
    }
}  

/*
 * 比较栈内运算符c1和栈外运算符c2的优先级
 */
char precede(char c1, char c2)
{
    int i1 = get(c1);
    int i2 = get(c2);  

    if(in[i1] > out[i2])
    {
        return '>';
    }
    else if(in[i1] < out[i2])
    {
        return '<';
    }
    else
    {
        return '=';
    }
}  

/*
 * 计算基本表达式的值
 */
int figure(int a, int theta, int b)
{
    switch(theta)
    {
    case 0:
        return a + b;
    case 1:
        return a - b;
    case 2:
        return a * b;
    default:
        return a / b;
    }
}  

/*
 * 计算表达式的值
 */
int EvaluateExpression(const char *exp)
{
    stack<int> OPND; //操作数栈
    stack<int> OPTR; //运算符栈
    OPTR.push(get('#'));

    int flag = 1; //表示正负号 1,表示正 0,表示负
    int a, theta, b;  

    if(!('+' == *exp || '-' == *exp || '(' == *exp || isdigit(*exp)))
    {//如果不是以'+'、'-'、'('或者数字的其中一个开头,则表达式错误
        cout << "表达式出错1" << endl;
        return -1;
    }
    if('+' == *exp)
    {
        exp++;//指向下一个字符
    }
	else if('-' == *exp)
    {
        flag = 0;
        exp++;//指向下一个字符
    }  

    int index = OPTR.top();				//获取运算符栈顶元素在数组的下标号
    while(*exp || symbol[index] != '#') //如果栈顶元素是'#'且当前元素为空结束计算
    {
        if(isdigit(*exp))
        {//如果当前元素是数字,计算整个操作数的值,然后压入操作数栈
            int sum = 0;
			while(isdigit(*exp))
			{//计算操作数的值
				sum = sum * 10 + (*exp - '0');
				exp++;
			}
			if (!flag)	//如果是负数
			{
				sum = -sum;
			}
            OPND.push(sum);
            flag = 1;
        }
        else
        {//如果不是数字
            switch(precede(symbol[OPTR.top()], *exp))//比较栈顶运算符和当前运算符的优先级
            {
            case '>' :
                b = OPND.top();
                OPND.pop();
                a = OPND.top();
                OPND.pop();
                theta = OPTR.top();
                OPTR.pop();
                OPND.push(figure(a, theta, b));
                break;
            case '<' :
                OPTR.push(get(*exp));
                if(*exp)
                {
                    exp++;
                }
                break;
            case '=' :
                OPTR.pop();
                if(*exp)
                {
                    exp++;
                }
                break;
            }
        }
        index = OPTR.top();
    }
    return OPND.top();
}  

int main()
{
	char c[50] = {0};
	cout << "请输入一个表达式: ";
    cin.getline(c,50);
	cout << EvaluateExpression(c) << endl;  

    return 0;
}

队列的应用

舞伴问题

1、问题叙述

 假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。若两队初始人数不相同,则较长的那一队中未配对者,等待下一轮舞曲。现要求写一算法模拟上述舞伴配对问题。

2、问题分析

 先入队的男士或女士亦先出队配成舞伴。因此该问题具体有典型的先进先出特性,可用队列作为算法的数据结构。

 在算法中,假设男士和女士的记录存放在一个数组中作为输入,然后依次扫描该数组的各元素,并根据性别来决定是进入男队还是女队。当这两个队列构造完成之后,依次将两队当前的队头元素出队来配成舞伴,直至某队列变空为止。此时,若某队仍有等待配对者,算法输出此队列中等待者的人数及排在队头的等待者的名字,他(或她)将是下一轮舞曲开始时第一个可获得舞伴的人。

3、具体算法及相关的类型定义

#include <QUEUE><span style="background-color: inherit; font-family: 微软雅黑; ">//C++中使用队列要包含的头文件</span>

using namespace std;
typedef struct
{
	char name[20];
	char sex; //性别,'F'表示女性,'M'表示男性
}Person;

void DancePartner(Person dancer[],int num)
{//结构数组dancer中存放跳舞的男女,num是跳舞的人数。

	Person p;
	queue<Person> Mdancers,Fdancers;

	for(int i = 0; i < num; i++)
	{//依次将跳舞者依其性别入队
		p=dancer[i];
		if(p.sex=='F')
			Fdancers.push(p); //排入女队
		else
			Mdancers.push(p); //排入男队
	}
	printf("The dancing partners are: \n \n");
	while(!(Fdancers.empty()||Mdancers.empty()))
	{
		//依次输入男女舞伴名
		p=Fdancers.front();		//获取女队第一人
		Fdancers.pop();			//出队
		printf("%s ",p.name);	//打印出队女士名

		p=Mdancers.front();		//获取男队第一人
		Mdancers.pop();			//出队
		printf("%s\n",p.name);	//打印出队男士名
	}
	if(!Fdancers.empty())
	{//输出女士剩余人数及队头女士的名字
		printf("\n There are %d women waitin for the next round.\n",Fdancers.size());
		p=Fdancers.front(); //取队头
		printf("%s will be the first to get a partner. \n",p.name);
	}
	else if(!Mdancers.empty())
	{//输出男队剩余人数及队头者名字
		printf("\n There are%d men waiting for the next round.\n",Mdancers.size());
		p=Mdancers.front();
		printf("%s will be the first to get a partner.\n",p.name);
	}
	else
	{
		printf("There is not person in the queue!");
	}
}//DancerPartners

int main()
{
	Person p[] = {{"A",'F'},{"B",'F'},{"C",'M'},{"D",'M'}};
	DancePartner(p,4);
}

结语:如果您不是打算从事C语言相关的底层开发的,只需要深刻理解部分数据结构的定义即可,至于具体的实现,简单了解,正如您所见的,底层的工作,C++已经帮您实现了!(您可以简单的理解为,这就是面向对象)

【栈和队列】栈和队列的基本应用(C++版)

时间: 2024-11-06 09:56:11

【栈和队列】栈和队列的基本应用(C++版)的相关文章

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型

import java.util.Stack; /**  * 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型.  * @author user  *  *思路:队列是先入先出,栈是先入后出,可以将数据压入第一个栈后,在弹出来压入第二个栈,弹得时候直接从第二个栈弹出,弹出后又将  *第二个栈中的所有数据弹出重新压入的一个栈  */ public class Solution {     Stack<Integer> stack1 = new Stack<

第三章:1.栈和队列 -- 栈的表示及实现

前言: 栈和队列 是两种重要的线性结构.从数据结构角度来看,栈和队列也是线性表,它的特殊性在于其操作是线性表的子集,是操作受限的线性表,因此可以称作限定性的数据结构. (限定性:如.人为的规定线性表只能从表尾插入和删除结点数据元素,那么这样的线性表就是栈) 目录: 1.栈 2.栈的应用举例 3.栈与递归的实现 4.队列 5.离散事件模型 正文: 栈的定义 栈(stack) 如上所说,就是限定只能在表尾进行插入和删除的线性表.表尾 称为 栈顶(top), 表头 称为 栈底 (bottom),没有数

算法(第四版)C#题解&mdash;&mdash;1.3.49 用 6 个栈实现一个 O(1) 队列

因为这个解法有点复杂,因此单独开一贴介绍. <算法(第四版)>中的题目是这样的: 1.3.49 栈与队列.用有限个栈实现一个队列,保证每个队列操作(在最坏情况下)都只需要常数次的栈操作. 那么这里就使用六个栈来解决这个问题. 这个算法来自于这篇论文. 原文里用的是 Pure Lisp,不过语法很简单,还是很容易看懂的. 先导知识--用两个栈模拟一个队列 如何使用两个栈来模拟一个队列操作? 这是一道很经典的题目,答案也有很多种,这里只介绍之后会用到的一种方法. 首先我们有两个栈,H 和 T,分别

两个栈实现队列+两个队列实现栈----java

两个栈实现队列+两个队列实现栈----java 一.两个栈实现一个队列 思路:所有元素进stack1,然后全部出stack1并进入stack2.实现队列的先进先出即:若stack2非空,我们需要的恰好再栈顶,出栈;若要给队列添加元素,即先进sack1,要出队时,若stack2不为空就出栈,为空时就把stack1全部进栈到stack2 二.两个队列实现一个栈 ps:图片原创于剑桥offer,来自网络 两个栈实现队列+两个队列实现栈----java,布布扣,bubuko.com

【C/C++学院】0828-STL入门与简介/STL容器概念/容器迭代器仿函数算法STL概念例子/栈队列双端队列优先队列/数据结构堆的概念/红黑树容器

STL入门与简介 #include<iostream> #include <vector>//容器 #include<array>//数组 #include <algorithm>//算法 using namespace std; //实现一个类模板,专门实现打印的功能 template<class T> //类模板实现了方法 class myvectorprint { public: void operator ()(const T &

剑指offer (7) 两个栈实现队列 两个队列实现栈

题目:用两个栈实现一个队列. 队列的声明如下,请实现它的两个函数 appendTail 和  deleteHead,分别完成队列尾部插入结点 和 队列头部删除结点 AppendTail:直接将元素入栈stack1 DeleteHead:当stack2中不为空时,在stack2中的栈顶元素是最先进入队列的元素,可以弹出 如果stack2为空,我们把stack1中的元素逐个弹出并入栈stack2,由于先进入队列的元素被压到stack1的底端,经过弹栈和压入stack2之后就处于stack2的顶端 1

栈,队列,优先级队列

---恢复内容开始--- 一.栈 1.栈:先进后出,后进先出,每次访问一个数据项,即最后一个添加的数据项(每次添加的数据放到最后).数据入栈和出栈的时间复杂度O(1),栈不需要移动和比较数据. 2.代码 1 public class Stack { 2 private int maxsize; 3 private int[] arr; 4 private int top; 5 6 public Stack(int s){ 7 maxsize = s; 8 arr = new int[maxsiz

数据结构之背包,队列,栈

1:数据抽象 概念: 抽象数据类型,是一种能够对使用者隐藏数据表示的数据类型,抽象数据类型之所以重要,是因为他在程序设计上支持封装. 本节目标:本节将介绍三种抽象类型,用java实现,背包,堆栈,队列等最简单的数据结构. 背包   背包是一种不支持从中删除元素的集合数据类型.他的目的就是帮助用例手机元素并迭代遍历所有收集到的元素.API图示参考1.1 import java.util.Iterator; import java.util.NoSuchElementException; /** b

数据结构&amp;算法(一)_堆、栈(堆栈)、队列、链表

堆: ①堆通常是一个可以被看做一棵树的数组对象.堆总是满足下列性质: ·堆中某个节点的值总是不大于或不小于其父节点的值: ·堆总是一棵完全二叉树.将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆.常见的堆有二叉堆.斐波那契堆等. ②堆是在程序运行时,而不是在程序编译时,申请某个大小的内存空间.即动态分配内存,对其访问和对一般内存的访问没有区别. ③堆是应用程序在运行的时候请求操作系统分配给自己内存,一般是申请/给予的过程. ④堆是指程序运行时申请的动态内存,而栈只是指一种使用

【12】python 栈型数据结构模拟、队列型数据结构模拟

一.压栈操作模拟 #__author:"吉*佳" #date: 2018/10/21 0021 #function:栈 # 栈:即是先进后出的一种数据结构 # (1)模拟压栈操作 stack=[] flag=True while flag: temp = input("请输入压栈元素[输入0代表退出]:") if temp!=str(0): stack.append(temp) else: print('压栈结束,栈内元素为:', stack) # 借助flag退出