参考:数据结构与算法基础(青岛大学-王卓)
传送门:
数据结构与算法_【1】概念引入(C++实现)
数据结构与算法_【2】线性表(顺序表链表)(C++实现)
数据结构与算法_【3】栈和队列(C++实现)
数据结构与算法_【4】串数组广义表(C++实现)
数据结构与算法_【5】树和二叉树(C++实现)
数据结构与算法_【6】树和森林(C++实现)
数据结构与算法_【7】哈夫曼树(C++实现)
数据结构与算法_【8】图(C++实现)
数据结构与算法_【9】查找(C++实现)
数据结构与算法_【10】排序(C++实现)
栈和队列
栈(后入先出)和队列(先进先出)是限定插入和删除只能在表的“端点”的线性表
1 概念
1.1栈
栈是仅在表尾进行插入、删除操作的线性表;表尾称为栈顶Top,表头称为栈底Base;插入元素到栈顶(表尾)的操作称为入栈,从栈顶(表尾)删除最后一个元素的操作称为出栈。
逻辑结构:一对一关系,前驱后继
存储结构:顺序栈、链栈,顺序栈较为常见
运算规则:只能栈顶运算(与一般线性表的区别)
1.2队列
队列是一种先进先出的线性表,在表一端插入(表尾),在另一端(表头)删除
逻辑结构:一对一,前驱后继
存储结构:顺序队或栈队,循环顺序队列较为常见
运算规则:先进先出,队首和队尾操作
2 实现
2.1 顺序栈的表示和实现
利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,栈底一般在低地址端
附设top指针,指示栈顶元素在顺序栈中的位置,但是为了操作方便,通常top指示真正的栈顶元素之上的下标地址!
另设base指针,指示栈底元素在顺序栈中的位置
stacksize表示栈可以使用的最大容量
空栈:top == base
栈满:top - base = stacksize
栈满时处理方法:(1)报错,返回操作系统;(2)分配更大的空间,作为栈的存储空间,将原栈的内容移入新栈
溢出:(1)上溢,栈已经满,又要压入元素;(2)下溢,栈已经空,还要弹出元素
注:上溢是一种错误,使问题的处理无法进行,而下溢一般认为是一种结束条件,即问题处理结束
顺序栈实现:
template<typename T>
class SeqStack {
private:
T* top;
T* base;
int stackSize;
public:
SeqStack();
bool StackEmpty();
bool StackFull();
void ClearStack();
void DestroyStack();
void ShowStack();
void Push(const T& e);
void Pop(T& e);
//void StackFull();
~SeqStack();
};
template<typename T>
SeqStack<T>::SeqStack()
{
this->base = new T[MAXSIZE];
if (!this->base)
{
cout << "分配地址失败!!!" << endl;
return;
}
this->top = this->base;
this->stackSize = MAXSIZE;
}
//后面实现 略
2.2 链栈的表示和实现
链栈是运算受限的单链表,只能在链表头部进行操作
说明:
链表的头指针就是栈项
不需要头结点
基本不存在栈满的现象
空栈相当于头指针指向空
插入和删除仅在栈顶处执行
2.3 栈与递归
递归定义:
(1)若一个对象部分地包含它自己,或用它自己给自己定义,则称这个对象是递归的
(2)若一个过程直接地或间接地调用自己,则称这个过程是递归的过程
嵌套调用执行过程:
(遵循后调用先返回,与栈后入先出相似)
递归优缺点
优点:结构清晰,程序易读
缺点:每次调用要生成工作记录,保存状态信息,入栈;返回时要出栈,恢复状态信息。时间开销大
递归->非递归
(1)尾递归、单向递归->循环结构
(2)自用 栈 模拟系统的运行时栈
2.4 顺序队列的表示和实现
队列(Queue)仅在表尾进行插入操作,在表头进行删除操作的线性表;是一种先进先出(FIFO)的线性表;插入元素称作入队,删除元素称作出队;队列的存储结构为链队或顺序队(常用循环顺序队)
逻辑结构:与同性线性表一致,仍为一对一关系
存储结构:链队或顺序队(常用循环顺序队)
运算规则: 只能在队尾和队首运算,先进先出
实现方式:关键掌握入队出队
创建队列:
template<typename T>
class SeqQueue {
private:
T* base;//初始化动态分配的存储空间
int front;//头指针
int rear;//尾指针
};
解决假上溢的方法:引入循环队列
队空队满时都有:front == rear
解决方法:(1)另外设一个标志以区别队空队满;(2)另外设一个变量,记录元素个数;(3)少用一个元素空间
(rear+1)%MAXQSIZE == front;
2.5 链式队列的表示和实现
若用户无法估计所用队列的长度,则宜采用链队!
3 代码实现
3.1 顺序栈(seqStack)代码实现
#pragma once
#include<iostream>
using namespace std;
#define MAXSIZE 100
template<typename T>
class SeqStack {
private:
T* top;
T* base;
int stackSize;
public:
SeqStack();
bool StackEmpty();
bool StackFull();
void ClearStack();
void DestroyStack();
void ShowStack();
void Push(const T& e);
void Pop(T& e);
//void StackFull();
~SeqStack();
};
template<typename T>
SeqStack<T>::SeqStack()
{
this->base = new T[MAXSIZE];
if (!this->base)
{
cout << "分配地址失败!!!" << endl;
return;
}
this->top = this->base;
this->stackSize = MAXSIZE;
}
template<typename T>
bool SeqStack<T>::StackEmpty()
{
if (this->base == this->top)
{
cout << "栈为空!" << endl;
return true;
}
return false;
}
template<typename T>
bool SeqStack<T>::StackFull()
{
if ((this->top - this->base) == this->stackSize)
{
cout << "栈已满!" << endl;
return true;
}
return false;
}
template<typename T>
void SeqStack<T>::ClearStack()
{
if (this->base)
{
this->top = this->base;
cout << "ClearStack!" << endl;
return;
}
cout << "栈不存在,无法清空!" << endl;
}
template<typename T>
void SeqStack<T>::DestroyStack()
{
if (this->base)
{
delete this->base;
this->stackSize = 0;
this->base = NULL;
this->top = NULL;
cout << "DestroyStack!" << endl;
return;
}
cout << "栈不存在,无法销毁!" << endl;
}
template<typename T>
void SeqStack<T>::ShowStack()
{
if (this->StackEmpty())
{
cout << "栈为空,无法打印!" << endl;
return;
}
T* p = this->base;
while (p != this->top)
{
cout << *p++ << endl;
}
}
template<typename T>
void SeqStack<T>::Push(const T& e)
{
if (this->StackFull())
{
cout << "栈已满!无法入栈!" << endl;
return;
}
*this->top ++ = e;
}
template<typename T>
void SeqStack<T>::Pop(T& e)
{
if (this->StackEmpty())
{
cout << "栈为空!无法出栈!" << endl;
return;
}
e = *--this->top;//注意这里this->top指向为空,要先-1,再弹出 不能打印top指针指向的元素!!!
}
template<typename T>
SeqStack<T>::~SeqStack()
{
}
3.2 链栈(linkStack)代码实现
#pragma once
#include<iostream>
using namespace std;
template<typename T>
class LinkStack;
//注意这里结点的定义,不能与链表里的类名重复!
template<typename T>
class LinkNode_Stack {
friend class LinkStack<T>;
public:
LinkNode_Stack()
{
//this->m_data = 0;
this->next = NULL;
}
~LinkNode_Stack()
{
}
private:
T m_data;
//嵌套定义:自己定义自己
LinkNode_Stack<T>* next;
};
template<typename T>
class LinkStack {
private:
LinkNode_Stack<T>* head;
public:
LinkStack();
bool StackEmpty();
void ShowLinkStack();
void Push(const T& e);//将e压入栈
void Pop(T& e);// 出栈,通过e返回
//void PopPtr(T* e);//出栈,返回指针 !!!未检测!!!
~LinkStack();
};
template<typename T>
LinkStack<T>::LinkStack()
{
this->head = new LinkNode_Stack<T>;
}
template<typename T>
bool LinkStack<T>::StackEmpty()
{
if (this->head->next == NULL)
{
//cout << "栈为空!" << endl;
return true;
}
return false;
}
template<typename T>
void LinkStack<T>::ShowLinkStack()
{
if (this->StackEmpty())
{
cout << "链栈为空!无法打印!" << endl;
return;
}
LinkNode_Stack<T>* p = this->head;
while (p->next)
{
cout << p->m_data << endl;
p = p->next;
}
}
template<typename T>
void LinkStack<T>::Push(const T& e)
{
LinkNode_Stack<T> *p = new LinkNode_Stack<T>;//分配一个结点地址
p->m_data = e;
p->next = this->head;
this->head = p;
}
template<typename T>
void LinkStack<T>::Pop(T& e)
{
if (this->StackEmpty())
{
cout << "链栈为空!无法出栈!" << endl;
return;
}
e = this->head->m_data;
LinkNode_Stack<T>* p = this->head;
this->head = this->head->next;
delete p;//从栈中释放数据
}
//template<typename T>
//void LinkStack<T>::PopPtr(T* e)
//{
// if (this->StackEmpty())
// {
// cout << "链栈为空!无法出栈!" << endl;
// return;
// }
//
// e = this->head
// LinkNode_Stack<T>* p = this->head;
// this->head = this->head->next;
// delete p;//从栈中释放数据
//}
template<typename T>
LinkStack<T>::~LinkStack()
{
}
3.3 顺序队(seqQueue)代码实现
#pragma once
#include<iostream>
using namespace std;
#define MAXQSIZE 5
template<typename T>
class SeqQueue {
private:
T* base;//初始化动态分配的存储空间
int front;//头指针
int rear;//尾指针
public:
SeqQueue();
int QueueLenth();
void ShowQueue();
void EnQueue(const T& e);//将e填入队列(队尾插入)
void DeQueue(T& e);//删除元素,通过e返回(队尾删除)
~SeqQueue();
};
template<typename T>
SeqQueue<T>::SeqQueue()
{
this->base = new T[MAXQSIZE];
if (!this->base)
{
cout << "内存分配失败!" << endl;
return;
}
this->front = 0;
this->rear = 0;
}
template<typename T>
int SeqQueue<T>::QueueLenth()
{
//循环队列! rear不一定在front后面,也有可能在前面的地址!
return (this->rear - this->front + MAXQSIZE) % MAXQSIZE;
}
template<typename T>
void SeqQueue<T>::ShowQueue()
{
if (this->front == this->rear)
{
cout << "队列为空!无法打印!" << endl;
return;
}
int lenth = this->QueueLenth();
int i = this->front;
while (lenth)
{
cout << this->base[i] << endl;
i = (i + 1) % MAXQSIZE;
lenth--;
}
}
template<typename T>
void SeqQueue<T>::EnQueue(const T& e)
{
//避免出现队空队满时都有:front == rear
//只允许插入MAXQSIZE-1个元素
if ((this->rear + 1) % MAXQSIZE == this->front)
{
cout << "队列已满!无法插入!" << endl;
return;
}
this->base[this->rear] = e;
this->rear = (this->rear + 1) % MAXQSIZE;
}
template<typename T>
void SeqQueue<T>::DeQueue(T& e)
{
if (this->front == this->rear)
{
cout << "队列为空!无法删除!" << endl;
}
e = this->base[this->front];
this->front = (this->front + 1) % MAXQSIZE;
}
template<typename T>
SeqQueue<T>::~SeqQueue()
{
}
3.4 链队(linkQueue)代码实现
#pragma once
#include<iostream>
using namespace std;
#define MAXLQSIZE 100;
template<typename T>
class LinkQueue;
template<typename T>
class LinkNode_Queue {
friend class LinkQueue<T>;
private:
T m_data;
LinkNode_Queue* next;
public:
LinkNode_Queue()
{
this->m_data = 0;
this->next = NULL;
}
~LinkNode_Queue()
{
}
};
template<typename T>
class LinkQueue {
private:
LinkNode_Queue<T>* front;
LinkNode_Queue<T>* rear;
public:
LinkQueue();
void DestroyQueue();
void ShowQueue();
void EnQueue(const T& e);//将e入队
void DeQueue(T& e);//队头出队,通过e返回
~LinkQueue();
};
template<typename T>
LinkQueue<T>::LinkQueue()
{
this->front = new LinkNode_Queue<T>;
if (!this->front)
{
cout << "内存分配失败!" << endl;
return;
}
this->rear = this->front;
}
template<typename T>
void LinkQueue<T>::DestroyQueue()
{
while (this->front)
{
LinkNode_Queue<T>* p = this->front->next;
delete this->front;
this->front = p;
}
}
template<typename T>
void LinkQueue<T>::ShowQueue()
{
if (this->front == this->rear)
{
cout << "队列为空!无法打印" << endl;
return;
}
//注意这里存在头结点
LinkNode_Queue<T> *p = this->front->next;//指针p指向首元结点
while (p)
{
cout << p->m_data << endl;
p = p->next;
}
}
template<typename T>
void LinkQueue<T>::EnQueue(const T& e)
{
LinkNode_Queue<T> *p = new LinkNode_Queue<T>;
p->m_data = e;
this->rear->next = p;
this->rear = this->rear->next;
}
template<typename T>
void LinkQueue<T>::DeQueue(T& e)
{
if (!this->front)
{
cout << "队列为空!无法出队!" << endl;
return;
}
e = this->front->next->m_data;
LinkNode_Queue<T>* p = this->front->next;
this->front->next = this->front->next->next;
if (this->rear == p)
{
this->rear = this->front;
}
delete p;
}
template<typename T>
LinkQueue<T>::~LinkQueue()
{
}