栈和队列复习

本文主要介绍了栈这一数据结构,栈是操作受限的线性表,操作主要是入栈和出栈。详细阐述了栈的顺序存储和链式存储,包括结构定义、创建、判空、进出栈等操作,对比了两种存储方式,指出元素长度固定用顺序栈,不固定用链栈,最后提到栈的拓展正在开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


理解栈

栈是一个特殊的线性表,它最特的地方就是它的操作被限制在了栈顶,栈底是固定的,操作也就只有入栈出栈

最先进栈的元素不是只能最后出栈。

栈只是对入栈出栈的位置进行了限制,但是没有对进出时间有限制。

栈的存储结构

顺序存储

栈的结构定义
typedef int DataType;
struct SeqStack
{
	int MAX;         //最大容量
	int top;         //栈顶指针
	DataType *elem;  //存放元素的起始指针
};
typedef struct SeqStack *SeqStack;
栈的创建
SeqStack SetNullStack_Seq(int m)  //创建空顺序栈
{
	SeqStack sstack = (SeqStack)malloc(sizeof(struct SeqStack));
	if (sstack != NULL){
		sstack->elem = (int*)malloc(sizeof(int)*m);
		if (sstack->elem != NULL){
			sstack->MAX = m;
			sstack->top = -1;
			return(sstack);
		}
		else {
			free(sstack);
			return NULL;
		}
	}
	else{
		printf("out of space");
		return NULL;
	}
}
栈的判空

判断top值是否为-1来判断栈是否为空,因为一般栈的首元素插入都是在‘0’这个位置,就像插入数组的第一位。

int IsNullStack_seq(SeqStack sstack) 
{
    return(sstack->top == -1);
}
顺序进栈
void Push_seq(SeqStack sstack, int x)  //入栈
{
	if (sstack->top >= (sstack->MAX - 1))  //检查栈是否满
		printf("overflow! \n");
	else{
		sstack->top++; //若不满,先修改栈顶变量
		sstack->elem[sstack->top] = x;//把元素x放到栈顶变量的位置中
	}
}
顺序出栈
void Pop_seq(SeqStack sstack)//出栈
{
	if (IsNullStack_seq(sstack)) //判断栈是否为空
		printf("Underflow!\n");
	else
		sstack->top = sstack->top - 1;//栈顶减1
}
拓:求栈顶元素
DataType Top_seq(SeqStack sstack)//求栈顶元素的值
{
	if (IsNullStack_seq(sstack))//判断sstack所指的栈是否为空栈
	{
		printf("it is empty");
		return 0;
	}
	else
		return sstack->elem[sstack->top];
}

入栈和出栈都无循环语句,所以时间复杂度均是O(1)。

链式存储

链栈是栈顶放在单链表的头部(失去意义的头结点可以不要),基本不存在栈满的情况。
栈链的操作绝大部分和单链表类似,只是在插入和删除上,特殊一些

栈的结构定义

有头结点的结构

typedef int DataType;
struct Node{
	DataType	  data;
	struct Node*  next;
};
typedef struct Node  *PNode;
typedef struct Node  *LinkStack;

无头结点的结构

typedef int Status; 
typedef int SElemType; /* SElemType类型根据实际情况而定,这里假设为int */

typedef struct StackNode
{
	SELemType data;
	struct StackNode *next;
}StackNode,*LinkStackPtr;

typedef struct LinkStack
{
	LinkStackPtr top;
	int count;
}LinkStack;
栈的创建

有头结点的创建

LinkStack SetNullStack_Link()  //创建带有头结点的空链栈
{
	LinkStack top = (LinkStack)malloc(sizeof(struct Node));
	if (top != NULL) top->next = NULL;
	else printf("Alloc failure");
	return top;  //返回栈顶指针
}

无头结点的创建

“把S置为空栈”个人认为是保险措施,在有头结点的创建中可以尝试使用。

/*  构造一个空栈S */
Status InitStack(LinkStack *S)
{ 
        S->top = (LinkStackPtr)malloc(sizeof(StackNode));
        if(!S->top)
                return 0;
        S->top=NULL;
        S->count=0;
        return OK;
}

/* 把S置为空栈 */
Status ClearStack(LinkStack *S)
{ 
        LinkStackPtr p,q;
        p=S->top;
        while(p)
        {  
                q=p;
                p=p->next;
                free(q);
        } 
        S->count=0;
        return OK;
}
栈的判空

有头结点的链栈判空

int IsNullStack_link(LinkStack top) //判断一个链栈是否为空
{
	if (top->next == NULL)
		return 1;
	else
		return 0;
}

无头结点的链栈判空

Status StackEmpty(LinkStack S)
{ 
        if (S.count==0)
                return 1;
        else
                return 0;
}

链式进栈

有头结点的进栈

void Push_link(LinkStack top, DataType x) //进栈
{
	PNode p;
	p = (PNode)malloc(sizeof(struct Node));
	if (p == NULL)
		printf("Alloc failure");
	else
	{
		p->data = x;
		p->next = top->next;
		top->next = p;
	}
}

无头结点的进栈

/* 插入元素e为新的栈顶元素 */
Status Push(LinkStack *S,SElemType e)
{
        LinkStackPtr s=(LinkStackPtr)malloc(sizeof(StackNode)); 
        s->data=e; 
        s->next=S->top;	/* 把当前的栈顶元素赋值给新结点的直接后继,见图中① */
        S->top=s;         /* 将新的结点s赋值给栈顶指针,见图中② */
        S->count++;
        return OK;
}

链式出栈

有头结点的出栈

void Pop_link(LinkStack top)// 删除栈顶元素
{
	PNode p;
	if (top->next == NULL)
		printf("it is empty stack!");
	else
	{
		p = top->next;
		top->next = p->next;
		free(p);
	}
}

无头结点的出栈
(这个直接自带获取栈顶元素的部分)

/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
Status Pop(LinkStack *S,SElemType *e)
{ 
        LinkStackPtr p;
        if(StackEmpty(*S))
                return ERROR;
        *e=S->top->data;
        p=S->top;					/* 将栈顶结点赋值给p,见图中③ */
        S->top=S->top->next;    /* 使得栈顶指针下移一位,指向后一结点,见图中④ */
        free(p);                    /* 释放结点p */        
        S->count--;
        return OK;
}
拓:求栈顶元素

有头结点

DataType Top_link(LinkStack top)// 求栈顶元素的值
{
	if (top->next == NULL)
	{
		printf("It is empty stack!");
		return 0;
	}
	else
		return top->next->data;
}

入栈和出栈都无循环语句,所以时间复杂度均是O(1)。

双栈对比

  1. 时间复杂度都为O(1)
  2. 顺序栈:若元素变化范围可控,即长度固定,则用顺序栈好一些(优势:存取时定位方便
  3. 链栈:若元素变化范围不可控,即长度不固定,则用链栈好一些(优势:可以很大!

栈的拓展

正在开发ing…………

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值