首先需要明确,和普通单链表不同的是,链栈不需要头指针,或者说它的头指针不叫作头指针,而是栈顶元素,想想如果我们将链表的头指针指向链的第一个节点,并将链头作为栈顶,那么链表的头指针就是我们需要的指向栈顶的指针,显然链栈的各种操作只需要依靠这个栈顶指针就能实现。
链表的结构定义:
先是需要定义一个链栈的节点,这个节点必须包含一个数据和一个指向下一个节点的指针,
其次是需要一个结构来记录链栈的节点信息,包括栈顶指针和链栈的元素个数。
typedef int ElemType;
typedef struct { /*链栈的节点*/
ElemType data;
LinkStackPtr next;
}StackNode, *LinkStackPtr;
typedef struct{ /*链栈的基本信息*/
LinkStackPtr top;
int count;
}LinkStack;
链栈的创建操作:
我们需要创建一个结构来记录链栈的信息,由于是第一次创建,所以链栈节点指向的信息是头节点为空,链栈中元素的数目为空。
LinkStack* creatStack(){
/*这个函数用来创建链栈*/
LinkStack* p;
p = (LinkStack*)malloc(sizeof(LinkStack));
p->top = NULL;
p->count = 0;
return p;
}
链栈的入栈操作:
bool pullStack(LinkStack *k, ElemType e){
/*这个函数用来将元素压入栈中*/
LinkStackPtr p;
p = (LinkStackPtr)malloc(sizeof(StackNode));
if(!p){
printf("空间创建失败!!");
return false;
}
p->data = e;
p->next = k->top;
k->top = p;
k->count++;
return true;
}
链栈的出栈操作:
ElemType PopStack(LinkStack *k){
/*这个函数用来弹出栈顶元素*/
if(count == 0){
printf("该栈是一个空栈,没有元素可以弹出!!");
}
ElemType pop_point = k->top->data;
LinkStackPtr p = k->top;
k->top = p->next;
k->count--;
free(p);
return pop_point;
}
链栈和顺序栈的时间复杂度都为O(1),但是由于链栈需要一个指向下一个节点的指针域所以额外占的空间会大一些,但同时它也由栈的长度不限的优点。综合起来,如果所栈元素的数目会在使用过程中发生较大的改变,我们一般使用链栈,而倘如我们栈的元素数目是固定不变的,则最好采用顺序栈的方式来存储。