C/C++ 入门算法,“栈”的全面剖析

栈的原理精讲

栈是一种线性结构,即线性排列。
好比如一条胡同:
在这里插入图片描述
先进来的车子只能等后面进来的车子出去后,他才能出去,也就体现了栈的特性:“后进先出”!

栈也是一种线性表,只不过它是操作受限的线性表,只能在一端操作。

进出的一端称为栈顶(top),另一端称为栈底(base)。栈可以用顺序存储,也可以用链式存储。我们先看顺序存储方式:
在这里插入图片描述
其中,base 指向栈底,top 指向栈顶。

注意:栈只能在一端操作,后进先出,这是栈的关键特征,也就是说不允许在中间查找、取值、插入、删除等操作,我们掌握好顺序栈的初始化、入栈,出栈,取栈顶元素等操作即可。

栈顶永远都是指向下一个待插入元素的位置!!!


顺序栈的算法实现

代码中所用到的所有接口:

bool initStack(Stack &stack);	// 初始化栈
bool estimateStackEmpty(Stack &stack);	// 判断是否为空
bool estimateStackFull(Stack &stack);	// 判断是否已满
int stackSize(Stack &stack);	// 获取栈已存储的元素个数
bool insertStack(Stack &stack, ElemType value); // 入栈
bool popStack(Stack &stack, ElemType &vlaue);	// 出栈
bool gainStack(Stack &stack, ElemType& value);	// 获取栈顶的元素
void deleteStack(Stack &stack);	// 释放栈的内存

栈数据结构的定义
#define StackMax 128	// 栈最大可以存放的元素个数

typedef int ElemType;	// 栈存储的数据类型

// 建栈
typedef struct _SqStack {
	ElemType *top;	// 栈顶指针
	ElemType *base;	// 栈底指针
}Stack;

栈的初始化

为栈底base分配内存,然后top,base都指向这块内存!
在这里插入图片描述

bool initStack(Stack &stack) {
	stack.base = new ElemType[StackMax];	// 分配内存(栈底指向它)
	if (!stack.base) {	// 判断是否分配内存失败
		return false;
	}

	stack.top = stack.base;	// 栈顶栈底指向同一个位置
	return true;
}

检测栈是否为空 && 检测栈是否已满

当栈顶与栈尾相等时,即栈为空!(由上面栈的初始化可知)

bool estimateStackEmpty(Stack &stack) {
	if (stack.top == stack.base) {	// 当栈顶栈底指向同一个位置,栈为空。
		return true;
	}
	return false;
}

当栈顶减去栈尾等于宏定义StackMax时,即栈已满!

bool estimateStackFull(Stack &stack) {	// 指针的特性:指针一减去指针二,可以得出他们
	if ((stack.top - stack.base) == StackMax) {	// 之中相隔几个元素。
		return true;					// 当与栈所能存储的最大值相等时,为满。
	}
	return false;
}

入栈

入栈操作:判断是否栈满,如果栈已满,则入栈失败,否则将元素放入栈顶,栈顶指针向上移动一个空间(top++)。

栈顶永远都是指向下一个待插入元素的位置!!!
在这里插入图片描述

bool insertStack(Stack &stack, ElemType value) {
	if (estimateStackFull(stack)) {
		cout << "栈已满!" << endl;
		return false;
	}

	*stack.top = value;	// 栈顶指针解引用后,value值赋值给它存储
	stack.top++;		// 栈顶指针只增一

	return true;
}

出栈

出栈操作: 和入栈相反,出栈前要判断是否栈空,如果栈是空的,则出栈失败,否则将栈顶自减一后(top–),减一后的栈顶指向的内存中的元素暂存给一个变量返回。
在这里插入图片描述

// 栈顶元素出栈后,保存出栈元素返回
bool popStack(Stack &stack, ElemType &value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	stack.top--;	// 栈顶指针自减一
	value = *stack.top;	// 将栈顶指针所在位置的值赋值给value返回

	return true;
}

获取栈顶元素

取栈顶元素和出栈不同,取栈顶元素只是把栈顶元素复制一份,栈的元素个数不变,而出栈是指栈顶元素取出,栈内不再包含这个元素。
在这里插入图片描述

bool gainStack(Stack &stack, ElemType& value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	value = *(stack.top - 1);	// 将栈顶指针“假”减一后的值赋值给value返回

	return true;
}

清空栈

释放内存

void deleteStack(Stack &stack) {
	if (stack.base) {
		delete stack.base;
		stack.top = NULL;
		stack.base = NULL;
		cout << "栈已释放内存!" << endl;
	}
}

获取栈存储的元素个数

栈顶减去栈尾即为栈存储的元素个数!

int stackSize(Stack &stack) {	// 指针的特性:指针一减去指针二,可以得出他们之中相隔几个元素。
	return stack.top - stack.base;
}

完整源码实现
#include <iostream>
#include <Windows.h>

using namespace std;

#define StackMax 128	// 栈最大可以存放的元素个数

typedef int ElemType;	// 栈存储的数据类型

// 建栈
typedef struct _SqStack {
	ElemType *top;	// 栈顶指针
	ElemType *base;	// 栈底指针
}Stack;

bool initStack(Stack &stack);	// 初始化栈
bool estimateStackEmpty(Stack &stack);	// 判断是否为空
bool estimateStackFull(Stack &stack);	// 判断是否已满
int stackSize(Stack &stack);	// 获取栈已存储的元素个数
bool insertStack(Stack &stack, ElemType value); // 入栈
bool popStack(Stack &stack, ElemType &vlaue);	// 出栈
bool gainStack(Stack &stack, ElemType& value);	// 获取栈顶的元素
void deleteStack(Stack &stack);	// 释放栈的内存


bool initStack(Stack &stack) {
	stack.base = new ElemType[StackMax];	// 分配内存(栈底指向它)
	if (!stack.base) {	// 判断是否分配内存失败
		return false;
	}

	stack.top = stack.base;	// 栈顶栈底指向同一个位置
	return true;
}

bool estimateStackEmpty(Stack &stack) {
	if (stack.top == stack.base) {	// 当栈顶栈底指向同一个位置,栈为空。
		return true;
	}
	return false;
}


bool estimateStackFull(Stack &stack) {	// 指针的特性:指针一减去指针二,可以得出他们
	if ((stack.top - stack.base) == StackMax) {	// 之中相隔几个元素。
		return true;					// 当与栈所能存储的最大值相等时,为满。
	}
	return false;
}


int stackSize(Stack &stack) {	// 指针的特性:指针一减去指针二,可以得出他们之中相隔几个元素。
	return stack.top - stack.base;
}


bool insertStack(Stack &stack, ElemType value) {
	if (estimateStackFull(stack)) {
		cout << "栈已满!" << endl;
		return false;
	}

	*stack.top = value;	// 栈顶指针解引用后,value值赋值给它存储
	stack.top++;		// 栈顶指针只增一

	return true;
}


// 栈顶元素出栈后,保存出栈元素返回
bool popStack(Stack &stack, ElemType &value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	stack.top--;	// 栈顶指针自减一
	value = *stack.top;	// 将栈顶指针所在位置的值赋值给value返回

	return true;
}


bool gainStack(Stack &stack, ElemType& value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	value = *(stack.top - 1);	// 将栈顶指针“假”减一后的值赋值给value返回

	return true;
}


void deleteStack(Stack &stack) {
	if (stack.base) {
		delete stack.base;
		stack.top = NULL;
		stack.base = NULL;
		cout << "栈已释放内存!" << endl;
	}
}


int main(void) {
	Stack stack;

	// 初始化栈
	initStack(stack);

	// 插入元素
	int n = 0;
	int value = 0;
	cout << "请输入需要插入的元素个数:";
	cin >> n;

	while (n > 0) {
		cin >> value;
		insertStack(stack, value);
		n--;
	}

	// 获取栈顶的元素
	gainStack(stack, value);
	cout << "当前栈顶的元素是:" << value << endl;

	// 获取栈的元素个数
	cout << "当前栈的元素个数是:" << stackSize(stack) << endl;


	// 出栈
	cout << "出栈顺序:" << endl;
	while (!estimateStackEmpty(stack)) {
		popStack(stack, value);
		cout << value << " ";
	}
	cout << endl;

	// 释放栈的内存
	deleteStack(stack);

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述


课后思考:

如果把栈的结构体定义改为如下形式,该如何实现操作栈的算法?

typedef struct _SqStack {
	int top;		// 栈顶的位置
	ElemType* base;	// 栈底指针
}Stack;

=

=

=

具体实现:

#include <iostream>
#include <Windows.h>

using namespace std;

#define StackMax 128	// 栈最大可以存放的元素个数

typedef int ElemType;	// 栈存储的数据类型

// 建栈
typedef struct _SqStack {
	int top;		// 栈顶的位置
	ElemType* base;	// 栈底指针
}Stack;

bool initStack(Stack& stack);	// 初始化栈
bool estimateStackEmpty(Stack& stack);	// 判断是否为空
bool estimateStackFull(Stack& stack);	// 判断是否已满
int stackSize(Stack& stack);	// 获取栈已存储的元素个数
bool insertStack(Stack& stack, ElemType value); // 入栈
bool popStack(Stack& stack, ElemType& vlaue);	// 出栈
bool gainStack(Stack& stack, ElemType& value);	// 获取栈顶的元素
void deleteStack(Stack& stack);	// 释放栈的内存


bool initStack(Stack& stack) {
	stack.base = new ElemType[StackMax];	// 分配内存(栈底指向它)
	if (!stack.base) {	// 判断是否分配内存失败
		return false;
	}

	stack.top = 0;
	return true;
}

bool estimateStackEmpty(Stack& stack) {
	if (stack.top == 0) {	// 当栈顶位置等于零,为空
		return true;
	}
	return false;
}


bool estimateStackFull(Stack& stack) {		
	if (stack.top == StackMax) {	// 当栈顶位置等于栈所能存储的最大值时,为满
		return true;					
	}
	return false;
}


int stackSize(Stack& stack) {	
	return stack.top;	// 栈顶位置就是元素的个数
}


bool insertStack(Stack& stack, ElemType value) {
	if (estimateStackFull(stack)) {
		cout << "栈已满!" << endl;
		return false;
	}

	stack.base[stack.top] = value;	// 以栈顶位置作为下标存储数据
	stack.top++;	// 栈顶自增一

	return true;
}


// 栈顶元素出栈后,保存出栈元素返回
bool popStack(Stack& stack, ElemType& value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	stack.top--;	// 栈顶自减一
	value = stack.base[stack.top];	// 以栈顶位置作为下标的值赋值给value返回

	return true;
}


bool gainStack(Stack& stack, ElemType& value) {
	if (estimateStackEmpty(stack)) {
		cout << "栈为空!" << endl;
		return false;
	}

	value = stack.base[stack.top - 1];	// 将栈顶下标“假”减一后的值赋值给value返回

	return true;
}


void deleteStack(Stack& stack) {
	if (stack.base) {
		delete stack.base;
		stack.top = 0;
		stack.base = NULL;
		cout << "栈已释放内存!" << endl;
	}
}


int main(void) {
	Stack stack;

	// 初始化栈
	initStack(stack);

	// 插入元素
	int n = 0;
	int value = 0;
	cout << "请输入需要插入的元素个数:";
	cin >> n;

	while (n > 0) {
		cin >> value;
		insertStack(stack, value);
		n--;
	}

	// 获取栈顶的元素
	gainStack(stack, value);
	cout << "当前栈顶的元素是:" << value << endl;

	// 获取栈的元素个数
	cout << "当前栈的元素个数是:" << stackSize(stack) << endl;


	// 出栈
	cout << "出栈顺序:" << endl;
	while (!estimateStackEmpty(stack)) {
		popStack(stack, value);
		cout << value << " ";
	}
	cout << endl;

	// 释放栈的内存
	deleteStack(stack);

	system("pause");
	return 0;
}

在这里插入图片描述


课后作业:栈的链式存储结构

栈其实是可以使用链表来实现的,具体实现给大家自己去思考啦!

=

=

=

刚开始小编首先想到的是使用双向链表来实现,但是这样实属杀鸡使用宰牛刀!

于是乎再进一步思考了一会,发现单向循环链表也可以做!
使用单向循环链表实现图解:

在这里插入图片描述

但是还可以更加简便,那就是使用单向链表来实现!

希望下面两幅图片可以助你理解:使用单向链表实现

在这里插入图片描述
在这里插入图片描述

单向链表实现栈 代码:

#include <iostream>
#include <Windows.h>

using namespace std;

typedef int DateType;

// 循环单项链表
typedef struct _linkStack {
	DateType date;
	int size;					// 统计栈的个数
	struct _linkStack *next;	// 头节点指向栈顶,其他节点指向下一个节点
}LinkList, LinkNode;



bool initLink(LinkList*& list);	// 初始化双向链表的栈
bool insertNode(LinkList*& list, LinkNode*& node); // 尾插法入栈
bool popNode(LinkList*& list, DateType& value);		// 出栈
bool gainNode(LinkList*& list, DateType& value);	// 获取栈顶的值
bool clearLink(LinkList*& list);	// 释放内存
void print_1(LinkList*& list);		// 单纯输出



bool initLink(LinkList*& list) {
	list = new LinkList;	// 分配内存
	if (!list) {
		cout << "内存分配失败!" << endl;
		return false;
	}

	list->date = -1;
	list->size = 0;
	list->next = NULL;

	return true;
}


bool insertNode(LinkList*& list, LinkNode*& node) {
	if (!list || !node) {
		cout << "节点不存在!" << endl;
		return false;
	}

	// 实现连接
	node->next = list->next;	// 新节点的next指向头节点的下一个节点
	list->next = node;			// 头节点的next指向新节点

	list->size++;	// 栈的元素个数加一

	return true;
}



bool popNode(LinkList*& list, DateType& value) {
	if (!list) {
		cout << "节点不存在!" << endl;
		return false;
	}

	value = list->next->date;	// 将头节点的下一个节点的值赋值给value返回

	list->size--;	// 栈的元素个数减一

	LinkNode* p = list->next;	// 将头节点的下一个节点赋值给节点p
	list->next = p->next;		// 头节点的next指向p的next
	delete p;	// 释放p的内存

	return true;
}



bool gainNode(LinkList*& list, DateType& value) {
	if (!list) {
		cout << "节点不存在!" << endl;
		return false;
	}

	value = list->next->date;	// 将头节点的下一个节点的值赋值给value返回

	return true;
}

bool clearLink(LinkList*& list) {
	if (!list) {
		return false;
	}

	list->size = 0;		// 栈的元素个数赋值0

	LinkList* p = list;		// 头节点赋值给p
	while (p) {			// p不为NULL执行循环
		list = list->next;	// 头节点只想自己的下一个节点
		delete p;			// 释放原头节点的内存
		p = list;			// 头节点赋值给p
	}
	cout << "释放成功!" << endl;
	return true;
}

// 打印栈中的元素
void print_1(LinkList*& list) {
	if (!list) {
		cout << "节点不存在!" << endl;
		return;
	}

	LinkList* p = list->next;
	while (p) {
		cout << p->date << ", ";
		p = p->next;
	}

	cout << endl;
}


int main(void) {
	LinkList* list = NULL;
	LinkNode* node = NULL;

	// 初始化
	initLink(list);


	// 插入元素
	int n = 0;
	int value = 0;
	cout << "请输入入栈的个数:";
	cin >> n;

	while (n > 0) {
		cin >> value;
		node = new LinkNode;
		node->date = value;

		insertNode(list, node);
		n--;
	}

	// 输出
	cout << endl << endl << "插入元素后:" << endl;
	print_1(list);
	cout << "栈的元素个数是:" << list->size << endl;


	// 出栈
	popNode(list, value);
	cout << endl << endl << "栈顶出栈后,出栈元素是:" << value << endl;
	cout << "栈的元素个数是:" << list->size << endl;

	cout << endl << endl << "栈的元素:" << endl;
	print_1(list);


	// 获取栈顶的元素
	gainNode(list, value);
	cout << endl << endl << "获取栈顶的元素是:" << value << endl;

	// 释放内存
	cout << endl << endl << "释放栈的内存:";
	clearLink(list);

	print_1(list);

	system("pause");
	return 0;
}

运行截图:
在这里插入图片描述


总结:
其实栈算是算法当中最简单的了,他不像堆、链表顺序表等那些那么繁杂!
重点理解他是如何入栈和出栈就可以了!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cpp_learners

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值