栈和队列(C++)

栈的相关概念

栈是仅在表尾进行插入,删除操作的线性表

表尾称为栈顶Top,表头称为栈底Base

插入元素到栈顶,称为入栈;从栈顶删除最后一个元素,称为出栈

栈的运算规则:先进后出

一.顺序栈

顺序栈的表示

利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素。栈底一般在低地址端

为了方便操作,通常Top指示真正的栈顶元素之上的下标地址,所以Top指向内存空间不存放元素

  • 空栈:top==base
  • 栈满:top-base==stacksize
  • 上溢:栈已满还要压入元素
  • 下溢:栈已空还要弹入元素
  • 栈中元素个数:top-base

顺序栈的定义

#define MAXSIZE 100
typedef char Elemtype;  //栈的数据类型
typedef struct Sqstack
{
	Elemtype* base;  //栈底指针
	Elemtype* top;  //栈顶指针
	int stacksize;  //栈的最大容量
}Sqstack;

顺序栈的初始化

bool Initstack(Sqstack& S)  //构造一个空栈
{
	S.base = new Elemtype[MAXSIZE];  //在堆区开辟内存
	if (!S.base)  //存储分配失败
	{
		cout << "顺序栈不存在" << endl;
		return false;
	}
	S.top = S.base;  //栈顶指针等于栈底指针,空栈的标志
	S.stacksize = MAXSIZE;
	return true;
}

判断顺序栈是否为空

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

顺序栈长度

int Stacklength(Sqstack& S)
{
	return S.top - S.base; 
	//top指示真正的栈顶元素之上的下标地址
	//base指示的元素的下标地址为0
}

顺序栈的清空和销毁

bool Clearstack(Sqstack& S)
{
	if (S.base)
	{
		S.base = S.top;   //空栈定义
		return true;
	}
	return false;
}

void Destroystack(Sqstack& S)
{
	if (S.base)   //栈还存在的条件判断
	{
		delete S.base;  //删除栈底指针
		S.stacksize = 0;  //栈的容量置为0
		S.base = S.top = nullptr;  //栈顶和栈底指针均为空
	}
}

顺序栈的入栈

  • 判断是否栈满,若满则出错(上溢)
  • 元素e压入栈顶
  • 栈顶指针加1
bool Push(Sqstack& S,const Elemtype& e)
{
	if ((S.top - S.base) == S.stacksize)
	{
		cout << "栈已满,无法入栈" << endl;
		return false;
	}
	    *S.top = e;  //将元素e压入栈顶
	    ++S.top; //栈顶指针加1
	return true;
}

顺序栈的出栈

  • 判断是否栈空,若栈为空则出错(下溢)
  • 获取栈顶元素e
  • 栈顶指针减1
bool Pop(Sqstack& S,Elemtype& e)
{
	if (S.base == S.top)
	{
		cout << "空栈,无法出栈!" << endl;
		return false;
	}
	--S.top;  //栈顶指针减1
	e = *S.top;  //获取栈顶元素e
	return true;
}

进制转换

void Change(int x)
{
	cout << "八进制转换后为:" << endl;
	Sqstack S;
	Initstack(S);
	int temp = x;
	while (temp) {
		Push(S, temp % 8);
		temp = temp / 8;
	}
	while (!Isempty(S)) {
		int i;
		//Pop(S, i);
		//cout << i;
	}
}

括号匹配

//输入括号()[],判断括号是否匹配成功, # 字符表示输入结束
//例: ([()]) 成功[(())]] 失败
bool Match(void)
{
	Sqstack S;
	Initstack(S);
	char ch, pop;
	int flag = 1;
	cout << "输入符号(以#为结束标志):" << endl;
	cin >> ch;

	while (flag && ch != '#') {
		switch (ch)
		{
		case '(':
			Push(S, ch);
			break;
		case'[':
			Push(S, ch);
			break;
		case')':
			if (!Isempty(S) && *(S.top-1) == '(')
			{
				Pop(S, pop);
			}
			else {
				flag = 0;
			}
			break;
		case']':
			if (!Isempty(S) && *(S.top - 1) == '[')
			{
				Pop(S, pop);
			}
			else {
				flag = 0;
			}
			break;
		}
		cin >> ch;
	}
	if (flag && Isempty(S))
	{
		cout << "匹配成功!" << endl;
		return true;
	}
	else
	{
		cout << "匹配失败!" << endl;
		return false;
	}
}

二.链栈

链栈的表示

链栈是运算受限的单链表,只能在链表的头部进行操作

链表的头指针就是栈顶,不需要头结点(在下面代码中,我新建了一个头结点,头结点的数据域用来存放链栈中元素的个数)

基本不存在栈满的情况,空栈就相当于头指针指向空

插入和删除操作仅在栈顶处执行

链栈的定义

typedef char Elemtype;
typedef struct Stacknode
{
	Elemtype data;
	Stacknode* next;
}*Linkstack

链栈的初始化

void Initstack(Linkstack& L)
{
	//创建一个头结点,在头结点的数据域中保存栈中元素的个数
	L = new Stacknode; 
	L->next = nullptr;
	L->data = 0;
}

判断链栈是否为空

bool Isempty(Linkstack& L)
{
	if (L->next == nullptr)
	{
		return true;
	}
	return false;
}

链栈的入栈

void Push(Linkstack& L, const Elemtype& e)
{
	Stacknode *p = new Stacknode;  //生成一个新结点p
	p->data = e;  //新结点的数据域置为e
	p->next = L->next;  //将新结点插入栈顶
	L->next = p;  //修改栈顶指针
	++L->data;  //栈中元素个数加1
}

链栈的出栈

void Pop(Linkstack& L, Elemtype& e)
{
	if (L->next == nullptr)
	{
		cout << "栈为空,无法出栈!" << endl;
		return ;
	}
	else {
		Stacknode* p = L->next;  //生成一个新结点p
		e = p->data;
		L->next = p->next;
		--L->data;
		delete p;
	}
}

获取链栈的元素的个数

int Stacklength(Linkstack& L)
{
	return L->data;
}

创建一个链栈(元素批量入栈)

#define count 6
void Creatstack(Linkstack& L)
{
	Elemtype e;
	for(int i=1;i<=count;i++)
	{
		cin >> e;
		Push(L, e);
	}
}

队列的相关概念

队列是仅在表尾进行插入操作,在表头进行删除操作的线性表

队列的运算规则:先进先出

一.顺序队列

顺序队列的定义

#define MAXQSIZE 100  //定义数组大小
typedef char Elemtype;
typedef struct SqQueue
{
	Elemtype* elem;
	int front;  //队头下标,指向队列头元素
	int rear;  //队尾下标,指向队尾元素下一个位置
}SqQueue;

循环队列

初始时:front=rear=0
空队标志:front==rear

  1. 若front=0,rear=MAXQSIZE时,再入队–真溢出
  2. 若front≠0,rear=MAXQSIZE时,再入队–假溢出

解决假上溢的方法:

在这里插入图片描述

将队空间设想成一个循环的表,即分配给队列的m个存储单元可以循环使用,当rear=MAXQSIZE时,若向量的开始端空着,又可以从头使用空着的空间。当front=MAXQSIZE时也一样。

base[0]接在base[MAXQSIZE-1]之后,若rear+1==MAXQSIZE,则令rear=0
(实现方法:利用模运算%)

插入元素:
Q.base[Q.rear]=x
Q.rear=(Q.rear+1)%MAXQSIZE

删除元素:
Q.base[Q.front]=x
Q.front=(Q.front+1)%MAXQSIZE

但是此时会出现一个新的问题,就是队空和队满的标志都是front==rear,要解决这个问题,可以在队列中少用一个元素空间,此时

队空: front== rear
队满: (rear+1)%MAXQSIZE==front
元素个数: (Q.rear-Q.front+MAXQSIZE)%MAXQSIZE

顺序队列的初始化

void Initqueue(SqQueue& Q)
{
	Q.elem = new Elemtype[MAXQSIZE];
	Q.front = Q.rear = 0;  //头指针和尾指针置为0,队列为空的标志
}

判断顺序队列是否为空/满

bool Isempty(SqQueue& Q)
{
	if (Q.front == Q.rear)
		return true;
	return false;
}
//判断是否满队
//如果队尾+1等于队头,表明队已经满了
//该队列是少用一个空间的循环队列,满队和空队的判断条件不一致
bool Isfull(SqQueue& Q)
{
	auto rear_next = (Q.rear + 1) % MAXQSIZE;
	if (rear_next == Q.front)
		return true;
	else
		return false;
}

进队&批量进队

bool Insertqueue(SqQueue& Q, const Elemtype& e)
{
	if (Isfull(Q)) {
		cout << "队已满,无法进队!" << endl;
		return false;
	}
	Q.elem[Q.rear] = e;  //新元素加入队尾
	Q.rear = (Q.rear + 1) % MAXQSIZE;  
	//队尾指针加1(当成是循环队列)
	return true;
}
//批量进队
#define n 6
void Creatqueue(SqQueue& Q)
{
	cout << "请输入"<<n<<"个队列元素:" << endl;
	Elemtype e;
	for (int i = 1; i <= n; i++) {
		cin >> e;
		Insertqueue(Q, e);
	}
}

出队

void Outqueue(SqQueue& Q)
{
	if (Isempty(Q))  
	//如果队头等于队尾,表明队里没有元素,不执行该程序
	{
		cout << "队列为空,没有元素可以出队" << endl;
	}
	Elemtype e;
	e = Q.elem[Q.front];  //保存队头元素
	Q.front = (Q.front + 1) % MAXQSIZE;  //队头指针加1
}

获取队列中元素的个数

int Length(SqQueue& Q)
{
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

打印队列

void Printqueue(SqQueue& Q)
{
	for (auto i = Q.front; i != Q.rear; i = (i + 1) % MAXQSIZE)
	{
		cout << Q.elem[i] << "  ";
	}
}

测试代码

#include <iostream>
using namespace std;

int main(void) {
	SqQueue Q;
	Initqueue(Q);
	Creatqueue(Q);

	cout << "此队列为:" << endl;
	Printqueue(Q);

	Outqueue(Q);
	cout <<endl<< "一个元素出队后队列为:" << endl;
	Printqueue(Q);

	int n1 = Length(Q);
	cout<<endl<< "队列中元素的个数为:" << n1 << endl;

	cout << "元素出队为:" << endl;
	while (!Isempty(Q))
	{
		cout <<Q.elem[Q.front] << " ";
		Outqueue(Q);
	}

	int n2 = Length(Q);
	cout <<endl<< "队列中元素的个数为:" << n2<< endl;

	system("pause");
	return 0;
}

二.链队

链队的表示

在这里插入图片描述
若用户无法估计所用队列的长度,则适合采用链队列

链队的定义

typedef char Elemtype;
typedef struct Qnode  
//定义结点,每个结点包括数据域data和指向下一个结点的指针域next
{
	Elemtype data;
	Qnode* next;
}Qnode;
//再定义一个抽象数据类型,表示队列,建立两个Qnode指针
typedef struct Linkqueue  
{
	Qnode* front;  //链队的头指针
	Qnode* rear;  //链队的尾指针
}Linkqueue;

链队的初始化

void Initqueue(Linkqueue &L)
{
	L.front = L.rear = new Qnode;
	L.front->data = 0;  //用于保存链队的元素个数
	L.rear->next = nullptr;  //尾指针的指针域置为空
}

链队的销毁

从队头结点开始,依次释放所有的结点

bool Destroyqueue(Linkqueue& L)
{
	while (L.front)
	{
		Qnode* p = L.front->next;
		delete L.front;
		L.front = p;
	}
	return true;
}

链队入队

void Insertqueue(Linkqueue& L, const Elemtype& e)  
//把元素插在队尾
{
	Qnode* p = new Qnode;
	p->data = e;
	p->next = nullptr;
	L.rear->next = p;
	L.rear = p;
	++L.front->data;  //队头指针数据域储存元素个数,加1
}

链队出队

bool Outqueue(Linkqueue& L, Elemtype &e)
{
	if (L.front->next == nullptr)
	{
		cout << "空队列,无法出队!" << endl;
		return false;
	}
	Qnode* p = L.front->next;
	L.front->next = p->next;
	e = p->data;
	delete p;
	--L.front->data;
	return true;
}

创建&打印链队

void Creatqueue(Linkqueue& L)
{
	cout << "请输入"<<count<<"个链队元素:" << endl;
	for (int i = 1; i <= count; i++) {
		Elemtype e;
		cin >> e;
		Insertqueue(L, e);
	}
}
void Printqueue(Linkqueue& L)
{
	Qnode* p = L.front->next;
	while(p)
	{
		cout << p->data <<"  ";
		p = p->next;
	}
}

测试代码

#include <iostream>
using namespace std;

int main(void)
{
    Linkqueue L;
	Initqueue(L);
	Creatqueue(L);
	cout << "此链队为:" << endl;
	Printqueue(L);

	//int m = L.front->data;
	//cout <<endl<< "此时链队中的元素个数为:" << m << endl;
	char e1 = L.front->next->data;
	cout <<endl<< "此时链队的队头元素为:" << e1 << endl;

	Elemtype x;
	Outqueue(L,x);
	cout << "出队元素为:" << x << endl;
	cout << "头元素出队后的链队为:" << endl;
	Printqueue(L);

	int n = L.front->data;
	cout << endl << "此时链队中的元素个数为:" << n << endl;
	char e2 = L.front->next->data;
	cout << "此时链队的队头元素为:" << e2 << endl;

  system("pause");
  return 0;
  }
### C++队列的实现与使用 #### 的实现与使用 在 C++ 的标准模板库(STL)中,`std::stack` 是一种容器适配器,它提供了后进先出(LIFO, Last In First Out)的数据存储方式。其基本操作包括 `push`, `pop`, `top`。 以下是 `std::stack` 的一些常用功能及其说明: - **`push(element)`**: 将一个元素压入顶。 - **`pop()`**: 移除顶的元素。 - **`top()`**: 返回顶元素的引用。 - **`empty()`**: 判断是否为空。 - **`size()`**: 返回中元素的数量。 示例代码展示如何使用 `std::stack`: ```cpp #include <iostream> #include <stack> int main() { std::stack<int> s; // 压入元素到中 s.push(1); s.push(2); // 输出顶元素 std::cout << "Top element: " << s.top() << std::endl; // 删除顶元素 s.pop(); // 检查是否为空 if (!s.empty()) { std::cout << "Stack is not empty." << std::endl; } // 获取当前大小 std::cout << "Size of stack: " << s.size() << std::endl; return 0; } ``` 上述代码展示了如何创建并操作一个整型[^1]。 #### 队列的实现与使用 同样,在 STL 中,`std::queue` 提供了一种先进先出(FIFO, First In First Out)的数据结构。它的基础操作包括 `push`, `pop`, `front`, `back`。 具体的操作描述如下: - **`push(element)`**: 向队列尾部添加新元素。 - **`pop()`**: 移除队首元素。 - **`front()`**: 返回队首元素的引用。 - **`back()`**: 返回队尾元素的引用。 - **`empty()`**: 判断队列是否为空。 - **`size()`**: 返回队列中元素的数量。 下面是关于 `std::queue` 使用的一个简单实例: ```cpp #include <iostream> #include <queue> int main() { std::queue<int> q; // 添加元素至队列 q.push(1); q.push(2); // 访问队首元素 std::cout << "Front element: " << q.front() << std::endl; // 访问队尾元素 std::cout << "Back element: " << q.back() << std::endl; // 删除队首元素 q.pop(); // 检查队列是否为空 if (!q.empty()) { std::cout << "Queue is not empty." << std::endl; } // 查看当前队列大小 std::cout << "Size of queue: " << q.size() << std::endl; return 0; } ``` 这段代码演示了如何初始化、填充以及管理一个简单的整数队列[^5]。 #### 自定义实现队列 除了直接利用 STL 容器外,还可以通过数组或者链表手动模拟队列的行为。这有助于深入理解这些数据结构的工作机制。例如,可以自定义一个基于动态数组的类或队列类,并重载必要的成员函数来完成相应的逻辑处理[^3]。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值