描述:
链栈,即栈的链式存储结构,链栈通常使用不带头结点的单链表来表示,因此其结点的结构和单链表的结点结构相同。
在一个链栈中,栈底就是链表的最后一个结点,而栈顶总是链表的第一个结点。因此,新入栈的元素即为链表中采用头插法新加入的结点,一个链栈可以由栈顶指针唯一确定,当top为NULL时,则表示该栈是一个空的链栈。
实现:
链栈结点的类型描述:
typedef int ElemType; typedef struct node{ ElemType data; struct node *next; }LinkNode,*LinkStack;
基本操作
1. 初始化链栈Init_LinkStack()
链栈的初始化操作就是创建一个不带头结点的空的单链表,如下:
//初始化链栈 LinkStack Init_LinkStack(){ LinkStack S; S = NULL; return S; }
2. 判断链栈空IsEmpty_LinkStack(LinkStack top)
根据定义,当栈顶指针top为NULL时,表示该结点为一个空栈,返回1,否则,则返回0 。
//判断链栈空 int IsEmpty_LinkStack(LinkStack top){ if(top == NULL) return 1; else return 0; }
3. 入链栈Push_SqStack(SqStack* S,ElemType x)
入栈,即向栈中插入一个元素作为新的栈顶元素,首先要动态申请一个结点作为新元素的存储空间,然后将新数据元素写入申请的存储空间中,并将栈顶指针top的值写入新结点中的指针域,最后将栈顶指针指向新插入的结点,代码如下:
//入栈操作 void Push_SqStack(SqStack* S,ElemType x){ //栈满,则退出 if(isFull_SqStack(S)){ printf("栈满!\n"); exit(0); } else{ S->data[++(S->top)] = x; } }
4. 出链栈Pop_SqStack(SqStack* S,ElemType* x)
出栈,即从栈中输出一个元素,并将其删除,具体过程为:当栈顶元素出栈时,先判断栈顶指针是否为空,如果空,则输出提示信息并退出,否则,取出栈顶元素的值返回,然后,将栈顶指针向后移动,并且释放掉被删除栈顶元素的存储空间。
//出栈 void Pop_SqStack(SqStack* S,ElemType* x){ //如果栈空,则输出提示信息,并退出 if(isEmpty_SqStack(S)){ printf("栈空!\n"); exit(0); } else *x = S->data[S->top--]; }
5. 读取链栈顶元素Top_SqStack(SqStack* S,ElemType* x)
读取链栈顶元素与出栈不同,二者的区别在于:读取栈顶元素时,栈顶指针不发生变化,仅取得栈顶元素的值;而出栈则还要将栈顶元素删除,在此时栈顶指针也要发生变化;但二者都要判断栈是否为空。
//读取栈顶元素 void Top_SqStack(SqStack* S,ElemType* x){ if(isEmpty_SqStack(S)){ printf("栈空!\n"); exit(0); } else *x = S->data[S->top]; }
6. 输出栈中所有的元素Print_SqStack(SqStack* S)
从栈顶开始遍历整个链栈,输出所有的元素,同样,需要判断链栈是否为空。
//输出整个栈 void Print_SqStack(SqStack* S){ if(isEmpty_SqStack(S)){ printf("栈空!\n"); exit(0); } int length = S->top; while(length > -1) printf("%d\t",S->data[length--]); printf("\n"); }
说明:
以上只是链栈最基本的操作,当然了,在实际应用中,往往不仅涉及入栈和出栈等操作,而且还需要对非栈顶的元素进行访问。
顺序栈和链栈的比较:
1. 顺序栈易于根据栈顶指针的位置进行相对位移,快速定位并读取栈的内部元素,因此,顺序栈比链栈应用更广泛。
2. 顺序栈读取内部元素的时间复杂度为O(1),链栈读取内部元素的时间复杂度为O(n),其中,n为链栈的长度。