惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
L
LINUX DO - 热门话题
S
Secure Thoughts
TaoSecurity Blog
TaoSecurity Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
T
Threat Research - Cisco Blogs
AI
AI
B
Blog RSS Feed
S
Schneier on Security
雷峰网
雷峰网
Schneier on Security
Schneier on Security
Help Net Security
Help Net Security
Cloudbric
Cloudbric
L
LINUX DO - 最新话题
罗磊的独立博客
有赞技术团队
有赞技术团队
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Apple Machine Learning Research
Apple Machine Learning Research
P
Proofpoint News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
The Hacker News
The Hacker News
博客园 - Franky
Attack and Defense Labs
Attack and Defense Labs
The Cloudflare Blog
Webroot Blog
Webroot Blog
Last Week in AI
Last Week in AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
博客园 - 叶小钗
美团技术团队
L
Lohrmann on Cybersecurity
T
The Blog of Author Tim Ferriss
The Last Watchdog
The Last Watchdog
T
Troy Hunt's Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Vercel News
Vercel News
Know Your Adversary
Know Your Adversary
O
OpenAI News
博客园 - 【当耐特】
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cybersecurity and Infrastructure Security Agency CISA
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
PCI Perspectives
PCI Perspectives
H
Heimdal Security Blog
I
InfoQ
GbyAI
GbyAI
T
Threatpost
C
Cisco Blogs

博客园 - 新西兰程序员

C++ 构造函数中的初始化参数列表initializer list C++中的线程thread,以及C++11中的std::atomic学习 Leetcode56 Merge Intervals 合并区间 -- C++实现 C++中的内存对齐 C++中的static关键字使用以及全局变量 C++17中的结构化绑定Structured Binding C++中的函数参数是指针类型, 是按值传递 C++中异常处理机制中的栈展开stack unwinding C++实现链表反转 Linux中的性能分析工具 perf 来分析C++性能 C++17中新建一个类时,编译器默认生成的类成员函数 QT中的元对象系统 Leetcode 114 - 二叉树展开为链表 Leetcode65 有效数字 - 判断给定的字符串是否是一个有效数字 LettCode2289-Steps to Make Array Non-descreasing C#中的委托详解 C++中的std::function C++中的仿函数Functor C++中的const和constexpr异同比较 C++中的左值和右值,以及右值引用,移动语义 C++中传递参数是指针类型以及传入参数是指针的指针(**)详解 C++中GetTickCount函数学习 C++中以类的成员函数作为Windows callback函数需要设置成static函数 C#中的System.Security.SecureString学习 C++中的悬挂指针和野指针 C++中四种不同的对象生存方式(in stack, in heap, global, local static) C#中使用Parallel类来进行多线程并发编程 String类型转LPCTSTR -----理解C++中的字符串类型转换 C++中的虚函数和虚函数表 C++中基类指针指向派生类对象
数据结构 - 栈的学习
新西兰程序员 · 2024-03-22 · via 博客园 - 新西兰程序员

栈 (Stack) 是一种非常常见的数据结构, 是一种 "先入后出"(First In Last Out, FILO)  "后进先出" 的数据结构 (Last In First Out,  LIFO)。  也可以把栈看成是一种特殊的线性表,只能在栈顶进行插入和删除操作。 也就是说,对于栈而言,你只能在栈顶进行操作,而栈底是固定的

栈的基本操作,包括 入栈(Push), 出栈(Pop), 取栈顶元素(Top) , 判空 (IsEmpty) 等

栈有顺序栈和链式栈

1. 顺序栈

我们来看看顺序栈的示意图:

顺序栈是一种使用数组实现的栈,也称为数组栈, 也就是说,它是通过数组来存储栈中的元素的, 并且通过栈顶指针来指示栈顶元素在数组中的位置。 顺序栈具有以下特点:

1. 存储结构: 顺序栈使用数组来作为底层的存储结构,栈中的每个元素会作为数组中的一个元素存在

2. 操作顺序:  栈只能够从栈顶插入和删除元素,不支持在栈中间插入和删除元素

3. 顺序访问:  只能从栈顶开始访问栈中的元素,不能从栈底或者中间位置来访问元素

 由上面可以看出,顺序栈的实现并不是很难,我们可以通过数组和栈顶指针两个变量来进行实现。 它的一些主要操作包括 初始化,入栈,出栈,获取栈顶元素,判断栈是否为空, 以及获取栈中元素的数量等。 

上面也提到,顺序栈的存储结构是数组,因此我们使用时也需要考虑数组大小的限制,当栈中元素数量超过数组大小时,需要对数组进行扩容

时间复杂度:

 遍历栈中元素的操作时间复杂度为 O(n)

入栈,出栈,获取栈顶元素,判断栈是否为空   =>  这几个操作时间复杂度为 O(1)

现在,我用C++来实现栈的这些基本操作

1. 用结构来定义一个栈

// 栈中的数据类型
typedef int stackType;
#define INITCAPA 5
//栈结构 typedef struct Stack{ stackType *arr; //数组 int top; //栈顶 int capacity; //栈的容量 } ST;

2. 初始化栈

void StackInit(ST *pst)
{
assert(pst);
pst->arr = (stackType *)malloc(INITCAPA * sizeof(stackType));
if(pst->arr == NULL)
{
perror("malloc fail");
return;
}
pst->top = 0; // top等于0,指的是栈顶元素的下一个位置
// pst->top = -1; //指的是栈顶元素的位置
pst->capacity = INTICAPA; }

 3. 判断空栈

因为在第2步中pst->top赋的初值为0. 所以当 top == 0 时,就表示栈为空

bool StackEmpty(ST* pst)
{
assert(pst);
return pst->top == 0; }

4. 入栈

入栈,需要先判断栈满没满,满的条件为 ptr->top == ptr->capacity, 如果栈已经满了,我们还想有元素入栈,那么就需要对栈进行扩容。 扩容的过程和顺序表是一样的

从上面第2步可以知道,top表示的是栈顶元素的下一个位置,所以在top下标处位置进行插入数据就可以。 完成后进行 top++就可以完成一次入栈了

void STPush(ST* pst, stackType newElement)
{
assert(pst);
if(pst->capacity == pst->top)
{
stackType* tmp = (stackType*)realloc(pst->arr, sizeof(stackType) * pst->capacity * 2);
if(tmp == NULL)
{
perror("realloc fail");
return;
}
pst->arr = tmp;
pst->capacity *= 2;
}
pst->arr[pst->top] = newElemenet;
pst->top++; }

5. 出栈

出栈,如果栈为空,出栈就会出问题,所以出栈前,我们需要判断一下,栈不为空

上面提到,入栈后top++, 显然,出栈就是top--, 也就是说我们进行 pst->top--, top值减去1,那么在其他所有操作中就访问不到最后一个元素了,也就达到了出栈的效果

void STPop(ST* pst)
{
assert(pst);
assert(!
StackEmpty(pst));
pst->top--;
}

6. 获取栈顶元素的值

获取栈顶元素的值,显然有个前提条件那就是栈中得有元素存在。如果栈是个空栈,那什么也获取不到,所以获取之前,还是需要使用上面自己写的StackEmpty方法判断一下

从上面可以知道,top表示栈顶元素的下一个位置,所以 top -1才表示栈顶元素的下标, 也就是 pst->arr[pst->top - 1] , 代码如下

stackType STTop(ST* pst)
{
assert(pst);
assert(!StackEmpty(pst));
return pst->arr[pst->top -1];

}

 7, 销毁

void STDestory(ST* ptr)
{
assert(ptr);
free(ptr->arr);
ptr->arr == NULL;
ptr->capacity = 0;
ptr->top = 0; }