前言:大家好😍,本文主要介绍了数据结构——顺序栈
目录
一、概念
1.1 顺序栈的基本概念
1.2 顺序栈的存储结构
二、基本操作
2.1 结构体定义
2.2 初始化
2.3 判空
2.4 判满
2.5 扩容
2.6 插入 入栈
2.7 删除 出栈
2.8 获取栈顶元素
2.9 获取有效值长度
2.10 清空
2.11 销毁
2.12 打印
2.13 测试
一、概念
顺序栈是栈的一种实现方式,它是基于顺序存储结构(通常是数组或动态分配的内存空间)实现的栈。栈是一种**后进先出(LIFO,Last In First Out)**的数据结构,这意味着最后放入栈中的元素会最先被取出。
1.1 顺序栈的基本概念
-
栈的定义:
-
栈是一种线性表,其操作主要在表的一端进行,这一端称为栈顶(Top),另一端称为栈底(Bottom)。
-
栈的操作遵循**后进先出(LIFO)**的原则,即最后放入栈中的元素最先被取出。
-
-
顺序栈的特点:
-
顺序栈使用连续的内存空间来存储栈中的元素,通常通过数组或动态分配的内存来实现。
-
栈底的位置是固定的,通常用一个指针(如
base
)来标记栈底。 -
栈顶的位置是动态变化的,用一个指针(如
top
)来表示栈顶的位置。
-
1.2 顺序栈的存储结构
顺序栈的存储结构通常包括以下部分:
ps是一个指向Seq_Stack
结构体的指针,所以 ps可以指向结构体的成员
-
base
:指向栈底的指针,标记栈的起始位置。 -
top
:栈顶指针,表示栈顶的位置。top
的值通常等于栈中元素的数量。 -
stacksize
:表示栈的总容量,即栈可以存储的最大元素数量。
二、基本操作
2.1 结构体定义
typedef char ELEM_TYPE;
#define INITSIZE 10//*2
struct Seq_Stack
{
ELEM_TYPE* base;//指针,用来接收malloc的返回值
int top;//栈顶指针
int stacksize;//当前总的格子数
};
typedef struct Seq_Stack Seq_Stack;
typedef struct Seq_Stack* PSeq_Stack;
base
是一个指针,它的作用是标记栈的底部位置,也就是这块连续内存空间的起始地址。有了base
,我们就能找到栈的“根基”,从而操作整个栈。无论栈顶指针top
如何变化(入栈或出栈),base
始终指向栈的底部,确保我们不会迷失方向。
2.2 初始化
void Init_Seq_Stack(Seq_Stack* ps)
{
assert(ps != NULL);
ps->base = (ELEM_TYPE*)malloc(INITSIZE * sizeof(ELEM_TYPE));
if (ps->base == NULL)//内存分配失败
{
exit(1);//程序调用exit终止运行
}
ps->top = 0;
ps->stacksize = INITSIZE;
}
参数:
Seq_Stack* ps
是一个指向Seq_Stack
结构体的指针。这个结构体定义了栈的基本属性,比如栈底指针、栈顶指针和栈的容量等。
ps->base
:这是栈底指针,用来存储malloc
分配的内存地址。分配完内存后,ps->base
就指向了这块内存的起始位置,也就是栈的底部。malloc
:这是一个动态内存分配函数,用来在堆上分配一块内存空间。
ps->top = 0
:栈顶指针top
初始化为0。在顺序栈中,top
的值通常表示栈中元素的数量。初始时栈为空,所以top
为0。
ps->stacksize = INITSIZE
:将栈的总容量stacksize
设置为初始大小INITSIZE
。这样我们就知道栈一开始可以存储多少个元素。通过
ps
,函数可以访问和修改这个栈的内部数据(如base
、top
和stacksize
)。
2.3 判空
//2.判空(判断顺序表有没有元素)
bool Is_Empty(Seq_Stack* ps)
{
if (ps == NULL)
exit(1);
return ps->top ==0;
}
这个指针
ps
就是用来告诉函数“我要检查的是哪一个栈”。
if (ps == NULL)
来检查指针是否为空。如果是空的,说明传入的栈是无效的,程序会调用exit(1)
终止运行,避免后续操作出错。
2.4 判满
bool Is_Full(Seq_Stack* ps)
{
if (ps == NULL)
return false;
return ps->top == ps->stacksize;
}
2.5 扩容
//4.扩容
static void Inc(Seq_Stack*ps)
{
assert(ps != NULL);
if (ps == NULL)
return;
ELEM_TYPE* tmp = (ELEM_TYPE*)realloc(ps->base, ps->stacksize * sizeof(ELEM_TYPE) * 2);
if (tmp != NULL)
ps->base = tmp;
ps->stacksize *= 2;
}
Inc
函数用于将顺序栈的容量加倍。从而允许更多的元素入栈。
realloc
:这是一个动态内存分配函数,用来重新分配一块内存空间。它接受两个参数:
第一个参数是当前内存块的指针(这里是
ps->base
)。第二个参数是新的内存大小(这里是
ps->stacksize * sizeof(ELEM_TYPE) * 2
)。ps->stacksize
是当前栈的容量,sizeof(ELEM_TYPE)
是每个元素的大小,* 2
表示将容量加倍。
tmp
:这是一个临时指针,用来存储realloc
返回的新内存地址。如果realloc
成功,它会返回新的内存块的指针;如果失败,它会返回NULL
。如果
tmp
不为NULL
,说明realloc
成功,新的内存已经分配好了。此时,将ps
所指向的结构体中的base
成员更新为tmp
的值。,即让栈底指针指向新的内存地址。将栈的总容量
stacksize
加倍。
2.6 插入 入栈
//插入元素(入栈/压栈) Push
bool Push(Seq_Stack* ps, ELEM_TYPE val)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if (Is_Full(ps))
{
Inc(ps);
}
ps->base[ps->top] = val;
ps->top++;
return true;
}
ps->base[ps->top] = val;
:将新元素val
插入到栈顶位置。ps->top
表示栈顶指针,ps->base[ps->top]
表示栈顶位置的内存地址。这里将新元素val
存储到栈顶位置。
ps->top++;
:将栈顶指针ps->top
加1,表示栈中元素的数量增加了一个。
2.7 删除 出栈
bool Pop(Seq_Stack* ps)
{
assert(ps != NULL);
if (ps == NULL)
return false;
if (Is_Empty(ps))
return false;
ps->top--;
return true;
}
2.8 获取栈顶元素
ELEM_TYPE Top(Seq_Stack* ps)
{
assert(ps != NULL);
if (ps == NULL)
exit(1);
if (Is_Empty(ps))
exit(1);
return ps->base[ps->top - 1];
return true;
}
ps->base[ps->top - 1]
:栈顶元素的索引是ps->top - 1
,因为ps->top
表示栈中元素的数量,而数组索引是从0开始的。因此,ps->base[ps->top - 1]
表示栈顶元素的值。
2.9 获取有效值长度
//5.获取有效值长度 Size
int Get_length(Seq_Stack* ps)
{
assert(ps != NULL);
if (ps == NULL)
return -1;
return ps->top;
}
2.10 清空
//6.清空 不需要free
void Clear(Seq_Stack* ps)
{
assert(ps != NULL);
if (ps == NULL)
return;
ps->top = 0;
}
2.11 销毁
//7.销毁 需要free
void Destroy(Seq_Stack* ps)
{
assert(ps != NULL);
if (ps == NULL)
return;
free(ps->base);
ps->base = NULL;
ps->top = ps->stacksize = 0;
}
Destroy
函数的作用是销毁一个顺序栈,并释放它所占用的动态内存。
调用
free(ps->base)
会释放ps->base
指向的内存空间。释放内存后,这块内存就不再属于程序了,程序不能再使用它。
2.12 打印
//8.打印
void Show(Seq_Stack* ps)
{
//assert
for (int i = 0; i < ps->top; i++)
{
printf("%c ", ps->base[i]);
}
printf("\n");
}
ps->base
:这是栈底指针,指向栈的起始内存地址。
ps->base[i]
:表示栈中第i
个元素的值。数组名本质上是一个指向数组首元素的指针。eg:arr
和&arr[0]
是等价的,都表示数组的起始地址。
2.13 测试
//顺序栈测试用例
int main()
{
/*srand((unsigned int)time(NULL));
int tmp = rand() % 29 + 1;
printf("%d\n", tmp);*/
Seq_Stack head;
Init_Seq_Stack(&head);
Push(&head, 'A');
Push(&head, 'B');
Push(&head, 'C');
Show(&head);//A B C
printf("%c\n", Top(&head));//C
Pop(&head);//A B
Show(&head);//A B
return 0;
}