一、栈的链式存储结构
如果一个栈存在频繁进栈和出栈操作,可以考虑链式结构。
栈的链式存储结构是指使用链表来实现栈这种数据结构。在链式存储结构中,栈的每个元素被封装成一个节点,节点之间通过指针相连,形成一个链表。栈顶元素对应链表的头部,栈底元素对应链表的尾部。这种结构可以动态地分配和管理存储空间,适合于需要频繁插入和删除操作的场景。
二、栈的基本操作(链表)
1、链栈的结构
typedef char SElemType;/*栈元素结构体*/
typedef struct StackNode{SElemType data;struct StackNode *next;
}StackNode,*StackLinkList;/*链栈结构体*/
typedef struct {StackLinkList top;SElemType count;
}StackLink;
2、创建空栈
/*创建一个空栈*/
int StackInit(StackLink *S){if(!S->top){return ERROR;}S->top = (StackLinkList)malloc(sizeof(StackLinkList));S->top = NULL;S->count = 0;return OK;
}
3、插入栈顶元素
/*插入元素e为新的栈顶元素*/
int StackPush(StackLink *S,SElemType e){StackLinkList p = (StackLinkList)malloc(sizeof(StackLinkList));p->data = e;p->next = S->top;/* 把当前的栈顶元素赋值给新结点的直接后继*/S->top = p;/* 将新的结点s赋值给栈顶指针*/S->count++;return OK;
}
4、 删除栈顶元素
/*若栈不空,则删除S的栈顶元素*/
/*将栈顶结点赋值给 p使得栈顶指针下移一位,指向后一结点释放结点p*/
int StackPop(StackLink *S){if(StackEmpy(S)){return ERROR;}SElemType e = S->top->data;StackLinkList q;q = S->top;S->top = S->top->next;free(q);S->count--;return e;
}
5、清空栈元素
/*清空所有的栈元素*/
void clearStack(StackLink *S){if(!S->top){return;}StackLinkList q;while (S->count != 0){q = S->top;S->top = S->top->next;free(q);S->count--;}
}
6、打印所有栈元素
1)按出栈顺序打印
/*打印所有的栈元素*/
void printStack(StackLink *S,char *arr,int *size){if(!S->top){return;}int i = 0;StackLinkList ptr;ptr = S->top;while (ptr != NULL){// printf("%c",ptr->data);arr[i++] = ptr->data;ptr = ptr->next;} // printf("\n");*size = i;
}
2)按入栈顺序打印
核心思想是采用递归的栈底开始向栈顶打印元素。
/*打印所有的栈元素逆序*/
void printResverStack(StackLinkList S){if(S == NULL){return;}printResverStack(S->next);printf("%c",S->data);
}
三、栈案例分析
案例:输入一串字符串,并判断该字符串是否为对称串。
代码思路:将字符串输入到栈中,并存储出栈元素到数组中,并将数组中的元素倒序输入到另一个数组中,判断两个数组元素是否一致。
代码示例:
#include "LinkStack.h"int main()
{StackLink Slist;SElemType arr[50];SElemType arr1[50];printf("本程序判断字符串是否为对称串\n");char ch;int size = 0;int j = 0;int i = 0;while (1){StackInit(&Slist);ch = '\0'; arr[50] = '\0';arr1[50] = '\0';j = 0;printf("请输入字符串(输入q或者Q结束):");while(1){ch = getchar();if(ch == '\n'||ch == 'q'||ch == 'Q'){break;}StackPush(&Slist,ch);}if(ch == 'q'||ch == 'Q'){break;}printStack(&Slist,arr1,&size);for(int i = 0;i < size;i++){arr[size-i-1] = arr1[i];}for(int i = 0;i < size;i++){if(arr1[i] != arr[i]){j = 1;break;}}if(j == 0){printf("是对称串\n");}else{printf("不是对称串\n");}}clearStack(&Slist);printf("程序结束,再见!\n");return 0;
}
运行结果:
四、链栈的适用情况
对比一下顺序栈与链栈,它们在时间复杂度上是一样的,均为O(1)。对于空间性能,顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的 优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样,如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。