4.栈以及相关代码

4.栈及其实现

线性逻辑结构:1.线性表---->顺序表(存储结构)  链表(存储结构)

线性逻辑结构:  2.栈------->顺序栈 (存储结构)  链式栈(存储结构)

线性表:增删改查 可以在线性表的任意位置进行操作-------太灵活

对线性表进行一些约束,一般来说对线性表进行两种约束,这两种约束分别得到另外的两个逻辑结构:一个是栈,另一个是队列

栈:限制在一端进行插入或者删除操作的线性表(俗称“堆栈”),中间也不许操作

允许进行操作的一端称为“栈顶”
不允许进行操作的一段称为“栈底”

栈中没有数据时 称为“空栈”

栈性质:先进后出/后进先出------>弹夹

栈顶是最后放入的数据(并不是指空间最上面的数据)

栈顶“指针”:标记栈顶的位置

(这个指针具有什么数据类型,取决于它保存啥--->如果是下标,则为int类型,“指针”只是说来用一下代指的,只是把名字拿来用,而不是它的含义,即变量)

栈底“指针”:标记栈底的位置

应用场景:

  1. 函数调用的实现(递归)
  2. 业务需求,倒着走的逻辑:历史记录 网页退回 撤销
  3. 物理上的堆栈

(堆)栈:先进后出的

  1. C++ STL库 stack

栈的实现:初始化,入栈(添加一个元素),出栈(删除一个元素--->只能删除栈顶元素),判空/判满,得到栈顶元素

#define maxsize 10

顺序存储结构实现:顺序栈--->基于数组实现data[10]

初始化一个栈:(1)存储数据的东西---数组 (2)栈顶”指针”top:(下标)int类型

栈底指针 固定指向下标0,不需要单独的变量标识

栈顶指针指向什么位置:
(1)指向真正的栈顶元素

初始化:top=-1(等于0代表0下标有元素)

入栈:top++,data[top]=k;

出栈:top--

判满:top==maxsize-1

判空:top==-1

  1. 指向真正栈顶元素的下一个位置

初始化:top=0

入栈:data[top]=k,top++;

出栈:top--

判满:top==maxsize

判空:top==0

得到栈顶元素:return data[top-1];

链式存储结构实现:链栈--->基于单链表实现:带头结点的单链表

把头结点端 当作栈顶:真正的栈顶元素在首元结点中

  1. 栈顶“指针”:头指针
  2. 初始:初始化一个带头结点的空的单链表
  3. 入栈:头插法
  4. 出栈:删除首元结点
  5. 得到栈顶元素:输出首元结点的数据

溢出:

顺序栈:上溢:栈满之后,继续入栈

下溢:栈空之后,继续出栈

链栈:  动态分配不存在上溢

存在下溢:栈空之后,继续出栈

顺序栈代码:

#include<stdio.h>
#include<stdlib.h>
#define maxsize 10

///顺序栈///
/*typedef struct{
	int date[maxsize];//栈中元素 
	int top;// 栈顶指针 	
}sstack;*/ 

typedef struct{
	int *date;//栈中元素 
	int top;// 栈顶指针 	
}sstack;

//--------------------------------------------------------------------- 
//栈操作:初始化,判空,入栈(push),出栈(pop),读取栈顶元素(top)
//以顺序栈为例子 
//初始化 
sstack initstack()
{
	sstack s;
	s.date =(int*)malloc(sizeof(int)*maxsize);
	s.top=-1;//初始化栈顶指针
	//也有 s.top=0
	// =-1,先加后赋值,指针指向栈顶元素
	//=0,先赋值再加,指针指向 栈顶元素的下一个存储单元 
	return s;
 } 
 
//入栈--对栈进行了修改,指针传递 
void Pushh(sstack *s,int k)
{
	//栈空间固定,加入一个元素要先判断是否满了,还能不能加入 
	if(s->top==maxsize-1)
	{
		printf("栈满\n");//栈满报错,不能加入 
	}
	else{
		s->top++;
		s->date[s->top]=k;
		//s.date [++s.top]=k;
	} 
 }//若top初始化为0,如何改写 
  
//出栈
void Popp(sstack *s)
{
	//删除之前判空,还有没有的删
	if(s->top==-1)
	{
		printf("栈空\n");//栈空报错,不能删除 
	 } 
	 else{
	 	s->top--;
	 } 
}//若top初始化为0,如何改写
 
//读取栈顶元素
void gettop(sstack s)
{
	int x;
	//判空,还有没有的读取 
	if(s.top==-1)
	{
		printf("栈空\n");//栈空报错,不能删除 
	
	 } 
	 else{
	 	x=s.date[s.top]; 
	 	printf("%d\n",x);
	 } 
	
 } //若top初始化为0,如何改写
int main()
{
	int x;
	sstack s=initstack();
	Pushh(&s,1);
	Pushh(&s,2);
	Pushh(&s,3);
	gettop(s);

	Popp(&s);
	gettop(s);

	Popp(&s);
	gettop(s);
	Pushh(&s,4);
	gettop(s);
	return 0; 

 } 
  
  
  
  
  
  
  
   

链栈代码:

#include<stdio.h>
#include<stdlib.h>
///链栈--单链表实现栈///
typedef struct listackNode{//链栈结点 
	int date;//链栈结点中元素 
	struct listackNode* next;//指针 	
}sstack,*listack;
//此处的listack与链表代码中的 linklist类似
//listack==sstack *;
//使用 listack 声明链栈中的结点指针,意在强调操作对象是栈; 
//使用 sstack* 声明链栈中的结点指针,意在强调操作对象是栈中的某个结点 

 
//头指针相当于 栈顶指针 
//直接在链表表头进行操作,链表表头相当于栈顶
//入栈:头插。 出栈:删除首元结点 

//--------------------------------------------------------------------- 
//栈操作:初始化,判空,入栈(push),出栈(pop),读取栈顶元素(top) 
//初始化 
listack initstack()
{
	listack s=(listack)malloc(sizeof(sstack));
	s->next=NULL;
	return s;
 } 
 
//入栈--对栈进行了修改,指针传递 
void Pushh(listack s,int k)
{
	//链表结点个数可以动态调整,无需判满
	//头插法插入结点,实现入栈 
	sstack *p=(sstack*)malloc(sizeof(sstack));//p是待插入的新结点 
	p->date =k;
	//头插法 插入p 
	p->next =s->next;
	s->next =p;  
	
 } 
//出栈
void Popp(listack s)
{
	//删除之前判空,还有没有的删
	if(s->next==NULL)
	{
		printf("栈空\n");//栈空报错,不能删除 
	 } 
	 else
	 {
	 sstack *p=s->next ;//让p指向待删除的首元结点
	 
	 s->next =p->next ;
	 free(p); 
	 p=NULL;
	 } 
} 
//读取栈顶元素
void gettop(listack s)
{
	int x;
	//判空,还有没有的读取 
	if(s->next==NULL)
	{
		printf("栈空\n");//栈空报错,不能删除	 
	 } 
	 else
	 {
	 	x=s->next->date;
		printf("%d\n",x); 
	 } 
	 
 } 
int main()
{
	int x;
	listack s=initstack();   
	Pushh(s,1);
	Pushh(s,2);
	Pushh(s,3);
	gettop(s);
	
	Popp(s);
	gettop(s);
	return 0; 
 } 
  
  
  
  

在C语言中,我们可以创建一个基于数组的简单数据结构来实现上述功能。以下是代码示例: 1. 定义实现数据结构(使用数组): ```c #define MAX_SIZE 100 typedef struct { int top; int data[MAX_SIZE]; } Stack; ``` 这里定义了一个结构体`Stack`,包含两个部分:`top`用于记录顶元素的位置,`data[]`作为存储元素的数组。 2. 的初始化: ```c void init(Stack *s) { s->top = -1; // 初始化顶为-1,表示空 } ``` 这个函数将顶位置设为-1,表示为空。 3. 入(push操作): ```c void push(Stack *s, int value) { if (s->top < MAX_SIZE - 1) { // 如果未满 s->top++; s->data[s->top] = value; } else { printf("Stack overflow.\n"); } } ``` 这个函数检查是否还有空间,然后将新元素放在顶并更新`top`。 4. 出(pop操作): ```c int pop(Stack *s) { if (s->top == -1) { // 如果为空 return -1; // 返回-1表示空错误 } else { int value = s->data[s->top]; // 获取顶元素 s->top--; // 移除顶元素并减小top return value; } } ``` 此函数获取并移除顶元素,并返回它。 5. 求顶元素的值: ```c int getTop(Stack *s) { if (s->top != -1) { return s->data[s->top]; // 非空返回顶元素 } else { return -1; // 空时返回-1 } } ``` 这个函数直接读取顶元素值,如果空则返回-1。 6. 元素输出(遍历顶到底): ```c void printStack(Stack *s) { for (int i = 0; i <= s->top; i++) { printf("%d ", s->data[i]); // 输出中所有元素 } printf("\n"); } ``` 此函数打印中的所有元素,从顶开始。 **相关问题--:** 1. 如何处理非法的出操作(如当为空时试图弹出元素)? 2. 这种数组实现的支持动态扩容吗? 3. 如果需要改变的最大容量,如何修改代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值