栈 | 队列

系统栈主要保存以下内容:

1.局部变量,2.函数的形参和返回值 3.函数的调用关系

一、栈

1.基本概念

栈是一种特殊的线性表,具有线性结构。表尾为栈顶,表头为栈顶。遵循先进后出原则,只能在栈顶进行插入和删除操作。

2.基本操作

栈的插入操作为入栈(进栈)。栈的删除操作为出栈。如下:

3.栈的顺序存储结构

     它使用一个一维数组来存储栈中的数据元素,数组的下标小的一端作为栈底,另一端作为栈顶。栈顶位置随入栈和出栈操作而变化,因此需要一个整型变量‌top来记录当前栈顶元素在数组中的位置。不多做介绍。

      分类:①满增栈     ②满减栈     ③空增栈     ④空减栈

基本类型类型说明出入栈操作
满增栈栈顶不为空,存储地址由低到高

入栈:栈顶++  入栈数据

出栈:出栈数据,栈顶--

满减栈栈顶不为空,存储地址由高到低

入栈:栈顶--  入栈数据

出栈:出栈数据,栈顶++

空增栈栈顶为空,存储地址由低到高

入栈:入栈数据,栈顶++

出栈:栈顶--,出栈数据

空减栈栈顶为空,存储地址由高到低

入栈:入栈数据,栈顶--

出栈:栈顶++,出栈数据

4.栈的链式存储结构

本质为单向链表。对于链栈来说,基本不存在栈满的情况。除非内存中已经没有可以使用的空间。

基本操作:

#include"link.h"
#include<stdio.h>
Stack_t *create_stack() //创建栈
{
	Stack_t*slink = malloc(sizeof(Stack_t));
	if(slink == NULL)
	{
		perror("fail malloc\n");
		return NULL;
	}
	slink->ptop = NULL;
	slink->clen = 0;
	return slink;
}
int is_empty_stack(Stack_t*slink)//判空
{
	return slink->ptop == NULL;
}
int push_stack(Stack_t*slink,Datatype data)//入栈
{
	Snode_t *pnode = malloc(sizeof(Snode_t));
    if(NULL == pnode)
    {
        perror("fail malloc\n");
        return -1;
    }
    pnode->data = data;
    pnode->pnext = NULL;
    pnode->pnext = slink->ptop;
    slink->ptop = pnode;
    slink->clen++;
	return 0;
}
void stack_for_each(Stack_t*slink)//遍历打印
{
	Snode_t*p = slink->ptop;
	while(p )
	{
		printf("%d\n",p->data);
		p = p->pnext;
	}
	printf("\n");
}
int pop_stack(Stack_t*slink,Datatype * data)//出栈
{
	if (is_empty_stack(slink))
		return 0;

	Snode_t *pdel = slink->ptop;
	slink->ptop = pdel->pnext;
	if (data != NULL)
	{
		*data = pdel->data;
	}

	free(pdel);
	slink->clen--;

	return 1;
}
int get_stack_top(Stack_t*slink,Datatype *data)//获取栈顶的值
{
	if(is_empty_stack(slink))
	{
		return 0;
	}
	Snode_t*p = slink->ptop;
	*data = p->data;
	return 1;
}
void clear_stack(Stack_t*slink)//清空栈
{
	while(!is_empty_stack(slink))
	{
		pop_stack(slink,NULL);
	}
}	
void destroy_stack(Stack_t*slink)//销毁栈
{
	clear_stack(slink);
	free(slink);
}

栈的数据类型声明

typedef int Datatype;
typedef struct Snode
{
    Datatype data;
    struct Snode*pnext;
}Snode_t;
typedef struct Stack
{
    Snode_t*ptop;
    int clen;
}Stack_t;
extern Stack_t *create_stack();
extern int push_stack(Stack_t*slink,Datatype data);
extern int pop_stack(Stack_t*slink,Datatype * data);
extern int get_stack_top(Stack_t*slink,Datatype *data);
extern void clear_stack(Stack_t*slink);
extern void destroy_stack(Stack_t*slink);
extern void stack_for_each(Stack_t*slink);

5.循环栈与链队栈的比较

①在时间复杂度上是一样的,均为0(1)。

②空间性能,顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样,如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。

二、队列

1.概念

队列:允许从一端插入数据,另一端删除数据的线性存储结构(FIFO)

管道的本质也是队列,队列主要用于缓存数据

2.基本操作

插入操作为入队操作(队尾) 删除操作为出队操作(队头)

3.顺序队列

使用不当会出现存在假溢出现象,一般使用循环队列,充分利用循环空间。

4.链式队列

初始化:

typedef int QDataType;
typedef struct qnode
{
    QDataType data;
    struct qnode *pnext;
}QNode_t;
typedef struct queue
{
    QNode_t *pfront;
    QNode_t *prear;
    int clen;
    pthread_mutex_t mutex;
}Queue_t;

基本操作:

#include"link.h"
#include<stdio.h>
Queue_t*create_queue()
{
	Queue_t *qlink = malloc(sizeof(QNode_t));
	if(qlink == NULL)
	{
		perror("error malloc 1\n");
		return NULL;
	}
	qlink->pfront = NULL;
	qlink->prear = NULL;
	pthread_mutex_init(&(qlink->mutex),NULL);
	qlink->clen = 0;
	return qlink;
}
int is_empty_queue(Queue_t*qlink)
{
	if(NULL == qlink->pfront && qlink->prear == NULL)
	{
		return 1;
	}
	return 0;
}
int push_queue(Queue_t *qlink,QDataType data)
{
	QNode_t * pnode = malloc(sizeof(QNode_t));
	pnode->data = data;
	pnode->pnext = NULL;
	if(pnode == NULL)
	{
		perror("error malloc2\n");
		return -1;
	}
	if(is_empty_queue(qlink))
	{
		qlink->pfront = pnode;
		qlink->prear = pnode;
	}
	else
	{
		QNode_t * p = qlink->prear;
		p->pnext = pnode;
		qlink->prear = pnode;
		qlink->clen++;
	}
}
int pop_queue(Queue_t *qlink,QDataType  * data)
{
	QNode_t *del = qlink->pfront;
	if(is_empty_queue(qlink))
	{
		return -1;
	}
	if(qlink->clen == 1)
	{
		qlink->pfront = NULL;
		qlink->prear = NULL;
	}
	qlink->pfront = del->pnext;
	if(data != NULL)
	{
		*data = del->data;
	}
	free(del);
	qlink->clen--;
	return 1;
}
void print_for_each(Queue_t*qlink)
{
	QNode_t*p = qlink->pfront;
	while(p)
	{
		printf("%d\n",p->data);
		p = p->pnext;
	}
	printf("........................\n");
}
int get_queue_pop(Queue_t*qlink,QDataType *data)
{
	if(is_empty_queue(qlink))
	{
		return -1;
	}
	QNode_t*p = qlink->pfront;
	*data = p->data;
}
void clear_queue_pop(Queue_t*qlink)
{
	while(!is_empty_queue(qlink))
	{
		pop_queue(qlink,NULL);
	}
}
void destroy_queue(Queue_t*qlink)
{
	clear_queue_pop(qlink);
	free(qlink);
}

5.循环队列与链队列的比较

①从时间上,其实它们的基本操作都是常数时间,即都为0(1)的,不过循环队列是事先申请好空间,使用期间不释放,而对于链队列,每次申请和释放结点也会存在一些时间开销,如果入队出队频繁,则两者还是有细微差异。

②空间上来说,循环队列必须有一个固定的长度,所以就有了存储元素个数和空间浪费的问题。而链队列不存在这个问题,尽管它需要一个指针域,会产生一些空间上的开销,但也可以接受。所以在空间上,链队列更加灵活。

三、问答。

1.程序运行过程中的栈区和数据结构的栈有什么区别?

程序运行过程中的栈区和数据结构中的栈是两个不同的概念,它们分别属于内存管理和数据结构领域。

  • 数据结构中的栈‌是一种后进先出(LIFO)的数据结构,它只允许在栈顶进行数据的添加(压栈)或移除(出栈)操作。数据结构中的栈是一种抽象数据类型,用于管理数据的存储和访问方式,它不直接涉及物理内存的分配和管理‌。

  • 程序运行过程中的栈区‌则是指内存中的一个特定区域,用于存储局部变量、函数调用的上下文信息等。在程序运行时,操作系统或运行时环境会自动管理这部分内存的分配和释放。栈区的特点是快速分配和释放内存,但空间大小通常受到限制,且只能从栈顶进行操作‌。

简而言之,数据结构中的栈是一种抽象数据类型,用于组织和管理数据;而程序运行过程中的栈区是内存中的一个具体区域,用于存储程序执行时的临时数据和函数调用信息,这两者在计算机科学中各有其用途和重要性‌。

2.队列和栈有什么区别?

①规则不同

1. 队列:先进先出(First In First Out)FIFO

2. 栈:先进后出(First In Last Out )FILO

②对插入和删除操作的限定不同

1. 队列:只能在表的一端进行插入,并在表的另一端进行删除;

2. 栈:只能在表的一端插入和删除。

③遍历数据速度不同

1. 队列:基于地址指针进行遍历,而且可以从头部或者尾部进行遍历,但不能同时遍历,无需开辟空间,因为在遍历的过程中不影响数据结构,所以遍历速度要快;

2. 栈:只能从顶部取数据,也就是说最先进入栈底的,需要遍历整个栈才能取出来,而且在遍历数据的同时需要为数据开辟临时空间,保持数据在遍历前的一致性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值