数据结构-链式栈(C语言)

1.函数的声明与自定义

linkstack.h

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

#define PUSH 1
#define POP 2
#define GETTOP 3
#define PRINT 4
#define EXIT 0

typedef char ElemType;

typedef struct linknode {
	ElemType data;
	struct linknode* next;
}LinkStNode;

#ifndef __LINKSTACK_H__
#define __LINKSTACK_H__

void menu();

void InitStack(LinkStNode*& s);			//初始化

void DestoryStack(LinkStNode*& s);		//销毁栈

bool StackEmpty(LinkStNode* s);			//判断栈空

bool Push(LinkStNode*& s, ElemType e);	//入栈

bool Pop(LinkStNode*& s, ElemType&e);	//出栈

bool gettop(LinkStNode* s, ElemType& e);//或取栈顶元素

void Print(LinkStNode* s, ElemType& e);//打印栈中元素

#endif // !__LINKSTACK_H__

2.链式栈的各函数操作

链式栈.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "linkstack.h"

void menu() {
	printf("************************************************\n");
	printf("******1.push                            **********\n");
	printf("******2.pop                     3.gettop********\n");
	printf("******4.print                   0.exit**********\n");
	printf("************************************************\n");
}

//初始化头结点
void InitStack(LinkStNode*& s) {
	s = (LinkStNode*)malloc(sizeof(LinkStNode));
	s->next = NULL;
}

//销毁栈空间
void DestoryStack(LinkStNode*& s) {
	LinkStNode* pre = s;							//定义指针pre指向头结点
	LinkStNode* p = s->next;						//定义指针p指向首节点
	while (p != NULL) {								//判断是否为空,首节点为空则整个栈为空,直接通过指针pre释放s开辟的空间
		free(pre);									//先释放头结点
		pre = p;									//领pre指向p,(也就是指向了头结点指向的下一个节点)
		p = pre->next;								//指针p也同步向后移
	}
	free(pre);										//释放最后一个节点的空间
	pre = NULL;										//指针赋空,避免野指针(但感觉这里也没太大必要,因为这只是个局部变量,跳出就没了)
}

//判断栈是否为空
bool StackEmpty(LinkStNode* s) {
	return(s->next = NULL);
}

//进栈操作
bool Push(LinkStNode*& s, ElemType e) {
	LinkStNode* p;									//开辟一个节点空间
	p = (LinkStNode*)malloc(sizeof(LinkStNode));
	p->data = e;									//头插法(头插法就会把最先进的元素排到尾部,可以实现栈的先进后出的特点)
	p->next = s->next;
	s->next = p;
	return true;
}

//因为是链式栈,先进后出的特点,所以是头插法,同时也是首节点先出
bool Pop(LinkStNode*& s, ElemType& e) {
	LinkStNode* p=NULL;								//创建结构体指针p,这个指针作用是指向出栈元素,避免出栈元素节点没指针指造成内存泄漏
	if (s->next == NULL) {							//判断是否空栈
		return false;
	}
	p = s->next;									//s为头节点,头结点指向的就是首节点,这里新建节点等于首节点
	e = p->data;									//提取出首节点元素赋值给e,这里的作用是可以设置参数e用于告诉用户出栈了什么元素
	s->next = p->next;								//头结点此时指向第二个节点,此时就把首节点独立出来了
	free(p);										//释放掉p节点空间
	p = NULL;
	return true;
}


//获取栈顶元素
bool gettop(LinkStNode* s, ElemType& e) {
	if (s->next == NULL) {
		return false;
	}
	e = s->next->data;
	return true;
}

//将栈中元素注意打印出来
void Print (LinkStNode* s, ElemType& e) {
	if (s->next == NULL) {							//判断栈是否为空
		printf("the stack is empty\n");
		return;
	}
	printf("栈中元素有:");
	while (s->next != NULL) {
		e = s->next->data;							//s为头结点,s的next即为首节点,打印首节点
		printf("%c ", e);
		s = s->next;
	}
	printf("\n");
}

3.运行

TEST.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "linkstack.h"

//链式栈
void test() {
	LinkStNode* s = NULL;
	int input = 0;
	ElemType e;
	InitStack(s);

	do {
		menu();
		printf("please choose mode:");
		scanf("%d", &input);
		//if (StackEmpty(s)) {
		//	printf("此栈为空\n");
		//}
		//else {
		//	printf("此栈不为空\n");
		//}
		switch (input) {
		case PUSH:
			printf("请输入要入栈的值:");
			getchar();
			scanf("%c", &e);						//因为e的类型为char型,只能接受一个字符(不是char数组),只能使用%c,使用%s在销毁空间时会出现堆栈溢出的错误,而使用%c会因为前面的换行导致跳过
			if (Push(s, e)) {						//所以要使用getchar把换行吞掉。(我理解是%s开辟的是属于字符串空间是大于1字节,而链式栈中设定一个节点为char型,仅为1字节,在销毁空间后,%s多余的空间并没能随着栈节点销毁而销毁就造成栈溢出
				printf("入栈成功\n");
			}
			else {
				printf("入栈失败\n");
			}
			break;
		case POP:
			if (Pop(s, e)) {
				printf("出栈成功\n");
			}
			else {
				printf("出栈失败");
			}
			printf("出栈元素为:%c\n", e);
			break;
		case GETTOP:
			gettop(s, e);
			printf("此时栈顶元素为:%c \n", e);
			break;
		case PRINT:
			printf("栈的内容为:");
			Print(s, e);
			break;
		case EXIT:
			DestoryStack(s);
			break;
		default:
			printf("模式选择错误,请重新输入!\n");
			break;
		}
	} while (input);
}
int main() {
	test();
	return 0;
}

4.结果

入栈与出栈都符合栈的先进后出的特点

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值