数据结构——栈

Posted 请揣满RMB

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构——栈相关的知识,希望对你有一定的参考价值。

🐨文章目录

⛺0. 前言

相信大部分的小伙伴,在小时候都玩过玩具枪,弹夹里面的"子弹",最先放进去,最后才打出来;最后放进去的"子弹",最先打出来。
其实在数据结构里面,也有一种这样的结构——栈,数据先进后出。

🏡1. 栈的概念及结构

🎈1.1 概念

  • 栈是限定仅在尾处进行插入和删除的线性表。因此对于栈来说,尾处有特殊含义,称为栈顶,头部称为栈底,不含元素的称为空栈
  • 压栈:栈的插入操作叫做压栈 / 进栈 / 入栈入的数据在栈顶
  • 出栈:栈的删除操作叫出栈出的数据也在栈顶
  • 栈中元素遵守后进先出LIFO(Last In First Out),的原则。

进栈、出栈示例:

🎈1.2 结构

栈可以用顺序表或者链表的方式实现。那么哪一种实现方式会好一点呢?

  • 数据结构都是在内存中管理我们的数据,当我们要对数据进行操作时,都是cpu来执行这些指令。
  • 因为内存的访问速度较慢,所以cup不会去直接访问内存,数据会先存储到cpu的缓存中。如果数据在缓存中,就叫命中;如果未命中,缓存的控制器就会将一定数量的数据块从内存读取到缓存中。这些数据的地址往往是相邻的。
  • 那么顺序表相比于链表,因为顺序表的内存地址是连续的,所以顺序表的缓存命中率是高于链表的,这是顺序表的一个优势。

所以我们这里用顺序表的结构是相对好一点的,本篇文章也是用顺序表结构实现

🏫2. 接口声明

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

#define STACK_SIZE_INIT 4
typedef int STDataType;

typedef struct Stack

	STDataType* base;
	int top; //栈顶元素下一个
	int capacity; //栈容量
ST;

//初始化
void STInit(ST* ps);

//销毁
void STDestroy(ST* ps);

//入栈
void STPush(ST* ps, STDataType e);

//出栈
void STPop(ST* ps);

//获取栈顶元素
STDataType STTop(ST* ps);

//判空
bool STEmpty(ST* ps);

//获取有效元素个数
int STSize(ST* ps);

💒3. 接口实现

🎇3.1 初始化和销毁

//初始化
void STInit(ST* ps)

	assert(ps);
	ps->base = (STDataType*)malloc(sizeof(STDataType) * 4);
	if (ps->base == NULL)
	
		perror("malloc fail");
		exit(-1);
	
	ps->capacity = STACK_SIZE_INIT;
	ps->top = 0;//top为0表示空栈


//销毁
void STDestroy(ST* ps)

	assert(ps);
	free(ps->base);
	ps->base = NULL;
	ps->capacity = 0;
	ps->top = 0;

🎇3.2 判空

//判空
bool STEmpty(ST* ps)

	return ps->top == 0;

tips:
虽然这里判断栈是否为空只有一条语句,但是对于我们写程序的来说,肯定是知道的,但是使用者可能不知道,top是指向栈顶元素下一个还是指向栈顶元素。所以我们封装起来,可读性会更高一点。

🎇3.3 入栈和出栈

//入栈
void STPush(ST* ps,STDataType e)

	assert(ps);
	//判断容量是否已满
	if (ps->top == ps->capacity)
	
		STDataType* tmp = realloc(ps->base, sizeof(STDataType) * ps->capacity * 2);
		if (tmp == NULL)
		
			perror("realloc fail");
			exit(-1);
		
		ps->base = tmp;
		ps->capacity *= 2;
	
	ps->base[ps->top] = e;
	ps->top++;


//出栈
void STPop(ST* ps)

	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;

🎇3.4 获取栈顶元素

//获取栈顶元素
STDataType STTop(ST* ps)

	assert(ps);
	assert(!STEmpty(ps));
	return ps->base[ps->top - 1];

🎇3.5 获取有效元素个数

//获取有效元素个数
int STSize(ST* ps)

	assert(ps);
	return ps->top;

🕍4. 接口测试

#define _CRT_SECURE_NO_WARNINGS 1
#pragma warning(disable:6031)
#include"Stack.h"
void TestStack1()

	ST s;
	//初始化
	STInit(&s);
	//压栈
	STPush(&s, 1);
	STPush(&s, 2);
	STPush(&s, 3);
	STPush(&s, 4);
	int size = STSize(&s);
	while (size--)
	
		//获取栈顶元素
		printf("%d ", STTop(&s));
		//出栈
		STPop(&s);
	
	//销毁
	STDestroy(&s);

int main()

	TestStack1();
	return 0;

数据结构-栈(C++实现)

栈:一种线性结构,不过是先进后出,实际生活中随处可见的例子是弹夹,先压进去的子弹最后打出,后压进去的子弹最先打出

栈的顶部称为栈顶,底部称为栈底

栈空的条件:栈顶指针的索引为-1

栈满的条件:栈顶指针指向栈容量大小-1的位置


栈的实现方式:数组栈、链栈,具体见代码实现

栈的特殊情况:共享栈,共享栈就是将两个栈组合起来

共享栈满的条件是:第一个栈的栈顶指针+1=第二个栈的栈顶指针

共享栈为空的条件是:第一个栈的栈顶指针为0,第二个栈的栈顶指针指向共享栈大小-1的位置

代码实现:

1、线性栈的实现

1.1、.h文件

#pragma once#ifndef __Stack__#define __Stack__#define MAXSIZE 30#include<iostream>using namespace std;
class Stack{private: int top; //栈顶 int data[MAXSIZE]; //栈底为data[0]
public: Stack(); //构造函数 ~Stack(); //析构函数 bool push(int val); //进栈 void traverse(); //遍历 bool pop(int& val); //出栈 bool is_empty(); //判断是否为空 bool is_full(); //判断是否栈满};


Stack::Stack():top(-1) //初始化参数,将栈顶指针指向-1的位置{
}
//析构函数Stack::~Stack(){
}
//进栈操作bool Stack:: push(int val){ //首先判断栈是否已满 if (is_full()) { return false; } //栈不满的情况下,先将栈顶指针移动一位,再插入元素 top++; //栈顶指针加一 data[top] = val; //插入元素 return true;}
//出栈操作bool Stack::pop(int& val){ //首先判断栈是否为空,为空则没有元素出栈 if (is_empty()) { return false; } //栈不为空时,先将元素弹出,再将栈顶指针减一 val = data[top]; top--; return true;}
//遍历栈void Stack::traverse(){ int p = top; //指定一个标志指向栈顶 while (p != -1) //当栈不为空时 { cout << data[p] << " "; p--;//p向下移动一个位置 } cout << endl;}
//判断栈是否满bool Stack::is_full(){ return MAXSIZE - 1 == top ? true : false; //如果栈中的元素个数减一为栈顶指针的位置,则判断栈满}
bool Stack::is_empty(){ return -1 == top ? true : false; //当栈顶指针为-1时,表示栈为空}

#endif // !__Stack__

1.2、.cpp文件

#include"Stack.h"#include<iostream>
using namespace std;

int main(){ Stack s; //创建栈对象 int val; s.push(1); s.push(2); s.push(3); s.push(4); s.push(5); s.traverse(); //遍历栈 s.pop(val); //出栈 cout << "出栈的值为:" << val << endl;

system("pause");
return 0;}

2、链栈的实现

链栈的实现类似于单链表,不过是先进后出

2.1、定义结点

/*tangzhao2021.4.14*/
#pragma once
class Node{public: Node(); //构造函数 ~Node(); //析构函数 friend class Stack;
private: int data; //数据域与指针域 Node* pNext; //数据域与指针域};

2.2、定义操作的头文件

/*tangzhao2021.4.14*/
#include"Node.h"#include<iostream>using namespace std;

class Stack{public: Stack(); ~Stack(); bool push(int val); //进栈 void traverse(); //遍历 bool pop(int& val); //出栈 bool empty(); void clear(); //清空private: Node* pTop; //栈顶 Node* pBottom; //栈底};
Stack::Stack(){}
//析构Stack::~Stack(){}
//进栈bool Stack::push(int val){ //因为是链栈,所以不需要判断栈是否已满 Node* pNew = new Node; //创立一个新的结点 pNew->data = val; pNew->pNext = pTop; //将新结点的指针指向栈顶指针 pTop = pNew; //将栈顶指针指向新的元素位置 return true;}
//遍历栈void Stack::traverse(){ Node* p = pTop; //新建一个指针指向栈顶位置 while (p != pBottom) //栈不为空 { cout << p->data << " "; p = p->pNext; //将p指向下一个元素的位置 } cout << endl;}
//出栈bool Stack::pop(int& val){ if (empty()) { return false; } Node* r = pTop; //新建一个指针指向栈顶元素 val = r->data; //取出要出栈的元素 pTop = pTop->pNext; //将栈顶指针下移 delete r; return true;}
//判断栈是否为空bool Stack::empty(){ return pTop == pBottom ? true : false;}
//清理栈void Stack::clear(){ if (empty()) { return; } Node* p = pTop; Node* q = NULL; while (p != pBottom) { q = p->pNext; delete p; p = q; }
}

2.3、.cpp主文件

/*tangzhao2021.4.14*/
#include"Node.h"#include"Stack_list.h"#include<iostream>using namespace std;

int main(){ Stack s; int val; s.push(1); s.push(2); s.push(3); s.push(4); s.push(5); s.traverse(); s.pop(val); cout << "出栈的值为:" << val << endl;

system("pause");
return 0;}

以上就是栈的基本内容,感谢大家的观看,欢迎转发、点赞、收藏,晚安各位。

以上是关于数据结构——栈的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之栈以及栈的基本操作

数据结构笔记——栈

数据结构-栈(C++实现)

数据结构栈和队列-;栈

顺序栈:创建&初始化入栈出栈计算栈中有效数据长度获取栈顶数据清空栈销毁栈

数据结构栈与队列