栈
栈的物理结构是一个数组,但是栈的逻辑结构是先进后出,类似于子弹入弹夹最后放入的子弹是最先打出的.相当于在数组的基础上加上了先进后出的规定.
C语言
#include<stdio.h>
#include<stdlib.h>
#define maxx 10
typedef struct {
int* data;
int top;
}Stack;
Stack InitStack() {
Stack s;
s.data = (int*)malloc(sizeof(int) * maxx);
if (s.data == NULL) {
printf_s("内存申请失败\n");
s.top = -1;
return s;
}
s.top = 0;
return s;
}
void Push(Stack* s, int k) {
if (s->top == maxx){
printf_s("栈满,无法入栈\n");
return;
}
s->data[s->top] = k;
s->top++;
return;
}
int IsEmpety(Stack* s) {
if (s->top == 0) {
return 1;
}
return 0;
}
void Pop(Stack* s)
{
if (IsEmpety(s))
{
printf("栈空,无法出栈\n");
return;
}
s->top--;
}
int Get(Stack s) {
if (IsEmpety(&s))
{
printf("栈空,无法出栈\n");
return;
}
return s.data[s.top - 1];
}
int main()
{
Stack s = InitStack();
Push(&s, 1);
Push(&s, 2);
Push(&s, 3);
Pop(&s);
Pop(&s);
Pop(&s);
printf("%d\n", Get(s));
return 0;
}
对于栈的操作非常的简单初始化 入栈 判空 出栈 获取栈顶元素,在逻辑上栈是不能进行遍历的所以没有加入遍历打印的操作.
首先用一个结构体包装Stack栈,包括了数据域和栈顶"指针"两部分,这个栈顶指针实质是下标.
1.初始化栈用malloc申请内存,常规操作需要判断内存是否申请成功,如果失败的话我们需要让top == -1进行标记,然后直接return.如果申请成功则让top == 0.
2.入栈操作我们会对栈进行修改所以应该用地址传参Stack* s,先对栈进行判满,如果没满那么直接让s->data[s->top] = k,top这个栈顶指针其实指向的是栈顶元素的上一个位置,入栈后栈顶也需要上移所以top++.
3.判空函数直接看栈顶是否等于0,如果是的那么说明这是一个空栈,反之不是.
4.删除操作需要结合判空函数,如果不空那么我们直接让top--即可,在逻辑上删除这个元素.因为我们对栈中元素进行了操作所以这里也是地址传参.
5.获取栈顶元素我们没有对栈进行操作,我们只是想看看栈顶的元素是啥,所以可以用值传参,这个操作也需要对栈进行判空但我们传入的是一个值,所以里面的判空函数我们需要取地址&.然后直接返回栈顶的值即可.
栈的操作少而且简单,只要牢牢抓住先进后出这个规则即可.还需要注意我们的传参方式是取决于对栈的操作要不要改变栈.
C++
#include<iostream>
using namespace std;
#define maxx 10
class Stack {
private:
int* data;
int top;
public:
Stack(){
this->data = new int[maxx];
this->top = 0;
}
void Push(int k) {
if (top == maxx) {
cout << "栈满,无法入栈" << endl;
this->top = -1;
return;
}
this->data[this->top] = k;
this->top++;
return;
}
int IsEmpety(){
if (this->top == 0) {
return 1;
}
return 0;
}
void Pop(){
if (this->IsEmpety()) {
cout << "栈空,无法删除" << endl;
return;
}
this->top--;
return;
}
int Get(){
if (this->IsEmpety()) {
cout << "栈空,无法删除" << endl;
return -1;
}
return this->data[this->top - 1];
}
void Print() {
if (IsEmpety()) {
cout << "栈空" << endl;
return;
}
cout << "栈内元素:";
for (int i = 0; i < top; i++) {
cout << data[i] << " ";
}
cout << endl;
}
~Stack() {
delete[] data; // 释放数组内存
}
};
int main() {
// 1. 创建栈(自动调用构造函数)
Stack s;
// 2. 入栈
s.Push(10);
s.Push(20);
s.Push(30);
cout << "入栈 10、20、30 后:" << endl;
s.Print(); // 打印栈
// 3. 获取栈顶
cout << "当前栈顶元素:" << s.Get() << endl;
// 4. 出栈
s.Pop();
cout << "出栈一次后:" << endl;
s.Print();
s.Pop();
s.Pop();
cout << "出栈三次后:" << endl;
s.Print();
// 5. 空栈测试
s.Pop(); // 栈空,无法删除
s.Get(); // 栈空,无法获取
return 0;
}
在C++中我们改用类来封装Stack相较于C语言中的结构体优点是不用再传 &s、不用管指针.