栈的链式存储结构,我们一般简称为“链栈”。由于单链表有头指针,而栈顶指针也是必须要有的,所以我们通常把栈顶放在单链表的头部,有了栈顶在头部,单链表中比较常用的头结点就失去了意义。通常对于链栈来说,是不需要头结点的,也基本不存在栈满的情况,除非内存已经没有使用的空间了。但对于空栈来说,链表原定义是头指针指向“空”,那么链栈的“空”其实就是“top=NULL”的时候。
链栈的进栈push和出栈pop操作都很简单,没有任何循环操作,时间复杂度均为O(1);顺序栈的时间复杂度和链栈是一样的,也为O(1)。对于空间性能,顺序栈需要事先确定一个固定的长度,可能存在内存空间浪费的问题,它的优势在于存取定位时很方便;而链栈要求每个元素都有指针域,这也增加了一些内存开销,但对于栈的长度无限制;所以如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好用链栈;反之,如果元素变化在可控范围内,建议使用顺序栈会更好一些。对于链栈的操作,绝大部分与单链表类似,只是在插入与删除上特殊一些罢了,下面我们来看看链栈的操作,具体操作源代码如下所示:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 #define OK 1 5 #define ERROR 0 6 #define TRUE 1 7 #define FALSE 0 8 9 #define MAXSIZE 100 /* 存储空间初始分配量 */ 10 11 typedef int Status; 12 typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */ 13 14 /* 链栈结构 */ 15 typedef struct StackNode 16 { 17 SElemType data; 18 struct StackNode *next; 19 }StackNode,*LinkStackPtr; 20 21 typedef struct 22 { 23 LinkStackPtr top; 24 int count; 25 }LinkStack; 26 27 Status visit(SElemType c) 28 { 29 printf("%d ",c); 30 return OK; 31 } 32 33 /* 构造一个空栈S */ 34 Status InitStack(LinkStack *S) 35 { 36 S->top = (LinkStackPtr)malloc(sizeof(StackNode)); 37 if(!S->top) 38 return ERROR; 39 S->top=NULL; 40 S->count=0; 41 42 return OK; 43 } 44 45 /* 把S置为空栈 */ 46 Status ClearStack(LinkStack *S) 47 { 48 LinkStackPtr p,q; 49 p=S->top; 50 while(p) 51 { 52 q=p; 53 p=p->next; 54 free(q); 55 } 56 S->count=0; 57 58 return OK; 59 } 60 61 /* 若栈S为空栈,则返回TRUE,否则返回FALSE */ 62 Status StackEmpty(LinkStack S) 63 { 64 if(S.count==0) 65 return TRUE; 66 else 67 return FALSE; 68 } 69 70 /* 返回S的元素个数,即栈的长度 */ 71 int StackLength(LinkStack S) 72 { 73 return S.count; 74 } 75 76 /* 插入元素e为新的栈顶元素 */ 77 Status Push(LinkStack *S,SElemType e) 78 { 79 LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode)); 80 s->data=e; 81 s->next=S->top; /* 把当前的栈顶元素赋值给新结点的直接后继 */ 82 S->top=s; /* 将新的结点s赋值给栈顶指针 */ 83 S->count++; 84 85 return OK; 86 } 87 88 /* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */ 89 Status Pop(LinkStack *S,SElemType *e) 90 { 91 LinkStackPtr p; 92 if(StackEmpty(*S)) 93 return ERROR; 94 *e=S->top->data; 95 p=S->top; /* 将栈顶结点赋值给p */ 96 S->top=S->top->next; /* 使得栈顶指针下移一位,指向后一结点 */ 97 free(p); /* 释放结点p */ 98 S->count--; 99 100 return OK; 101 } 102 103 /* 从栈顶到栈底依次对栈中每个元素输出 */ 104 Status StackTraverse(LinkStack S) 105 { 106 LinkStackPtr p; 107 p=S.top; 108 while(p) 109 { 110 visit(p->data); 111 p=p->next; 112 } 113 printf(" "); 114 115 return OK; 116 } 117 118 int main() 119 { 120 int j,e; 121 LinkStack s; 122 123 if(InitStack(&s)==OK) 124 for(j=1;j<=10;j++) 125 Push(&s,j); 126 printf("1.栈中元素依次为:"); 127 StackTraverse(s); 128 129 Pop(&s,&e); 130 printf("2.弹出的栈顶元素 e=%d ",e); 131 printf("3.弹出栈顶元素 e=%d 后,栈的长度为 %d ",e,StackLength(s)); 132 133 Pop(&s,&e); 134 printf("4.弹出的下一个栈顶元素 e=%d ",e); 135 printf("5.栈中元素依次为:"); 136 StackTraverse(s); 137 138 Push(&s,16); 139 printf("6.插入新栈顶元素 e=%d 后,栈的长度为 %d ",16,StackLength(s)); 140 printf("7.栈中元素依次为:"); 141 StackTraverse(s); 142 143 ClearStack(&s); 144 printf("8.清空栈后,栈的长度为 %d ",StackLength(s)); 145 146 return 0; 147 }