数据结构与算法_【3】栈和队列(C++实现)

参考:数据结构与算法基础(青岛大学-王卓)
传送门:
数据结构与算法_【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()
{

}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值