数据结构 栈【链栈的操作】

71 篇文章 12 订阅
4 篇文章 0 订阅

目录

一、链栈结点定义

二、链栈定义

三、栈的初始化

四、栈的插入操作——push

五、栈的判空

六、找到栈顶元素

七、栈的删除操作——pop

八、栈的销毁

九、测试

十、源码 


一、链栈结点定义

//结构体:定义栈的每一个结点
typedef struct Node
{
	//数据域
	int data;
	//指针域
	Node* next;
//重命名,将struct Node 重命名为Node
}Node;

二、链栈定义

//结构体:定义链栈
typedef struct Stack
{
	//链栈里只需要存放头结点就可以
	Node* head;
//重命名,将struct Stack 重命名为Stack
}Stack;

三、栈的初始化

//函数:栈的初始化
//定义了结构体,我们首先需要一个函数来初始化链栈
//主要用途就是分配空间
//返回值自然是一个栈指针Stack*,以便我们能找到这个初始化的栈
//传参为空,因为不需要任何参数,我们直接在函数里初始化
Stack* initialStack()
{
	//为栈分配空间
	Stack* s = (Stack*)malloc(sizeof(Stack));
	//初始化头结点,将头结点指向空
	Node* ret = (Node*)malloc(sizeof(Node));
	ret->next = NULL;
	s->head = ret;
	//返回栈指针
	return s;
}

四、栈的插入操作——push

//函数:栈的插入操作
//很明显需要用头插法
//因为头插法,头结点指向的始终是栈顶元素,
//找到栈顶元素的时间复杂度为O(1),与栈的大小无关
//如果用尾插法,就麻烦了,找到栈顶元素的时间复杂度为O(N)
//或者使用双向链表,但都很麻烦
//返回值:void,因为我们是对栈进行操作,不需要返回值
//参数:传入要操作的栈的指针即可
void push(Stack* s)
{
	//首先创建一个结点指针,并分配内存空间
	Node* cur = (Node*)malloc(sizeof(Node));
	//为其赋值
	int value;
	scanf("%d", &value);
	cur->data = value;
	//有了值还不够,因为指针域还未初始化
	//所以需要进行指针域的初始化
	//先让这个指针的next指向头结点的next
	cur->next = s->head->next;
	//再让头结点的next指向他
	s->head->next = cur;
	//这样就完成了
}

五、栈的判空

//函数:栈的判空
//判断一个栈是否为空,返回类型需要是一个布尔类型
//为空:true 非空:false
//传入的参数需要是一个具体的栈,且必须是指针,因为是链栈
bool isStackEmpty(Stack* s)
{
	//如果头结点的下一个结点,也就是栈顶元素指针,是NULL
	//说明此栈为空
	if (s->head->next == nullptr)
	{
		return true;
	}
	//如果栈顶元素指针非空,说明栈中至少存在一个元素
	//说明非空
	else
	{
		return false;
	}
}

六、找到栈顶元素

//函数:找到栈顶元素
//因为我们要找到栈顶元素
//所以返回值肯定是一个结点指针,也就是Node*类型
//传入的参数需要是一个具体的栈,且必须是指针,因为是链栈
Node* findTop(Stack* s)
{
	//首先进行判空
	//如果栈为空
	if (isStackEmpty(s))
	{
		//说明栈中没有任何一个元素,
		//自然也不存在栈顶元素,
		//直接返回NULL
		return nullptr;
	}
	//经过上面的步骤,肯定说明栈不为空
	//所以要开始找栈顶元素了
	//创造一个栈顶指针,并令其为栈顶元素
	Node* top = s->head->next;
	//返回栈顶元素指针即可
	return top;
}

七、栈的删除操作——pop

//函数:删除栈顶元素
//有了上述封装好的函数,我们就可以直接用了
void pop(Stack* s)
{
	//首先进行安全性检查:判空
	//如果栈为空,直接返回
	if (isStackEmpty(s))
	{
		return;
	}
	//找到栈顶元素
	Node* top = findTop(s);
	//删除栈顶元素
	s->head->next = top->next;
	//释放栈顶元素
	free(top);
	top = nullptr;
}

八、栈的销毁

//函数:销毁栈
//有始有终,防止内存泄露
void deleteStack(Stack* s)
{
	//不断进行pop操作,直到栈为空
	while (!isStackEmpty(s))
	{
		pop(s);
	}
	//此时,除了头结点,所有结点已经释放干净
	//接下来释放头结点
	free(s->head);
	s->head = nullptr;
	//最后释放栈指针空间,并避免悬空指针
	free(s);
	s = nullptr;
}

九、测试

//主函数里进行操作
int main()
{
	//创建一个栈
	printf("执行创建栈操作\n");
	Stack* myStack = initialStack();
	//检测判空操作
	printf("执行判空操作\n");
	if (isStackEmpty(myStack))
	{
		printf("栈为空!\n");
	}
	else
	{
		printf("栈非空!\n");
	}
	//检测push操作
	printf("执行push操作:\n");
	push(myStack);
	printf("执行push操作:\n");
	push(myStack);	
	printf("执行push操作:\n");
	push(myStack);
	//再次检测判空操作
	printf("执行判空操作\n");
	if (isStackEmpty(myStack))
	{
		printf("栈为空!\n");
	}
	else
	{
		printf("栈非空!\n");
	}
	//检测top操作
	Node* top = findTop(myStack);
	printf("执行top操作:\n");
	printf("栈顶元素为:");
	printf("%d\n",top->data);
	//检测pop操作
	printf("执行pop操作\n");
	pop(myStack);
	//检测top操作
	top = findTop(myStack);
	printf("执行top操作:\n");
	printf("栈顶元素为:\n");
	printf("%d", top->data);
	//检测deleteStack操作
	printf("执行销毁操作:\n");
	deleteStack(myStack);
	if (myStack == nullptr)
	{
		printf("栈已释放完毕!\n");
	}
	else
	{
		printf("栈未释放完毕!\n");
	}
	return 0;
}

十、源码 

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <iostream>

//结构体:定义栈的每一个结点
typedef struct Node
{
	//数据域
	int data;
	//指针域
	Node* next;
//重命名,将struct Node 重命名为Node
}Node;

//结构体:定义链栈
typedef struct Stack
{
	//链栈里只需要存放头结点就可以
	Node* head;
//重命名,将struct Stack 重命名为Stack
}Stack;

//函数:栈的初始化
//定义了结构体,我们首先需要一个函数来初始化链栈
//主要用途就是分配空间
//返回值自然是一个栈指针Stack*,以便我们能找到这个初始化的栈
//传参为空,因为不需要任何参数,我们直接在函数里初始化
Stack* initialStack()
{
	//为栈分配空间
	Stack* s = (Stack*)malloc(sizeof(Stack));
	//初始化头结点,将头结点指向空
	Node* ret = (Node*)malloc(sizeof(Node));
	ret->next = NULL;
	s->head = ret;
	//返回栈指针
	return s;
}

//函数:栈的插入操作
//很明显需要用头插法
//因为头插法,头结点指向的始终是栈顶元素,
//找到栈顶元素的时间复杂度为O(1),与栈的大小无关
//如果用尾插法,就麻烦了,找到栈顶元素的时间复杂度为O(N)
//或者使用双向链表,但都很麻烦
//返回值:void,因为我们是对栈进行操作,不需要返回值
//参数:传入要操作的栈的指针即可
void push(Stack* s)
{
	//首先创建一个结点指针,并分配内存空间
	Node* cur = (Node*)malloc(sizeof(Node));
	//为其赋值
	int value;
	scanf("%d", &value);
	cur->data = value;
	//有了值还不够,因为指针域还未初始化
	//所以需要进行指针域的初始化
	//先让这个指针的next指向头结点的next
	cur->next = s->head->next;
	//再让头结点的next指向他
	s->head->next = cur;
	//这样就完成了
}

//函数:栈的判空
//判断一个栈是否为空,返回类型需要是一个布尔类型
//为空:true 非空:false
//传入的参数需要是一个具体的栈,且必须是指针,因为是链栈
bool isStackEmpty(Stack* s)
{
	//如果头结点的下一个结点,也就是栈顶元素指针,是NULL
	//说明此栈为空
	if (s->head->next == nullptr)
	{
		return true;
	}
	//如果栈顶元素指针非空,说明栈中至少存在一个元素
	//说明非空
	else
	{
		return false;
	}
}

//函数:找到栈顶元素
//因为我们要找到栈顶元素
//所以返回值肯定是一个结点指针,也就是Node*类型
//传入的参数需要是一个具体的栈,且必须是指针,因为是链栈
Node* findTop(Stack* s)
{
	//首先进行判空
	//如果栈为空
	if (isStackEmpty(s))
	{
		//说明栈中没有任何一个元素,
		//自然也不存在栈顶元素,
		//直接返回NULL
		return nullptr;
	}
	//经过上面的步骤,肯定说明栈不为空
	//所以要开始找栈顶元素了
	//创造一个栈顶指针,并令其为栈顶元素
	Node* top = s->head->next;
	//返回栈顶元素指针即可
	return top;
}

//函数:删除栈顶元素
//有了上述封装好的函数,我们就可以直接用了
void pop(Stack* s)
{
	//首先进行安全性检查:判空
	//如果栈为空,直接返回
	if (isStackEmpty(s))
	{
		return;
	}
	//找到栈顶元素
	Node* top = findTop(s);
	//删除栈顶元素
	s->head->next = top->next;
	//释放栈顶元素
	free(top);
	top = nullptr;
}

//函数:销毁栈
//有始有终,防止内存泄露
void deleteStack(Stack* s)
{
	//不断进行pop操作,直到栈为空
	while (!isStackEmpty(s))
	{
		pop(s);
	}
	//此时,除了头结点,所有结点已经释放干净
	//接下来释放头结点
	free(s->head);
	s->head = nullptr;
	//最后释放栈指针空间,并避免悬空指针
	free(s);
	s = nullptr;
}

//主函数里进行操作
int main()
{
	//创建一个栈
	printf("执行创建栈操作\n");
	Stack* myStack = initialStack();
	//检测判空操作
	printf("执行判空操作\n");
	if (isStackEmpty(myStack))
	{
		printf("栈为空!\n");
	}
	else
	{
		printf("栈非空!\n");
	}
	//检测push操作
	printf("执行push操作:\n");
	push(myStack);
	printf("执行push操作:\n");
	push(myStack);	
	printf("执行push操作:\n");
	push(myStack);
	//再次检测判空操作
	printf("执行判空操作\n");
	if (isStackEmpty(myStack))
	{
		printf("栈为空!\n");
	}
	else
	{
		printf("栈非空!\n");
	}
	//检测top操作
	Node* top = findTop(myStack);
	printf("执行top操作:\n");
	printf("栈顶元素为:");
	printf("%d\n",top->data);
	//检测pop操作
	printf("执行pop操作\n");
	pop(myStack);
	//检测top操作
	top = findTop(myStack);
	printf("执行top操作:\n");
	printf("栈顶元素为:\n");
	printf("%d", top->data);
	//检测deleteStack操作
	printf("执行销毁操作:\n");
	deleteStack(myStack);
	if (myStack == nullptr)
	{
		printf("栈已释放完毕!\n");
	}
	else
	{
		printf("栈未释放完毕!\n");
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值