第五周day4

本文介绍了栈和队列两种特殊表结构,包括它们的功能限制、基本运算以及在实际问题中的应用。栈分为顺序栈和链式栈,遵循先进后出的原则,常用于函数调用、表达式解析等。队列则是一个先进先出的数据结构,有顺序队列和链式队列两种形式,常见于消息队列、树的层序遍历等场景。同时,文章提供了栈和队列的C语言实现示例。

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

功能受限的表结构

    对表结构的功能加以限制,形成了特殊的表结构

    栈:

        只有一个出入口的表结构,先进后出,FILO

        顺序栈:

            存储元素内存的首地址

            栈的容量

            栈顶位置

        运算:

            创建、销毁、入栈、出栈、栈满、栈空、获取栈顶元素、数量

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define TYPE int
//顺序栈
typedef struct Arraystack
{
	TYPE* ptr;   //存储元素首地址
	size_t cal;	//栈的容量
	size_t top;//栈顶位置	
}Arraystack;

//创建
Arraystack* creat_array_stack(size_t cal)
{
	Arraystack* stack = malloc(sizeof(Arraystack));
	stack->ptr = malloc(sizeof(TYPE)*cal);
	stack->cal=cal;
	stack->top=0;  //入栈的位置  空增栈
	return stack;
}

//销毁
void destroy_array_stack(Arraystack* stack)
{
	free(stack->ptr);
	free(stack);
}

//栈空
bool empty_array_stack(Arraystack* stack)
{
	return !stack->top;
}

//栈满
bool full_array_stack(Arraystack* stack)
{
	return stack->top >= stack->cal;
}

//入栈
bool push_array_stack(Arraystack* stack,TYPE val)
{
	if(full_array_stack(stack)) return false;
	stack->ptr[stack->top++] = val;
	return true;
}

//出栈
bool pop_array_satck(Arraystack* stack)
{
	if(empty_array_stack(stack)) return false;
	stack->top--;
	return true;
}

//栈顶
bool top_array_stack(Arraystack* stack,TYPE *val)
{
	if(empty_array_stack(stack)) return false;
	*val=stack->ptr[stack->top-1];
	return true;
}

//数量
size_t size_array_stack(Arraystack* stack)
{
	return stack->top;
}

bool is_pop(int* a, int* b,int len)
{
	int i=0,j=0;
	Arraystack* stack=creat_array_stack(len);
	while(i<len) 
	{
		push_array_stack(stack,a[i]);
		int top=-10;
		while(top_array_stack(stack,&top) && top==b[j])
		{
			
			pop_array_satck(stack);
			j++;
		}
		i++;
	}
	bool flag= empty_array_stack(stack);
	destroy_array_stack(stack);
	return flag;
}
int main(int argc,const char* argv[])
{
	Arraystack* stack = creat_array_stack(10);
	for(int i=0; i<10; i++)
	{
		push_array_stack(stack,i+10);
		int top=-10;
		top_array_stack(stack,&top) && printf("top=%d\n",top);
	}
	printf("---------------\n");
	while(!empty_array_stack(stack))
	{
		int top=-10;
		top_array_stack(stack,&top) && printf("top=%d\n",top);
		pop_array_satck(stack);	
	}
	int a[5]={1,2,3,4,5},b[5]={5,4,3,2,1};
	if(is_pop(a,b,5)) 
	{
		printf("yes");
	}
	else
	{
		printf("no");
	}
}

        链式栈:

            数据项:

                栈顶

                节点数量

            运算:

            创建、销毁、入栈、出栈、栈满、栈空、获取栈顶元素、数量

        栈的应用:

            1、函数的调用、栈内存

            2、生产者和消费者模型(仓库使用栈实现)

            3、表达式的解析(中缀表达式转后缀表达式)

        栈常见的笔试题:

            某序列为入栈顺序,判断哪些是正确的出栈顺序

            1 2 3 4 5

            1 2 3 4 5 yes

            3 2 1 5 4 yes

            3 1 2 4 5 no    注意:边入边出

            编程题:实现一个函数,判断序列b是否是序列a的出栈顺序

            bool is_pop(int* a,int* b,int len)

            问题:两个顺序栈,如何安排他们的存储方向,能够空间利用最大化

   

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TYPE int
//设计单链表的节点
typedef struct Node
{
	TYPE data;//节点的数据域
	struct Node* next;//节点的指针域
}Node;

//创建节点
Node* creat_node(TYPE data)
{
	//分配存储节点的内存
	Node* node=malloc(sizeof(Node));
	node->data=data;
	node->next=NULL;
	return node;
}

typedef struct Liststack
{
	Node* top;
	size_t cnt;
}Liststack;

//创建
Liststack* creat_list_stack(void)
{
	Liststack* stack = malloc(sizeof(Liststack));
	stack->top=NULL;
	stack->cnt=0;
	return stack;
}

//入栈
void push_list_stack(Liststack* stack,TYPE val)
{
	Node* node = creat_node(val);
	node->next = stack->top;
	stack->top = node;
	stack->cnt++;
}

//栈顶
TYPE top_list_stack(Liststack* stack)
{
	return stack->top->data;
}

//栈空
bool empty_list_stack(Liststack* stack)
{
	return NULL == stack->top;	
}

//出栈
void pop_list_stack(Liststack* stack)
{
	Node* temp=stack->top;
	stack->top=stack->top->next;
	free(temp);
	stack->cnt--;
}

//数量
size_t size_list_stack(Liststack* stack)
{
	return stack->cnt;
}

//销毁
void destroy_list_stack(Liststack* stack)
{
	while(!empty_list_stack(stack))
	{
		pop_list_stack(stack);
	}
	free(stack);
}
int main(int argc,const char* argv[])
{
	Liststack* stack=creat_list_stack();
	for(int i=0; i<10; i++)
	{
		push_list_stack(stack,rand()%100);
		if(!empty_list_stack(stack))
		{
			printf("top:%d\n",top_list_stack(stack));
		}
	}
	printf("------------------\n");
	while(!empty_list_stack(stack))
	{
		printf("top:%d  size=%d\n",top_list_stack(stack),size_list_stack(stack));
		pop_list_stack(stack);
	}
}

    队列:

        一个端口进数据,另一个端口出数据,先进先出表,FIFO

        顺序队列:

            数据项:

                存储元素的内存首地址

                对头位置

                队尾位置

                队列容量

            运算:

                创建、销毁、入队、出队、队满、队空、查看对头、队尾、数量

           

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define TYPE int

typedef struct ArrayQueue
{
	TYPE* ptr;
	size_t cal;
	size_t head;	//front对头
	size_t tail;	//rear队尾 接下来要入队的位置
}ArrayQueue;

//创建
ArrayQueue* creat_array_queue(size_t cal)
{
	ArrayQueue* queue=malloc(sizeof(ArrayQueue));
	queue->ptr=malloc(sizeof(TYPE)*(cal+1));	//解决对空堆满问题
	queue->cal=cal+1;
	queue->head=0;
	queue->tail=0;
	return queue;
}

//销毁
void destroy_array_queue(ArrayQueue* queue)
{
	free(queue->ptr);
	free(queue);
}

//队空
bool empty_array_queue(ArrayQueue* queue)
{
	return queue->head==queue->tail;
}

//队满
bool full_array_queue(ArrayQueue* queue)
{
	return (queue->tail+1)%queue->cal==queue->head;
}

//入队
bool push_array_queue(ArrayQueue* queue,TYPE val)
{
	if(full_array_queue(queue)) return  false;
	queue->ptr[queue->tail]=val;
	queue->tail=(queue->tail+1)%queue->cal;
	return true;
}

//出队
bool pop_array_queue(ArrayQueue* queue)
{
	if(empty_array_queue(queue)) return false;
	queue->head=(queue->head+1)%queue->cal;
	return true;
}

//队头
TYPE head_array_queue(ArrayQueue* queue)
{
	return queue->ptr[queue->head];
}

//队尾
TYPE tail_array_queue(ArrayQueue* queue)
{
	return queue->ptr[(queue->tail+queue->cal-1)%queue->cal];
}

//数量
size_t size_array_queue(ArrayQueue* queue)
{
	return (queue->tail+queue->cal-queue->head)%queue->cal;
}

int main(int argc,const char* argv[])
{
	ArrayQueue* queue=creat_array_queue(10);
	for(int i=0; i<10; i++)
	{
		push_array_queue(queue,rand()%100);
		printf("%d ",tail_array_queue(queue));
		printf("num=%d\n",size_array_queue(queue));
	}
	printf("---------------\n");
	while(!empty_array_queue(queue))
	{
		printf("%d ",head_array_queue(queue));
		printf("num=%d\n",size_array_queue(queue));
		pop_array_queue(queue);
	}
}

            注意问题1:

                由一维数组组成,对头位置head+队尾位置tail表示,如果入队则tail+1,出队则head+1,为了让队列可以循环使用,我们把队列看作一个环,因此每次+1操作都对队列容量取余

                    tail=(tail+1)%cal

                    head=(head+1)%cal

            注意问题2:

                为了解决判断对空、队满条件相同的问题,额外多申请一个容量但不使用,此时:

                    判断对空条件:head == tail

                    判断队满条件:(tail+1)%cal==head

                    顺序队列元素数量:

                    (tail+cal-head)%cal

                还可以多加一个数据项,表示队列中的元素数量,也可以解决该问题,还不需要多少申请一个容量,但是是非常规的解决方法,不常考

        链式队列:

            由若干个节点组成

            数据项:

                对头指针

                队尾指针

                节点数量

            运算:

                创建、销毁、入队、出队、队空、查看对头、队尾、数量

#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#define TYPE int
//设计单链表的节点
typedef struct Node
{
	TYPE data;//节点的数据域
	struct Node* next;//节点的指针域
}Node;

//创建节点
Node* creat_node(TYPE data)
{
	//分配存储节点的内存
	Node* node=malloc(sizeof(Node));
	node->data=data;
	node->next=NULL;
	return node;
}

//链式队列
typedef struct ListQueue
{
	Node* head;
	Node* tail;
	size_t cnt;
}ListQueue;

//创建
ListQueue* creat_list_queue(void)
{
	ListQueue* queue=malloc(sizeof(ListQueue));
	queue->head = NULL;
	queue->tail = NULL;
	queue->cnt=0;
	return queue;
}

//队空
bool empty_list_queue(ListQueue* queue)
{
	return 0 == queue->cnt;
}

//入队
void push_list_queue(ListQueue* queue,TYPE val)
{
	Node* node=creat_node(val);
	if(empty_list_queue(queue))
	{
		queue->head = node;
		queue->tail = node;
	}
	else
	{
		queue->tail->next = node;
		queue->tail = node;
	}
	queue->cnt++;
}

//出队
bool pop_list_queue(ListQueue* queue)
{
	if(empty_list_queue(queue)) return false;
	Node* temp = queue->head;
	queue->head = temp->next;
	free(temp);
	queue->cnt--;
	if(empty_list_queue(queue)) queue->tail=NULL;
	return true;
}

//队头
TYPE head_list_queue(ListQueue* queue)
{
	return queue->head->data;
}

//队尾
TYPE tail_list_queue(ListQueue* queue)
{
	return queue->tail->data;
}

//数量
size_t size_list_queue(ListQueue* queue)
{
	return queue->cnt;
}

//销毁
void destroy_list_queue(ListQueue* queue)
{
	while(pop_list_queue(queue));
	free(queue);
}

int main(int argc,const char* argv[])
{
	ListQueue* queue = creat_list_queue();
	for(int i=0; i<10; i++)
	{
		push_list_queue(queue,rand()%100);
		printf("tail:%d size:%d\n",tail_list_queue(queue),size_list_queue(queue));
	}
	printf("----------------\n");
	while(!empty_list_queue(queue))
	{
		printf("head:%d size:%d\n",head_list_queue(queue),size_list_queue(queue));
		pop_list_queue(queue);
	}
	destroy_list_queue(queue);
	queue=NULL;
}

        队列应用:

            1、消息队列

            2、树的层序遍历

            3、图的广度优先遍历

            4、封装线程池、数据池

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值