数据结构–栈
什么是栈?
首先先给大家讲一下栈是什么: 栈是一种特殊的线性表。特殊之处就在于对栈的操作的特殊。对于栈,只允许其在固定的一端进行插入和删除元素操作。不像普通的顺序表,链表,可以在任意位置进行删除插入元素的操作。 那么“进行数据插入和删除操作的一端”就被称作为栈顶,另一端被称为栈底。栈中的元素遵守着后进先出,或者说先进后出的原则。(因为只允许在一端进行插入删除,假设栈中已经存有元素,那么我要取出第一个存进去的元素,就要先把后面的元素一个个拿出来,才能把第一个存进去的元素取出来) 压栈:栈的插入操作叫做进栈、压栈、入栈(不同的叫法)。插入数据都在栈顶 出栈:栈的删除操作叫做出栈。删除数据,取出数据,也在栈顶。
栈的实现
栈的实现有两种实现方式,一种就是和顺序表类似,用数组实现,另一种则是通过单链表来实现栈。
实现代码
# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
# include <stdbool.h>
typedef int SKDataType;
typedef struct Stack
{
SKDataType * a;
int top;
int capacity;
} SK;
void SKInit ( SK* ps) ;
void SKDestroy ( SK* ps) ;
void SKPush ( SK* ps, SKDataType x) ;
void SKPop ( SK* ps) ;
SKDataType SKTop ( SK* ps) ;
int SKSize ( SK* ps) ;
bool SKEmpty ( SK* ps) ;
# include "stack.h"
void SKInit ( SK* ps)
{
assert ( ps) ;
ps-> a= NULL ;
ps-> capacity= 0 ;
ps-> top= 0 ;
}
void SKDestroy ( SK* ps)
{
assert ( ps) ;
free ( ps-> a) ;
ps-> a= NULL ;
ps-> top= ps-> capacity= 0 ;
}
void SKPush ( SK* ps, SKDataType x)
{
assert ( ps) ;
if ( ps-> top== ps-> capacity)
{
int newCapacity= ps-> capacity== 0 ? 4 : ps-> capacity* 2 ;
SKDataType * tmp= ( SKDataType* ) realloc ( ps-> a, sizeof ( SKDataType) * newCapacity) ;
if ( tmp== NULL )
{
perror ( "realloc failed" ) ;
exit ( - 1 ) ;
}
ps-> a= tmp;
ps-> capacity= newCapacity;
}
ps-> a[ ps-> top] = x;
ps-> top++ ;
}
void SKPop ( SK* ps)
{
assert ( ps) ;
assert ( ps-> top> 0 ) ;
ps-> top-- ;
}
SKDataType SKTop ( SK* ps)
{
assert ( ps) ;
assert ( ps-> top> 0 ) ;
return ps-> a[ ps-> top- 1 ] ;
}
int SKSize ( SK* ps)
{
assert ( ps) ;
return ps-> top;
}
bool SKEmpty ( SK* ps)
{
assert ( ps) ;
return ps-> top== 0 ;
}
# include "stack.h"
void TestStack1 ( )
{
SK st;
SKInit ( & st) ;
SKPush ( & st, 1 ) ;
SKPush ( & st, 2 ) ;
SKPush ( & st, 3 ) ;
SKPush ( & st, 4 ) ;
SKPush ( & st, 5 ) ;
while ( ! SKEmpty ( & st) )
{
printf ( "%d " , SKTop ( & st) ) ;
SKPop ( & st) ;
}
printf ( "\n" ) ;
SKDestroy ( & st) ;
}
int main ( )
{
TestStack1 ( ) ;
return 0 ;
}
函数讲解
栈的结构
typedef int SKDataType;
typedef struct Stack
{
SKDataType * a;
int top;
int capacity;
} SK;
初始化栈
void SKInit ( SK* ps)
{
assert ( ps) ;
ps-> a= NULL ;
ps-> capacity= 0 ;
ps-> top= 0 ;
}
销毁栈
void SKDestroy ( SK* ps)
{
assert ( ps) ;
free ( ps-> a) ;
ps-> a= NULL ;
ps-> top= ps-> capacity= 0 ;
}
销毁栈就没什么好说的了,就是把结构体(工具包)里面的本体(数组/栈)给free掉(将动态开辟的空间返还给系统),指针置空,其他值也置为零。
压栈
void SKPush ( SK* ps, SKDataType x)
{
assert ( ps) ;
if ( ps-> top== ps-> capacity)
{
int newCapacity= ps-> capacity== 0 ? 4 : ps-> capacity* 2 ;
SKDataType * tmp= ( SKDataType* ) realloc ( ps-> a, sizeof ( SKDataType) * newCapacity) ;
if ( tmp== NULL )
{
perror ( "realloc failed" ) ;
exit ( - 1 ) ;
}
ps-> a= tmp;
ps-> capacity= newCapacity;
}
ps-> a[ ps-> top] = x;
ps-> top++ ;
}
如果这部分的解析还是不清楚的话可以先往下看,看完就明白了。
出栈
void SKPop ( SK* ps)
{
assert ( ps) ;
assert ( ps-> top> 0 ) ;
ps-> top-- ;
}
出栈也很简单,我们不需要对栈内元素做什么,我们直接更改下标就好了。让top–,因为我初始化top=0嘛。所以top就是栈顶元素的下一个元素的下标,也就是栈顶元素下标+1,top–之后,原本的栈顶就变成了新栈顶的下一个元素。后续插入数据也不会影响,会被直接覆盖。
获取现在栈顶元素的值
SKDataType SKTop ( SK* ps)
{
assert ( ps) ;
assert ( ps-> top> 0 ) ;
return ps-> a[ ps-> top- 1 ] ;
}
这个也没什么好说的,top就是栈顶元素的下标+1,想要获得栈顶元素,top-1就可以了。
栈的大小(栈中含有的有效元素个数)
int SKSize ( SK* ps)
{
assert ( ps) ;
return ps-> top;
}
因为我初始化top=0,每次插入元素,top就+1,所以top的大小也是有效元素的大小。
判断栈是否为空
bool SKEmpty ( SK* ps)
{
assert ( ps) ;
return ps-> top== 0 ;
}
因为我初始化top=0,这个就标志了栈是没有元素的。和上面计算栈的大小差不多,每次插入元素top+1,所以就可以直接用top==0来判断了。返回的是bool类型,记得带上stdbool.h头文件。
测试函数说明
# include "stack.h"
void TestStack1 ( )
{
SK st;
SKInit ( & st) ;
SKPush ( & st, 1 ) ;
SKPush ( & st, 2 ) ;
SKPush ( & st, 3 ) ;
SKPush ( & st, 4 ) ;
SKPush ( & st, 5 ) ;
while ( ! SKEmpty ( & st) )
{
printf ( "%d " , SKTop ( & st) ) ;
SKPop ( & st) ;
}
printf ( "\n" ) ;
SKDestroy ( & st) ;
}
int main ( )
{
TestStack1 ( ) ;
return 0 ;
}
那么栈的内容就大概讲完了。后面会给大家讲道题,帮助大家感受一下,栈的作用。