使用C语言实现链栈(带头结点和不带头结点)

目录

1.链栈

2.链栈的相关操作

(1)数据结构定义

(2)初始化和销毁

(3)入栈

(4)出栈

(5)主函数

(6)测试


1.链栈

链栈和单链表是差不多的,只是规定了入栈和出栈只能在表头一端进行(栈顶)。

注:链栈相比于顺序栈(动态)来说会比较方便的是不用担心插入节点是否出现空间满的问题,但是链栈中的节点之间不是连续的存储关系,逻辑上是连续的,但是在内存中的存储是分布散开的。

注:以上是带头结点的链栈。其实在实际中我们更多的时候是会关注的是栈的实际应用,而不是仅仅关注的是栈本身的简单实现,所以学会了栈的基本操作之后,学会将栈应用到实际中非常的重要,也是对自己的挑战。

使用C语言实现顺序栈

使用栈将十进制转换为八进制

使用栈判断括号是否匹配

使用栈判断回文字符串

使用C语言实现单链表(带头结点)

2.链栈的相关操作

(1)数据结构定义

#include<stdlib.h>
#include<stdio.h>

#define MAXSIZE 10

typedef int ElemType;

typedef struct Linknode {
	ElemType data;
	struct Linknode*next;
}*LiStack;

//菜单栏
void MenuSqStack(){
	printf("----------1.入栈元素--------\n");
	printf("----------2.获取栈顶元素----\n");
	printf("----------3.弹出栈顶元素----\n");
	printf("----------4.重新初始化------\n");
	printf("----------5.退出操作--------\n");
}

(2)初始化和销毁

首先是带头结点:

//初始化
void InitLiStack(LiStack&s){
	s=(Linknode*)malloc(sizeof(Linknode));
	if(s==NULL){
		printf("内存分配失败!\n");
		return ;
	}
	s->next=NULL;
	printf("空间申请成功!\n");
} 
//销毁
void DestryLiStack(LiStack&s){
	Linknode*p=s->next;
	while(p!=NULL){
		Linknode*r=p;
		p->next=r->next;
		free(r);
	}
	free(s);
	printf("销毁成功!\n");
} 

不带头结点:

//初始化
void InitLiStack(LiStack&s){
	s=NULL;
	printf("申请空间成功!\n"); 
} 
//销毁
void DestryLiStack(LiStack&s){
	Linknode*p=s;
	while(p->next!=NULL){
		Linknode*r=p;
		p=r->next;
		free(r);
	}
	//最后一个节点特殊处理
	free(p); 
	printf("销毁成功!\n");
} 

(3)入栈

带头结点:

//入栈
void PushLiStack(LiStack&s,ElemType e){
	Linknode*r=(Linknode*)malloc(sizeof(Linknode));
	r->data=e;
	r->next=s->next;
	s->next=r;
	printf("插入节点成功!\n"); 
} 

不带头结点:

相比于带头点的链栈来说相对较复杂,因为开始的时候s==NULL,所以首选需要将插入的第一个节点做特殊的处理。

//入栈
void PushLiStack(LiStack&s,ElemType e){
	//如果开始没有节点,特殊处理 
	if(s==NULL){
		Linknode*r=(Linknode*)malloc(sizeof(Linknode));
		r->data=e;
		r->next=NULL;
		s=r;
		printf("插入节点成功!\n"); 
		return ; 
	} 
	Linknode*r=(Linknode*)malloc(sizeof(Linknode));
	//首先将头结点的值修改为要插入的值e,将r->data=s->data,最后直接在头结点后面插入节点 r即可 
	r->data=s->data;
	s->data=e;
	r->next=s->next;
	s->next=r;
	printf("插入节点成功!\n"); 
} 

(4)出栈

带头结点:

//出栈
void PopLiStack(LiStack&s,ElemType&e){
	if(s->next==NULL){
		printf("栈空!\n");
		return;
	}
	Linknode*p=s->next;
	e=p->data;
	s->next=p->next;
	free(p);
	printf("出栈成功!\n"); 
} 

//获取栈顶节点
Linknode*GetElem(LiStack&s,ElemType&e){
	if(s->next==NULL){
		printf("栈空!\n");
		return NULL;
	}
	Linknode*p=s->next;
	e=p->data;
} 

不带头结点:

删除的操作其实不一定像我这样写,我只是做了一个最后一个节点的特殊处理。

//出栈
void PopLiStack(LiStack&s,ElemType&e){
	if(s==NULL){
		printf("栈空!\n");
		return;
	}
	//只有一个节点的时候特殊处理 
	if(s->next==NULL){
		e=s->data; 
		free(s);
		return ;
	} 
	Linknode*p=s;
	e=p->data;
	s->next=p->next;
	free(p);
	printf("出栈成功!\n"); 
} 

//获取栈顶节点
Linknode*GetElem(LiStack&s,ElemType&e){
	if(s==NULL){
		printf("栈空!\n");
		return NULL;
	}
	Linknode*p=s;
	e=p->data;
} 

(5)主函数

主函数对于带头结点和不带头结点都是一样的。

int main() {
	LiStack s;
	ElemType e;
	InitLiStack(s);
	while(1){
		int flag=0;
		bool popFlag=false;
		Linknode*p;
		MenuSqStack();
		printf("请输入操作: ");
		scanf("%d",&flag);
		switch(flag){
			case 1:
				printf("请输入元素(-1_end): ");
				scanf("%d",&e);
				while(e!=-1){
					PushLiStack(s,e);
					printf("请输入元素(-1_end): ");
					scanf("%d",&e);
				}
				break;
			case 2:
				p=GetElem(s,e);
				if(p!=NULL){
					printf("栈顶元素 = %d\n",e);
				}
				break;
			case 3:
				PopLiStack(s,e);
				printf("弹出栈顶元素 = %d\n",e);
				break;
			case 4:
                //首先要销毁之后再重新申请 
				DestryLiStack(s);
				InitLiStack(s);
				break;
			default:
				DestryLiStack(s);
				printf("结束操作\n");
		}
		if(flag==5){
			break;
		}
	}
	return 0;
}

(6)测试

首先是带头结点的测试;

不带头结点的测试:

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值