链栈的优点:便于多个栈共享存储空间和提高效率,且 不存在栈满上溢的现象
链栈——带头结点
整体思路:
构建和单链表类似,进栈采用头插法,出栈也是删除首元结点,遍历是一个难点,详细见下图
入栈
-
图解
由于链栈栈的空间小,不需要考虑栈满的情况。入栈可以理解为带头结点的单链表的头插法。
-
代码
bool Push(LiStack &S,ElemType e){ Node *p=(LiStack) malloc(sizeof(Node)); p->data=e; p->next=S->next;//头插法 S->next=p; return true; }
出栈
-
图解
出栈对应的是删除首元结点
-
代码
bool Pop(LiStack &S,ElemType &e){ if (S->next==NULL)return false; Node *p=S->next; e=p->data; S->next=p->next; free(p); return true; }
遍历
下面完整代码是从栈顶到栈底
若是想要从栈底到栈顶可以使用下面的代码:
/*递归*/
void show(LiStack S){
if (S->next!=NULL)
show(S->next);
if (S!=NULL)
printf("%d ",S->data);
}
/*遍历*/
void Proint(LiStack S){
if(S->next!=NULL)
show(S->next);
else
printf("当前栈中没有元素");
printf("\n");
}
完整代码
/*
*Function:链式栈——带头结点
*/
#include "stdio.h"
#include "stdlib.h"
typedef int ElemType;
typedef struct LinkNode{
ElemType data;
LinkNode *next;
}Node,*LiStack;
/*初始化栈*/
void InitStack(LiStack &S){
S=(LiStack) malloc(sizeof(Node));
S->next=NULL;
}
/*判断空栈*/
bool StackEmpty(LiStack S){
if (S->next==NULL)return true;
else return false;
}
/*
* 进栈
* 不需要考虑栈溢出
*/
bool Push(LiStack &S,ElemType e){
Node *p=(LiStack) malloc(sizeof(Node));
p->data=e;
p->next=S->next;//头插法
S->next=p;
return true;
}
/*
* 出栈
* 进栈的时候是头插,出栈就相当于删除首元结点
*/
bool Pop(LiStack &S,ElemType &e){
if (S->next==NULL)return false;
Node *p=S->next;
e=p->data;
S->next=p->next;
free(p);
return true;
}
/*取栈顶元素*/
bool GetTop(LiStack S,ElemType &e){
if (S->next==NULL)return false;
e=S->next->data;
return true;
}
/*销栈*/
void DestoryStack(LiStack &S){
ElemType e;
while(S->next!=NULL) {
Pop(S,e);
}
free(S);
}
/*遍历*/
void Proint(LiStack S){
if (StackEmpty(S)){
printf("当前栈中没有元素\n");
return;
}
LinkNode *p=S->next;
while(p!=NULL){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
int main(){
LiStack S;
printf("***************************************\n");
printf("******** 1.初始化栈 2.空栈判断 ********\n");
printf("******** 3. 进 栈 4. 出 栈 ********\n");
printf("******** 5.读取栈顶 6. 销 栈 ********\n");
printf("******** 7. 遍 历 0. 退 出 ********\n");
printf("***************************************\n");
bool flag= true;
int x;
ElemType e;
while(flag) {
printf("请输入命令:");
scanf("%d", &x);
switch (x) {
case 1:
InitStack(S);
printf("\t空栈初始化完成\n");
break;
case 2:
if (StackEmpty(S)) printf("\t该栈是空栈\n");
else printf("\t该栈不是空栈\n");
break;
case 3:
printf("\t请输入要进栈的元素:");
int a;
scanf("%d", &a);
if (Push(S, a))printf("\t元素进栈成功\n");
else printf("\t元素进栈失败\n");
break;
case 4:
if (Pop(S, e))
printf("\t元素出栈成功,出栈的元素为:%d\n", e);
else
printf("\t元素进栈失败\n");
break;
case 5:
if (GetTop(S, e))
printf("\t栈顶元素为:%d\n", e);
else
printf("\t该栈为空栈\n");
break;
case 6:
DestoryStack(S);
printf("\t销毁成功\n");
break;
case 7:
printf("\t当前栈中元素:");
Proint(S);
break;
case 0:
printf("退出成功\n");
flag = false;
break;
default:
printf("命令错误,请重新输入!!!");
break;
}
}
}
运行结果
链栈——不带头结点
完整代码
#include "stdio.h"
#include "stdlib.h"
typedef int ElemType;
typedef struct LinkNode{
ElemType data;
LinkNode *next;
}Node,*LiStack;
/*初始化栈*/
void InitStack(LiStack &S){
S=NULL;
}
/*判断空栈*/
bool StackEmpty(LiStack S){
if (S==NULL)return true;
else return false;
}
/*
* 进栈
* 不需要考虑栈溢出
*/
bool Push(LiStack &S,ElemType e){
Node *p=(LiStack) malloc(sizeof(Node));
p->data=e;
p->next=S;//头插法
S=p;
return true;
}
/*
* 出栈
* 进栈的时候是头插,出栈就相当于删除首元结点
*/
bool Pop(LiStack &S,ElemType &e){
if (S==NULL)return false;
Node *p=S;
e=p->data;
S=p->next;
free(p);
return true;
}
/*取栈顶元素*/
bool GetTop(LiStack S,ElemType &e){
if (S==NULL)return false;
e=S->data;
return true;
}
/*销栈*/
void DestoryStack(LiStack &S){
ElemType e;
while(S!=NULL) {
Pop(S,e);
}
free(S);
}
/*遍历*/
void Proint(LiStack S){
if (StackEmpty(S)){
printf("当前栈中没有元素\n");
return;
}
LinkNode *p=S;
while(p!=NULL){
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
int main(){
LiStack S;
printf("***************************************\n");
printf("******** 1.初始化栈 2.空栈判断 ********\n");
printf("******** 3. 进 栈 4. 出 栈 ********\n");
printf("******** 5.读取栈顶 6. 销 栈 ********\n");
printf("******** 7. 遍 历 0. 退 出 ********\n");
printf("***************************************\n");
bool flag= true;
int x;
ElemType e;
while(flag) {
printf("请输入命令:");
scanf("%d", &x);
switch (x) {
case 1:
InitStack(S);
printf("\t空栈初始化完成\n");
break;
case 2:
if (StackEmpty(S)) printf("\t该栈是空栈\n");
else printf("\t该栈不是空栈\n");
break;
case 3:
printf("\t请输入要进栈的元素:");
int a;
scanf("%d", &a);
if (Push(S, a))printf("\t元素进栈成功\n");
else printf("\t元素进栈失败\n");
break;
case 4:
if (Pop(S, e))
printf("\t元素出栈成功,出栈的元素为:%d\n", e);
else
printf("\t元素进栈失败\n");
break;
case 5:
if (GetTop(S, e))
printf("\t栈顶元素为:%d\n", e);
else
printf("\t该栈为空栈\n");
break;
case 6:
DestoryStack(S);
printf("\t销毁成功\n");
break;
case 7:
printf("\t当前栈中元素:");
Proint(S);
break;
case 0:
printf("退出成功\n");
flag = false;
break;
default:
printf("命令错误,请重新输入!!!");
break;
}
}
}
运行结果
参考资料
《王道:数据结构考研复习指导》