考研数据结构之链栈

提示:君子以俭德避难,不可荣以禄


前言

提示:这里可以添加本文要记录的大概内容:
在前面通过学习链表 我们知道单链表可以写成有表头的和无表头的 ,写有头结点的好处是什么来着?什么! 忘记了? 回去翻一下我们最喜欢的作者


添加头结点的目的是为了让包括空表在内的所有链表都有一个头指针。这样对是否为空的链表的操作就能统一起来,其中的数据域有时存放表的长度,有时什么都不放 所以若是带头节点使用的就是,删除,,插入的时候就不需要判断是否是第一个元素了操作就统一起来了(因为若是没有头节点 而你删除的又是第一个元素你的操作是L=frist->next, free(first); 若是删除的不是第一个元素pre->next=pre->next->next) ;
————————————————
所以使用单链表来创建一个表的话 要不要加头结点呢正如上面说的加不加是为了插入或者删除的时候是不是首结点统一起来 但是我们可以高大上的栈呀 我们只能在第一个元素进行操作 所以加不加头都可以,结构都能统一起来,不要问我为什么不把最后一个元素看为为TOP 链表只能一个一个来找 若是尾结点看为TOP 你的时间复杂度本来是O(1) 一下子让你提升了一个级别到达了O(n),当然可以加一个尾指针,可是何必?

一、结构体

所以由上面一段话 我们就可以定义出链栈的结构体了

// 链栈的存储结构
typedef struct StackNode
{
    int data;
    struct StackNode *next;
}StackNode,*LinkStack;
//单链表的定义
typedef struct LNode{
	ElemType data;
	struct LNode *next;
}LNode,*LinkList;//这两个是等价的

正如你所见的单链表与链栈就结构体而言没有区别 甚至可以说是一模一样只是定义基本操作的时候一个可以任意取数据 一个只能在表头取数据,

二、代码分块

这里我们写的是不包含头结点的(因为前面静态中与动态都是用带头节点写的,这里自己尝试一下新的,其实大差不差)

1、 链表的初始化(无头结点的单量表的初始化)

用我在链表中写的盘子原理 不带头节点 盘子上面就不用放任何东西,

bool InitStack(Stack* &L){
	L=NULL;
}

2、链表判空(或者叫做无头结点的判空)

这就是不带头结点的判空 若为空 L==NULL 盘子上没有任何东西

bool StackEmpty(Stack* L){
	if(L==NULL){
		cout<<"栈为空"<<endl;
		return true; 
	} 
	else {
		cout<<"栈不为空"<<endl; 
		return false;
	}
}
//压入

3、进栈(或者叫做无头结点的头插入)

//压入栈 ,压入栈简单来说就是链表的头插法 
bool Push(Stack* &L,ElemType &x){
	Stack* P=NULL;//先用P来保存第一个首结点的位置 
	//要插入一个数据 自然需要申请一个结点,申请结点自然需要判断申请空间是否成功 
	P=(Stack*)malloc(sizeof(Stack));
	if(P==NULL){
		exit(1);
	}
	P->data=x;
	P->next=L;//P的next还没有初始化 所以先把next 的空表区域填上 
	L=P; 
	cout<<"压入栈之后";PrintStack(L);
}

请添加图片描述

4、出栈(无头结点单链表的头删除)

//出栈就是不带头节点的单链表中删除首结点的操作 
bool Pop(Stack* &L,ElemType &x){
	
	Stack* P=NULL;
	 if(L==NULL){
	 	printf("链表为空"); 
	 	return false;
	 }
	 else{
	 	P=L; //定义一个变量P来接过盘子 其实也就是定义一个变量同时指向首结点 
	 	x=L->data;
	 	L=L->next;
		free(P); 
	 }
	 cout<<"进行出栈之后的操作是";
	 PrintStack(L); 
	 return true; 
}

请添加图片描述

5、获得栈顶元素

别忘了判空就行了 要不然会异常退出 还有就是首元素的值是如何表达的 L->data

bool GetTop(Stack* L,ElemType &x){
	if(L==NULL) return false;
	 else{
	 	x=L->data;  
	 }
	 return true; 
}

请添加图片描述

6、销毁链栈(销毁无头单链表)

与顺序表不一样 要一个一个释放

//也是无头结点单链表的销毁 
bool DestoryStack(Stack* &L){
	Stack *P=L;
	while(L){
		P=L;
		L=L->next;
		free(P);
		P=NULL;	
	}
}

请添加图片描述

三、可执行代码汇总

//InitStack(&S):初始化一个空栈
//StackEmpty(S)判断一个栈是否为空,若是为空则返回turn 否则返回false
//Push(&S,&x):进栈若是栈未满,则将x加入使之成为新的栈顶
//Pop(&S,&x):出栈,若是栈非空,则弹出栈顶元素,并用X返回、
//GetTop(S,&x):读栈顶元素,若是栈顶元素非空,则用x返回栈顶元素
//DestoryStack(&S):销毁栈,并释放栈S占用的存储空间(&表引用调用)
#include<bits/stdc++.h>
#define ElemType int
#define OK 1
#define ERROR 0 
#define MAX 3 
using namespace std;
typedef struct Stack{
	ElemType data;
	struct Stack* next; 
}Stack;
//在我写打印的时候突然想到若是栈满 再来打印的话  最后的指针就会越界,此时就不能* S.top 
//所以这里你就应该知道为什么有的书上设置top开始的值为-1 
void PrintStack(Stack* L){
	Stack* P=L;
	if(P==NULL){
		cout<<"此时的栈链为空"<<endl;
	}
	cout<<"此时栈中的元素是(左边为栈顶)";
	while(P){
		cout<<P->data<<" ";
		P=P->next;	
	}
	cout<<endl;
}
bool InitStack(Stack* &L){
	L=NULL;//用我在链表中写的盘子原理 不带头节点 盘子上面就不用放任何东西,
}
bool StackEmpty(Stack* L){
	if(L==NULL){
		cout<<"栈为空"<<endl;
		return true; 
	} 
	else {
		cout<<"栈不为空"<<endl; 
		return false;
	}
}
//压入栈 ,压入栈简单来说就是链表的头插法 
bool Push(Stack* &L,ElemType &x){
	Stack* P=NULL;//先用P来保存第一个首结点的位置 
	//要插入一个数据 自然需要申请一个结点,申请结点自然需要判断申请空间是否成功 
	P=(Stack*)malloc(sizeof(Stack));
	if(P==NULL){
		exit(1);
	}
	P->data=x;
	P->next=L;//P的next还没有初始化 所以先把next 的空表区域填上 
	L=P; 
	cout<<"压入栈之后";PrintStack(L);
}
//出栈就是不带头节点的单链表中删除首结点的操作 
bool Pop(Stack* &L,ElemType &x){
	
	Stack* P=NULL;
	 if(L==NULL){
	 	printf("链表为空"); 
	 	return false;
	 }
	 else{
	 	P=L; //定义一个变量P来接过盘子 其实也就是定义一个变量同时指向首结点 
	 	x=L->data;
	 	L=L->next;
		free(P); 
	 }
	 cout<<"进行出栈之后的操作是";
	 PrintStack(L); 
	 return true; 
}
bool GetTop(Stack* L,ElemType &x){
	if(L==NULL) return false;
	 else{
	 	x=L->data;  
	 }
	 return true; 
}
//也是无头结点单链表的销毁 
bool DestoryStack(Stack* &L){
	Stack *P=L;
	while(L){
		P=L;
		L=L->next;
		free(P);	
	}
}
void menu(){
	cout<<"请选择你要进行的操作"<<endl;
	cout<<"1、判断栈是否为空 2、进栈 3、出栈 "<<endl;
	cout<<"4、获得栈顶的值 5、销毁栈  6、展示栈中的内容 7、退出"<<endl;
} 
int main(){
	Stack* L;ElemType x;
	InitStack(L); 
	int choice;
	while(1){
		menu();	
		cin>>choice;
		if(7==choice) break;
		switch(choice){
			case 1:{
				StackEmpty(L);
				break;
			}
			case 2:{
				cout<<"请输入你要入栈的值"<<endl; 
				cin>>x; 
				Push(L,x);
				break;
			}
			case 3:{
				if(L==NULL){
					cout<<"casezhong L为空"<<endl;
				}
				Pop(L,x);
				break;
			}
			case 4:{
				GetTop(L,x);
				cout<<"此时栈顶元素是"<<x<<endl;
				break;
			}
			case 5:{
				DestoryStack(L);
				break;
			}
			case 6:{
				PrintStack(L);
				break;
			} 
			default:break;
		}
	} 
	return 0;	
}

总结:代码不难 大家可以尝试一下 效果更好

总结

若是文章对你的提升由哪怕一点帮助的话 请答应我 不要吝啬你的点赞评论 你的鼓励对作者是一种莫大的鼓励

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值