一、链栈的优点:
1、采用链栈不必预先估计栈的最大容量;
2、避免内存溢出。由于链栈的内存分配是按需进行的,因此只要系统有可用空间,就不会出现栈满导致溢出的情况。
3、空间利用率高。链栈可以根据实际情况动态调整栈的大小,避免了顺序栈可能出现的内存溢出等问题,提高了空间利用率。
4、操作方便。链栈的入栈和出栈操作都是在栈顶进行,操作方便
二、链栈的缺点:
1、链栈相对于顺序栈在内存空间上会额外消耗指针变量的存储空间,因为链栈需要额外的指针来维护节点之间的关系。
2、链栈在访问和操作元素时需要进行指针的频繁跳转,可能会导致性能上的损失,因此在实际应用中,对于需要高效率的场景可能不太适用。
3、对于小规模数据,链栈的额外指针开销可能会使得空间利用率不如顺序栈
但是链栈有缺点也有优点,综合实际情况进行选择使用链栈还是顺序栈。
三、定义结构体:
1、定义结点的结构体:分为数据域和指向下一个结点的指针
//定义栈中元素的结构
typedef struct StackNode{
SElemType data;
struct StackNode *next;
}StackNode ;
2、定义栈顶结构体
//定义栈结构 栈顶
typedef struct {
StackNode *top;
}StackLink;
四、链栈的操作:
1、初始化操作:
首先进行申请内存空间,然后进行判断其是否分配内存空间成功(判断条件为!S->top),若分配成功,将栈置为空栈。
//初始化栈,无头结点
bool ChuShiHua_1(StackLink *S){
S->top = (StackNode*)malloc(sizeof(StackNode));
if (!S->top) {
return false ; //分配内存地址失败
}
S->top = NULL;
return true ;
}
2、入栈操作--非单一入栈:
入栈思想:将S新结点申请内存空间,并且将入栈元素放到新结点的数据域,接着将当前的栈顶元素赋值给新结点的直接后续,然后再将新结点改为栈顶元素(即是新结点变为新的栈顶元素)
//入栈操作-建栈
bool RuZhan_1(StackLink *S){
StackNode *s; //用于申请新结点的
SElemType e ; //存放元素数据缓存区
int fale = 1; //循环标志
printf("\n\t\t请输入数据并换行(以’0'为停止录入数据标志)\n");
while (fale) {
printf("\n\t\t请输入数据并换行:");
scanf("%d",&e);
if (e!=0) {
s = (StackNode *)malloc(sizeof(StackNode)); //申请新结点
s->data = e;
s->next = S->top; //把当前的栈顶元素赋值给新结点的直接后续
S->top = s; //把新结点赋值为栈顶元素
}else{
fale = 0;
}
}
return true ;
}
3、入栈操作--单一入栈:
入栈思想:同上面入栈思想一样,但是其入栈的规模不一样
//进栈操作-单一进栈
bool RuZhan_2(StackLink *S,SElemType e){
StackNode *s;
s = (StackNode *)malloc(sizeof(StackNode)); //申请内存空间
s->data = e ; //赋值
s->next = S->top ; //将新结点的直接后续赋值为栈顶
S->top = s; //将栈顶改为新的结点位置
return true ;
}
4、出栈操作:
思想:首先判断其栈是否为空栈,若为空栈无法进行出栈操作;再然后定义一个工作指针,接着将栈顶的位置赋值给工作指针,再将栈顶元素数据域带回,接着将栈顶所指位置下移,最后释放工作指针的内存空间:
bool ChuZhan_1(StackLink *S,SElemType *e){
StackNode *p; //工作指针
if (S->top==NULL) {
printf("\n\t\t此栈为空\n");
return false ;
}
p = S->top ;
*e = p->data; //将要出栈的元素进行带回
S->top = p->next; //将栈顶下移
free(p); //释放栈顶的内存空间
return true ;
}
5、显示操作:
思想:首先判断其栈是否为空,若为空则输出此栈为空栈,否则将栈中元素输出,从栈顶依次输出,而循环的停止条件为工作指针不为空(NULL)
bool XianShi_1(StackLink *S){
StackNode *p ; //工作指针:用来进行遍历
p = S->top; //将栈顶元素赋值给工作指针
if (p==NULL) {
printf("\n\t\t此栈为空栈");
printf("\n");
return false ;
}
while (p!=NULL) {
printf("%3d",p->data);
p = p->next ;
}
printf("\n");
return true ;
}
6、将栈置空操作:
思想:首先定义工作指针,接着判断此栈是否为空,若为空无须进行置空处理。若不为空,循环条件为:此栈不为空。将栈顶元素赋值给工作指针,再将栈顶元素下移,接着释放其工作指针的内存,接着进行此循环;
//将栈置为空栈
bool KongZhan_1(StackLink *S){
StackNode *p; //工作指针:用于将栈中元素删除
if (S->top==NULL) {
printf("\n\t\t此栈为空栈\n");
return false ;
}
while (S->top!=NULL) {
p = S->top;
S->top = p->next;
free(p);
}
printf("\n\t\t将栈置为空:成功\n");
return true ;
}
7、数制转至操作:
//数制转换--十进制转二进制
//除二取余,逆序输出
bool ZhuanHuan_1(StackLink *S,int x){
int Y; //用来记录余数
int C = x; //用来记录x/2
if (S->top!=NULL) {
printf("\n\t\t请将此栈置为空栈,再进行转换\n");
return false ;
}
while (C!=0) {
Y = C%2; //取余数
RuZhan_2(S,Y); //入栈是为了将其逆序输出
C = C/2; //换掉被除数
}
printf("\n\t\t此十进制数%d转换为二画进制数为:",x);
XianShi_1(S);
printf("\n");
return true ;
}