数据结构 第三章 栈 和 队列
栈和队列 都是一种受限的线性表。
【栈】stack
特性: 先进后出的线性表 LIFO
比如:放盘子,最后放上去的,最先取下来。

基本操作函数:
init() : 创建 destroy():销毁 push():插入数据 top(): 取得栈顶元素 pop(): 删除栈顶元素 isEmpty(): 判空,栈是否为空
n个数据入栈,数据出栈的种类个数,使用卡特兰公示:(1/(n+1)) * Cn2n

【顺序栈】
使用顺序表来实现:
struct statck{
type data[100];
type top; 数组索引,即栈顶元素的索引, top == -1, 栈空
}

【链栈】
struct statck{
type *pdata;
type *pbottom;
type* ptop; 数组索引,即栈顶元素的索引, top == -1, 栈空
}

【栈的应用】
IDE环境中符号匹配问题

四则运算中 界限符(括号) 匹配问题
四则运算的计算
【栈-四则运算】
表达式由, 操作数、操作符、界限符 构成

数学表达式形式分为以下三种:
中缀表达式: ( 15 / ( 7 - ( 1 + 1 ) ) * 3 ) - (2 + ( 1 + 1 ) )
前缀表达式【波兰式】: - * / 15 - 7 + 1 1 3 + 2 + 1 1
后缀表达式【逆波兰式子】: 15 7 1 1 + - / 3 * 2 1 1 + + -
其中常用的计算机表达式为 逆波兰式。
详细转换过程:
中缀转前缀 :
从右向左扫描字符串,将表达式转为 后缀表达式 T(X), 将T(x) 逆序,即,转换为前缀表达式。

实现过程如下:

前缀计算过程:

计算过程 同时也是 后缀转中缀 的过程;类似于下面的后缀计算过程,详细看后缀。此处不写了。
中缀转后缀:
操作符入栈,遇到限定符或栈顶元素的优先级较高,则栈顶元素出栈,新操作符入栈。具体流程如下:

详细操作流程:

后缀 表达式计算:
操作数入栈,遇到操作符,执行相应的操作,把结果压入栈中,继续下一循环。注意:先出栈的操作数为右操作数,后出栈的为左操作数。具体流程如下:

具体操作【同时也是 后缀转中缀 的过程】:

【栈在递归中的应用: 函数调用栈】
如下图:

计算 f(5)时,f(5)中调用 f(4),f(4)调用f(3),...f(1)结束,然后从f(1)依次弹出栈,f(5)函数计算完成.
函数栈中存放的是函数执行过程中所需要的内存栈空间,即局部变量所占内存空间。他是根据代码区的指令进行分配。
递归解决的问题:问题属性相同且规模较小。例如: 阶乘、斐波那契数列
优点:找到问题属性,实现代码,依次调用,写代码方便。
缺点:函数调用栈溢出。重复计算,效率低。
可以用动态规划、栈、for循环 代替递归调用。
【队列】queue
先进先出(FIFO—first in first out)线性表。 前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
基本操作函数:
init() : 创建 destroy():销毁 push():插入数据 top(): 取得队头元素 pop(): 删除队头元素 isEmpty(): 判空,队列是否为空
【顺序队列】
struct statck{
type data[100];
type front; 队头索引 front = (front+1) % 100
type rear; 队尾索引 rear= (rear+1) % 100
type num; num == 0是,队列为空
}

由于内存分配固定,队头/尾的索引需要向后递增,所以需要 %100 来实现 循环队列,同样防止索引递增下去引起的数组越界。
【链队列】
struct statck{
type *pdata;
type *pfront; 队头指针
type *prear; 队尾指针
// type *pnext; 插入元素的下一个数据内存,该变量实现循环队列;如果队列的基类本生就是循环链表的话,不需要使用该变量,因为他本身就是循环队列。
type num; num == 0是,队列为空
}

【双端队列】: 分别供两端插入或删除
扩展:
只能从一端输入,两端可以输出的双端队列【输入受限的双端队列】
只能从一端输出,两端可以输入的双端队列【输出受限的双端队列】
应用:
* 求回文
* 求平衡问题
【队列的应用:】
树的层次遍历:

遍历过程:
① 入队列,
①出队,左右孩子结点②③入队, 结果①
②出队,左右孩子结点 ④⑤入队,结果①②
③出队,左右孩子结点⑥入队,结果①②③
④出队,左右孩子结点为空,无元素入队,结果①②③④
⑤出队,左右孩子结点为空,无元素入队,结果①②③④⑤
⑥出队,左右孩子结点为空,无元素入队,结果①②③④⑤⑥
队列为空,结束。
树的层次遍历完成。
图的广度优先遍历 BFS:

遍历过程:
① 入队列,结点flag设置为1
①出队,孩子结点②④入队,结点flag设置为1,结果①
②出队,孩子结点 ③入队,结点flag设置为1,结果①②
④出队,孩子结点⑤⑥入队,结点flag设置为1,结果①②④
③出队,无孩子结点,结果①②④③
⑤出队,⑥结点flag为1,不入队,⑦结点入队,结点flag设置为1,结果①②④③⑤
⑥出队,⑤结点flag为1,不入队,⑧结点入队,结点flag设置为1,结果①②④③⑤⑥
⑦出队,⑤⑧结点flag为1,不入队,结果①②④③⑤⑥⑦
⑧出队,⑥⑦结点flag为1,不入队,结果①②④③⑤⑥⑦⑧
队列为空,结束。
BFS完成。
队列在操作系统中的应用:
多个进程争夺系统资源时,常用策略--> FCFS(FIRST COME FIRST SERVICE) 先来先服务。
打印机的缓冲区,可以使用优先队列,设置打印权限。
【四则运算的实现】
【类图】

【实现代码】
Dlist.h
#pragma once
using namespace std;
using DoubleNode = struct _dNode
{
int data;
struct _dNode* pProir;
struct _dNode* pNext;
};
// 双向链表
class Dlist
{
public:
// init 放到构造函数中
Dlist();
// destroy 放到析构函数中
virtual ~Dlist();
// 前插数据
int InsertHead(int value);
// 后插数据
int InsertEnd(int value);
// 删除元素
int erase(int index);
// 设定元素值
int setValue(int index, int value);
// 查找从Index 后面值为value的元素的索引
int LocateElem(int index, int value);
// 查找从Index 的值
int GetElemValue(int index, int& value);
// 判断链表是否为空
bool IsEmpty();
// 链表长度
int Size();
protected:
// 取得下标为 index 的元素
DoubleNode* getElem(int index);
protected:
DoubleNode* pHead;// 表头
DoubleNode* pTail;// 表尾
int num;// 元素的个数
};
#include "Dlist.h"
Dlist::Dlist()
{
pHead = new DoubleNode{0, nullptr, nullptr};// 表头
pTail = new DoubleNode{0, nullptr, nullptr};// 表尾
pHead->pNext = pTail;
pTail->pProir = pHead;
num = 0;// 元素的个数
}
Dlist::~Dlist()
{
while (pHead->pNext !=nullptr)
{
DoubleNode* Elem = pHead->pNext;
pHead->pNext = Elem->pNext;
delete Elem;
}
delete pHead;
}
// 前插数据
int Dlist::InsertHead(int value)
{
DoubleNode* Elem = new DoubleNode{value, nullptr, nullptr};
num++;
Elem->pNext = pHead->pNext;
Elem->pProir = pHead;
pHead->pNext = Elem;
Elem->pNext->pProir = Elem;
return 0;
}
// 后插数据
int Dlist::InsertEnd(int value)
{
DoubleNode* Elem = new DoubleNode{value, nullptr, nullptr};
num++;
Elem->pProir = pTail->pProir;
Elem->pNext = pTail;
Elem->pProir->pNext = Elem;
pTail->pProir = Elem;
return 0;
}
// 取得下标为 index 的元素
DoubleNode* Dlist::getElem(int index)
{
if ((index >= num) || nullptr == pHead)
{
return nullptr;
}
// 第0号元素
DoubleNode* Elem = pHead->pNext;
// 找到指定元素
while (index >= 1)
{
Elem = Elem->pNext;
index--;
}
return Elem;
}
// 删除元素
int Dlist::erase(int index)
{
DoubleNode* Elem = getElem(index);
if (nullptr == Elem)
{
return -1;
}
// 修改指针链
Elem->pProir->pNext = Elem->pNext;
Elem->pNext->pProir = Elem->pProir;
// 删除结点
delete Elem;
// 计数减一
num--;
return 0;
}
// 设定元素值
int Dlist::setValue(int index, int value)
{
DoubleNode* Elem = getElem(index);
if (nullptr == Elem)
{
return -1;
}
Elem->data = value;
return 0;
}
// 查找从Index 后面值为value的元素的索引
int Dlist::LocateElem(int index, int value)
{
DoubleNode* Elem = getElem(index);
if (nullptr == Elem)
{
return -1;
}
int retIndex = index;
do
{
if (Elem->data == value)
{
break;
}
retIndex++;
} while (nullptr != (Elem = Elem->pNext));
if (retIndex == num)
{
retIndex = -1;
}
// 函数值返回
return retIndex;
}
// 查找从Index 的值
int Dlist::GetElemValue(int index,int& value)
{
DoubleNode* Elem = getElem(index);
if (nullptr == Elem)
{
return -1;
}
value = Elem->data;
return 0;
}
// 判断链表是否为空
bool Dlist::IsEmpty()
{
return num == 0 ? true : false;
}
// 链表长度
int Dlist::Size()
{
return num;
}
KDqueue.h
#ifndef DATA_STRUCT_K_DQUEUE_H
#define DATA_STRUCT_K_DQUEUE_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "Dlist.h"
/**
* 双端队列
*/
class KDqueue : public Dlist
{
public:
/**
* 构造函数
*/
KDqueue();
/**
* 析构函数
*/
virtual ~KDqueue();
/**
* 头插入
*/
int PushHead(int v);
/**
* 取得头元素
*/
int TopHead();
/**
* 删除头元素
*/
int PopHead();
/**
* 尾插入
*/
int PushTail(int v);
/**
* 取得尾元素
*/
int TopTail();
/**
* 弹出尾元素
*/
int PopTail();
/**
* 清空队列
*/
void clear();
KDqueue& operator=(const KDqueue& v);
// 打印数据
void PrintFromHead();
};
#endif
KDqueue.cpp
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KDqueue.h"
KDqueue::KDqueue() :Dlist()
{
}
KDqueue::~KDqueue()
{
}
int KDqueue::PushHead(int v)
{
int ret = InsertHead(v);
return ret;
}
int KDqueue::TopHead()
{
if (pTail == pHead->pNext)
{
return 0;
}
return pHead->pNext->data;
}
int KDqueue::PopHead()
{
DoubleNode* temp = pHead->pNext;
if (pTail == temp)
{
return -1;
}
num--;
pHead->pNext = temp->pNext;
temp->pNext->pProir = pHead;
delete temp;
return 0;
}
int KDqueue::PushTail(int v)
{
int ret = InsertEnd(v);
return ret;
}
int KDqueue::TopTail()
{
if (pHead == pTail->pProir)
{
return 0;
}
return pTail->pProir->data;
}
int KDqueue::PopTail()
{
DoubleNode* temp = pTail->pProir;
if (pHead == temp)
{
return -1;
}
num--;
pTail->pProir = temp->pProir;
temp->pProir->pNext = pTail;
delete temp;
return 0;
}
void KDqueue::clear()
{
while (pHead->pNext != pTail)
{
DoubleNode* Elem = pHead->pNext;
pHead->pNext = Elem->pNext;
delete Elem;
}
num = 0;
}
KDqueue& KDqueue::operator=(const KDqueue& v)
{
if (&v == this)
{
return *this;
}
this->clear();
if (v.pHead->pNext != v.pTail)
{
this->pHead->pNext = v.pHead->pNext;
v.pHead->pNext->pProir = this->pHead;
this->pTail->pProir = v.pTail->pProir;
v.pTail->pProir->pNext = this->pTail;
v.pHead->pNext = v.pTail;
v.pTail->pProir = v.pHead;
this->num = v.num;
}
return *this;
}
void KDqueue::PrintFromHead()
{
DoubleNode* Elem = pHead->pNext;
while (Elem != pTail)
{
cout << Elem->data << " ";
Elem = Elem->pNext;
}
cout << endl;
}
KQueue.h
#ifndef DATA_STRUCT_K_QUEUE_H
#define DATA_STRUCT_K_QUEUE_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KDqueue.h"
/**
* 队列实现类
*/
class KQueue : public KDqueue
{
public:
/**
* 构造函数
*/
KQueue();
/**
* 析构函数
*/
virtual ~KQueue();
/**
* 元素从队尾入队
*/
int Push(int v);
/**
* 取得队头元素
*/
int Top();
/**
* 弹出队头元素
*/
int Pop();
};
#endif
KQueue.cpp
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KQueue.h"
KQueue::KQueue()
{
}
KQueue::~KQueue()
{
}
int KQueue::Push(int v)
{
int ret = PushTail(v);
return ret;
}
int KQueue::Top()
{
int ret = TopHead();
return ret;
}
int KQueue::Pop()
{
int ret = PopHead();
return ret;
}
KStatck.h
#ifndef DATA_STRUCT_K_STATCK_H
#define DATA_STRUCT_K_STATCK_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KDqueue.h"
/**
* 栈实现类
*/
class KStatck : public KDqueue
{
public:
/**
* 栈构造函数
*/
KStatck();
/**
* 栈析构函数
*/
virtual ~KStatck();
/**
* 元素压栈
*/
int Push(int v);
/**
* 取得栈顶元素
*/
int Top();
/**
* 弹出栈顶元素
*/
int Pop();
};
#endif
KStatck.cpp
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KStatck.h"
KStatck::KStatck()
{
}
KStatck::~KStatck()
{
}
int KStatck::Push(int v)
{
int ret = PushHead(v);
return ret;
}
int KStatck::Top()
{
int ret = TopHead();
return ret;
}
int KStatck::Pop()
{
int ret = PopHead();
return ret;
}
KOperation.h
#ifndef DATA_STRUCT_K_OPERATION_H
#define DATA_STRUCT_K_OPERATION_H
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KStatck.h"
#include "KQueue.h"
/**
* 四则运算实现类
*/
class KOperation
{
private:
/**
* 栈对象,中缀转后缀,保存操作符,计算后缀,保存操作数
*/
KStatck m_oStatck;
/**
* 队列对象,保存式子结果值
*/
KQueue m_oQueue;
/**
* 最终计算的结果值
*/
int m_nResultValue;
public:
/**
* 构造函数
*/
KOperation();
/**
* 析构函数
*/
virtual ~KOperation();
/**
* 中缀转后缀
*/
int FromInToSuffix();
/**
* 计算后缀表达式
*/
int ClaculateSuffix();
/**
* 输出计算结果值
*/
void OutResult();
/**
* 输入字符串
*/
int InPutText(string strText);
};
#endif
KOperation.cpp
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <assert.h>
#include "KOperation.h"
enum op
{
Add_Enum = -100,
Sub_Enum,
Multi_Enum = -80,
divi_Enum,
LBrackets_Enum =-70,
RBrackets_Enum = -60
};
KOperation::KOperation()
{
}
KOperation::~KOperation()
{
}
int KOperation::FromInToSuffix()
{
KQueue QueueTemp;
while (!m_oQueue.IsEmpty())
{
m_oStatck.PrintFromHead();
int v = m_oQueue.Top();
m_oQueue.Pop();
if (v >= Add_Enum && v <= RBrackets_Enum)
{
// 左括号
if (v == LBrackets_Enum)
{
m_oStatck.Push(v);
continue;
}
// 右括号
if (v == RBrackets_Enum)
{
// 栈非空
if(!m_oStatck.IsEmpty())
{
int X = m_oStatck.Top();
m_oStatck.Pop();
if (X == LBrackets_Enum)
{
continue;
}
else
{
QueueTemp.Push(X);
bool flag = m_oStatck.IsEmpty();
if (flag)
{
return -1;
}
else
{
X = m_oStatck.Top();
m_oStatck.Pop();
if (X != LBrackets_Enum)
{
return -1;
}
}
}
}
else
{
return -1;
}
continue;
}
if (m_oStatck.IsEmpty())
{
m_oStatck.Push(v);
continue;
}
int X = m_oStatck.Top();
if (v > X+1)
{
QueueTemp.Push(v);
}
else
{
if (X == LBrackets_Enum)
{
m_oStatck.Push(v);
}
else
{
m_oStatck.Pop();
m_oStatck.Push(v);
QueueTemp.Push(X);
}
}
continue;
}
QueueTemp.Push(v);
}
// 栈空
while (!m_oStatck.IsEmpty())
{
int v = m_oStatck.Top();
m_oStatck.Pop();
if (v == LBrackets_Enum)
{
return -1;
}
QueueTemp.Push(v);
}
m_oQueue = QueueTemp;
m_oQueue.PrintFromHead();
return 0;
}
int KOperation::ClaculateSuffix()
{
m_oStatck.clear();
KQueue QueueTemp;
while (!m_oQueue.IsEmpty())
{
int v = m_oQueue.Top();
m_oQueue.Pop();
if (v >= Add_Enum && v <= RBrackets_Enum)
{
if (m_oStatck.Size() < 2)
{
return -1;
}
int R = m_oStatck.Top();
m_oStatck.Pop();
int L = m_oStatck.Top();
m_oStatck.Pop();
int ret = 0;
if (Add_Enum == v)
{
ret = L + R;
}
else if (Sub_Enum == v)
{
ret = L - R;
}
else if (Multi_Enum == v)
{
ret = L * R;
}
else if (divi_Enum == v)
{
ret = L / R;
}
m_oStatck.Push(ret);
continue;
}
m_oStatck.Push(v);
}
m_nResultValue = m_oStatck.Top();
m_oStatck.Pop();
return 0;
}
void KOperation::OutResult()
{
cout << "四则运算的结果为" << m_nResultValue << endl;
}
int KOperation::InPutText(string strText)
{
string temp;
for (auto v : strText)
{
if ((v >= '0' && v <= '9') || (v == '(') || (v == ')') || (v == '+') || (v == '-') || (v == '*') || (v == '/'))
{
if (v >= '0' && v <= '9')
{
temp.push_back(v);
}
else
{
if (!temp.empty())
{
m_oQueue.Push(atoi(temp.c_str()));
temp.clear();
}
switch (v)
{
case '+':
m_oQueue.Push(Add_Enum);
break;
case '-':
m_oQueue.Push(Sub_Enum);
break;
case '*':
m_oQueue.Push(Multi_Enum);
break;
case '/':
m_oQueue.Push(divi_Enum);
break;
case '(':
m_oQueue.Push(LBrackets_Enum);
break;
case ')':
m_oQueue.Push(RBrackets_Enum);
break;
default:
break;
}
}
}
else
{
return -1;
}
}
m_oQueue.PrintFromHead();
return 0;
}
结束

浙公网安备 33010602011771号