链式栈,顾名思义,就是规定一个只能头插头删或者尾插尾删的链表,来实现栈结构先进先出原则
在这里我们选用头插和头删的方法,因为尾插和尾删都需要遍历链表,时间复杂度较高。
不多比比,直接通过代码演示
- 结构体声明
typedef char LinkListType;
typedef struct LinkListStack{
struct LinkListStack* next;//指针域,指向下一个节点的指针
LinkListType data;//数据域,用来存放数据
}LinkListStack;
- 具体函数声明
//初始化栈
void LinkListStackInit(LinkListStack** head);
//入栈
void LinkListStackPush(LinkListStack** head,LinkListType value);
//出栈
void LinkListStackPop(LinkListStack** head);
//销毁栈
void DestroyNode(LinkListStack* node);
//创建新节点
LinkListStack* CreateNode(LinkListType value);
//取栈顶元素
int LinkListStackGetTop(LinkListStack* head,LinkListType* value);
初始化和销毁
void LinkListStackInit(LinkListStack** head)
{
if(head==NULL){
//非法输入
return;
}
*head=NULL;
}
//封装free函数,实现单个节点的销毁,如果想一次性销毁整个栈,需要遍历链表,依次释放每个节点空间才可以
void DestroyNode(LinkListStack* node)
{
free(node);
}
入栈和出栈
//因为链表中的节点都是一块独立的内存空间,所以在进行创建栈或者插入操作时,就需要开辟新的内存空间
//并分配给每个节点,因为堆上开辟的空间是不连续的,所以节点与节点之间需要一个next指针来连接起来
LinkListStack* CreateNode(LinkListType value)
{
LinkListStack* newNode = (LinkListStack*)malloc(sizeof(LinkListStack));
newNode->next = NULL;
newNode->data = value;
return newNode;
}
//入栈
//头插时间复杂度为O(1),推荐
void LinkListStackPush(LinkListStack** head,LinkListType value)
{
if(head == NULL)
{
//非法输入
return;
}
if(*head==NULL)
{
//空栈
*head = CreateNode(value);
return;
}
LinkListStack* cur = CreateNode(value);
cur->next = *head;
*head = cur;
}
//出栈
//头删时间复杂度为O(1),推荐
void LinkListStackPop(LinkListStack** head)
{
if(head==NULL)
{
//非法输入
return;
}
if(*head==NULL)
{
//空栈
return;
}
LinkListStack* cur = *head;
*head=(*head)->next;
DestroyNode(cur);
}
取出栈顶元素同样是需要输出型参数
int LinkListStackGetTop(LinkListStack* head,LinkListType* value)
{
if(head==NULL){
//空链表
return 0;
}
*value = head->data;
return 1;
}