数据结构【栈和队列】

目录

概念与结构

栈的实现

栈的数据

栈的初始化

入栈

出栈

取栈顶元素

获取有效个数

栈的销毁

队列

概念与结构

队列的实现

队列的数据

初始化队列

入队列

出队列

取队头数据

取队尾数据

获取有效个数

队列销毁

栈的代码

stack.h

stack.c

test.c

队列的代码

Queue.h

Queue.c

test.c


概念与结构

栈:⼀种特殊的线性表,其只允许在固定的⼀端进⾏插⼊和删除元素操作。进⾏数据插⼊和删除操作 的⼀端称为栈顶,另⼀端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。

压栈:栈的插⼊操作叫做进栈/压栈/⼊栈,⼊数据在栈顶。

出栈:栈的删除操作叫做出栈。出数据也在栈顶。

栈底层结构选型。

栈的实现⼀般可以使⽤数组或者链表实现,相对⽽⾔数组的结构实现更优⼀些。因为数组在尾上插⼊ 数据的代价⽐较⼩。

栈的实现

栈我们用顺序表来实现

栈的数据

arr就是数组,给arr申请空间后就是数组了。

空间就是有多少个空间。

栈顶是用来进栈和出栈的。

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int data;
typedef struct stack
{
	data* arr;//存放数值
	int koj;  //空间
	int top;  //栈顶
}stack;

栈的初始化
cpp 复制代码
//初始化
void stack_csh(stack* r);

把arr置为空。

把koj和栈顶置为0。

cpp 复制代码
//初始化
void stack_csh(stack* r)
{
	assert(r);
	r->arr = NULL;
	r->koj = r->top = 0;
}

入栈
cpp 复制代码
//入栈
void stack_push(stack* r, data x);

思路:先判断空间够不够,不够就2倍增容。

够的话,在栈顶的位置插入数据x。

cpp 复制代码
//入栈
void stack_push(stack* r, data x)
{
	assert(r);
	//空间大小等于栈顶,就说明空间不够
	if (r->koj == r->top)
	{
		int koj1 = r->koj == 0 ? 4 : 2 * r->koj;
		stack* tab = (stack*)realloc(r->arr, sizeof(stack));
		if (tab == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//把新申请的空间给r
		r->arr = tab;
		r->koj = koj1;
	}
	//空间够直接入栈
	r->arr[r->top] = x;
	r->top++;
}

cpp 复制代码
void p()
{
	stack add;
	//初始化栈
	stack_csh(&add);
	//入栈
	stack_push(&add,1);
	stack_push(&add,2);
	stack_push(&add,3);
	stack_push(&add,4);
}

int main()
{
	p();
	return 0;
}

出栈
cpp 复制代码
//布尔类型
bool buer(stack* r);

//出栈
void stack_pop(stack* r);

布尔类型,栈顶为0返回真,不为0返回假

cpp 复制代码
//布尔类型
bool buer(stack* r)
{
	assert(r);
	return r->top == 0;
}

这里布尔类型接收真,假,这个逻辑非!把真变假,把假变真。

栈的删除操作叫做出栈。

我们只需要让,栈顶减减就行了

cpp 复制代码
//出栈
void stack_pop(stack* r)
{
	assert(r);
	//布尔类型
	assert(!buer(r));
	r->top--;
}

出栈我们可以用循环来出栈,也可以用4条来出栈。


取栈顶元素
cpp 复制代码
//取栈顶
data stack_top(stack* r);


arr数组的栈顶减1这个位置就可以拿到4。

cpp 复制代码
//取出栈顶
data stack_top(stack* r)
{
	assert(r);
	assert(!buer(r));
	return r->arr[r->top - 1];
}

取出栈顶的数据赋值给tab,然后打印出来。然后出栈

cpp 复制代码
	while (!buer(&add))
	{
		//取出栈顶数据
		data tab = stack_top(&add);
		printf("%d ", tab);

		//出栈
		stack_pop(&add);

	}

获取有效个数
cpp 复制代码
//获取有效个数
data stack_size(stack* r);

我们直接返回top就行了。

cpp 复制代码
//有效个数
data stack_size(stack* r)
{
	assert(r);
	return r->top;
}

当前有效个数是4,循环出栈后,有效个数是0


栈的销毁
cpp 复制代码
//销毁
void xiaoh(stack* r);

判断arr这个空间是不是空,不是空释放arr空间,

koj和top赋值为0。

cpp 复制代码
//销毁
void xiaoh(stack* r)
{
	assert(r);
	if (r->arr != NULL)
	{
		free(r->arr);
	}
	r->arr = NULL;
	r->koj = r->top = 0;
}

队列

概念与结构

概念:只允许在⼀端进⾏插⼊数据操作,在另⼀端进⾏删除数据操作的特殊线性表,队列具有先进先 出FIFO(First In First Out)

⼊队列:进⾏插⼊操作的⼀端称为队尾

出队列:进⾏删除操作的⼀端称为队头

队列底层结构选型

队列也可以数组和链表的结构实现,使⽤链表的结构实现更优⼀些,因为如果使⽤数组的结构,出队 列在数组头上出数据,效率会⽐较低。


队列的实现

创建3个文件,test.c测试文件,Queue.h头文件,Queue.c函数文件


队列的数据
cpp 复制代码
typedef int data;
typedef struct queuedata//单链表
{
	data arr;//存放的数据
	struct queuedata* p;//指向下一个节点
}queuedata;

typedef struct Queue
{
	queuedata* to; //队头------单链表的 头节点
	queuedata* wei;//队尾------单链表的 尾节点
	int size; //有效个数
}Queue;

初始化队列
cpp 复制代码
//初始化
void csh(Queue* r);

我们只需要把队头和队尾置为NULL,有效个数给0。

cpp 复制代码
//初始化
void csh(Queue* r)
{
	assert(r);
	r->to = r->wei = NULL;
	r->size = 0;
}


入队列

入队列要从队尾进入

cpp 复制代码
//入队,队尾
void dui_wei(Queue* r,data x);

思路:

1.申请一个单链表的空间,把x给新申请的空间,

2.判断队尾是不是空,是空当前链表里没有数据,所以让队头和队尾指向新申请的空间,

3.不是空,这个和单链表的尾插差不多,队尾的p指向新申请的空间,

有效个数加1

cpp 复制代码
//入队尾
void dui_wei(Queue* r,data x)
{
	assert(r);
	//申请单链表空间
	queuedata* tab = (queuedata*)malloc(sizeof(queuedata));
	if (tab == NULL)
	{
		perror("malloc");
		exit(1);
	}
	//把x赋值给新申请空间的arr
	tab->arr = x;
	tab->p = NULL;

	//入队
	//判断队尾是不是空
	if (r->wei == NULL)
	{
		//是空,队头队尾指向新申请的空间
		r->to = r->wei = tab;
	}
	else//不是空
	{
		//队尾p指向新申请的空间
		r->wei->p = tab;
		//队尾走到新申请的空间
		r->wei = r->wei->p;
	}
	//有效个数加1
	r->size++;
}

我们可以看到插入了4个数据1,2,3,4,有效个数是4

cpp 复制代码
void p()
{
	Queue add;
	//初始化
	csh(&add);
	//入队,尾
	dui_wei(&add, 1);
	dui_wei(&add, 2);
	dui_wei(&add, 3);
	dui_wei(&add, 4);

}

int main()
{
	p();
	return 0;
}

出队列

出队列:进⾏删除操作的⼀端称为队头

出队列要从队头出,


出队列,我们要用布尔类型,判断链表是不是空,是空不能出队列,报错。

cpp 复制代码
//布尔类型
bool buer(Queue* r);
//出队列
void dui_to(Queue* r);

布尔判断队头是不是等于空,是返回真,不是返回假。

cpp 复制代码
//布尔类型
bool buer(Queue* r)
{
	assert(r);
	return r->to == NULL;
}

思路:判断队头等于队尾,说明只有一个节点。直接释放就行了,

不等于说明有链表里有空间,把头节点的下一个节点给tab,释放头节点,再把tab给头节点。

有效个数减1

cpp 复制代码
//出队,头
void dui_to(Queue* r)
{
	assert(r);
	//布尔类型,!把真变假,把假变真
	assert(!buer(r));
	//判断队头等于队尾,就说明只有一个节点
	if (r->to == r->wei)
	{
		//直接释放空间
		free(r->to);
		//把队头和队尾置为空
		r->to = r->wei = NULL;
	}
	else
	{
		//把队头的下一个节点给tab
		queuedata* tab = r->to->p;
		//释放当前队头节点
		free(r->to);
		//把tab节点给队头
		r->to = tab;
	}
	//有效个数减1
	--r->size;
}

取队头数据
cpp 复制代码
//取队头数据
data qto(Queue* r);

直接返回头节点的数据就行了

cpp 复制代码
//取队头数据
data qto(Queue* r)
{
	assert(r);
	assert(!buer(r));
	return r->to->arr;
}

cpp 复制代码
printf("头:%d\n", qto(&add));

取队尾数据
cpp 复制代码
//取队尾数据
data qwei(Queue* r);

直接返回队尾的数据就行了。

cpp 复制代码
//取尾
data qwei(Queue* r)
{
	assert(r);
	assert(!buer(r));
	return r->wei->arr;
}

cpp 复制代码
printf("尾:%d\n", qwei(&add));

获取有效个数
cpp 复制代码
//有效个数
data size(Queue* r);

cpp 复制代码
//有效个数
data size(Queue* r)
{
	assert(r);
	return r->size;
}

cpp 复制代码
printf("size:%d\n", size(&add));

队列销毁
cpp 复制代码
//销毁
void xiaoh(Queue* r);

把队头给tab,让tab循环销毁单链表,add保存头节点的下一个节点,释放头节点,把add给tab,

把队头和队尾置为NULL,有效个数给0。

cpp 复制代码
//销毁
void xiaoh(Queue* r)
{
	assert(r);
	assert(!buer(r));
	//把队头给tab
	queuedata* tab = r->to;
	//循环销毁单链表
	while (tab != NULL)
	{
		//add保存头节点的下一个节点
		queuedata* add = tab->p;
		//释放头节点
		free(tab);
		//把add给tab
		tab = add;
	}
	//把队头和队尾置为空
	r->to = r->wei = NULL;
	//有效个数赋值为0
	r->size = 0;
}

栈的代码

stack.h
cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int data;
typedef struct stack
{
	data* arr;//存放数值
	int koj;  //空间
	int top;  //栈顶
}stack;

//初始化
void stack_csh(stack* r);
//入栈
void stack_push(stack* r, data x);

//布尔类型
bool buer(stack* r);

//出栈
void stack_pop(stack* r);

//取栈顶
data stack_top(stack* r);

//获取有效个数
data stack_size(stack* r);

//销毁
void xiaoh(stack* r);
stack.c
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"

//初始化
void stack_csh(stack* r)
{
	assert(r);
	r->arr = NULL;
	r->koj = r->top = 0;
}

//入栈
void stack_push(stack* r, data x)
{
	assert(r);
	//空间大小等于栈顶,就说明空间不够
	if (r->koj == r->top)
	{
		int koj1 = r->koj == 0 ? 4 : 2 * r->koj;
		stack* tab = (stack*)realloc(r->arr, sizeof(stack));
		if (tab == NULL)
		{
			perror("realloc");
			exit(1);
		}
		//把新申请的空间给r
		r->arr = tab;
		r->koj = koj1;
	}
	//空间够直接入栈
	r->arr[r->top] = x;
	r->top++;
}

//布尔类型
bool buer(stack* r)
{
	assert(r);
	return r->top == 0;
}

//出栈
void stack_pop(stack* r)
{
	assert(r);
	//布尔类型
	assert(!buer(r));
	r->top--;
}

//取出栈顶
data stack_top(stack* r)
{
	assert(r);
	assert(!buer(r));
	return r->arr[r->top - 1];
}

//有效个数
data stack_size(stack* r)
{
	assert(r);
	return r->top;
}

//销毁
void xiaoh(stack* r)
{
	assert(r);
	if (r->arr != NULL)
	{
		free(r->arr);
	}
	r->arr = NULL;
	r->koj = r->top = 0;
}
test.c
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"


void p()
{
	stack add;
	//初始化栈
	stack_csh(&add);
	//入栈
	stack_push(&add,1);
	stack_push(&add,2);
	stack_push(&add,3);
	stack_push(&add,4);
	//出栈
	/*stack_pop(&add);
	stack_pop(&add);
	stack_pop(&add);
	stack_pop(&add);*/
	printf("size:%d\n", stack_size(&add));

	while (!buer(&add))
	{
		//取出栈顶数据
		data tab = stack_top(&add);
		printf("%d ", tab);

		//出栈
		stack_pop(&add);

	}
	printf("size:%d\n", stack_size(&add));

	//销毁
	xiaoh(&add);
}

int main()
{
	p();
	return 0;
}

队列的代码

Queue.h
cpp 复制代码
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int data;
typedef struct queuedata//单链表
{
	data arr;//存放的数据
	struct queuedata* p;//指向下一个节点
}queuedata;

typedef struct Queue
{
	queuedata* to; //队头------单链表的 头节点
	queuedata* wei;//队尾------单链表的 尾节点
	int size; //有效个数
}Queue;

//初始化
void csh(Queue* r);

//入队,队尾
void dui_wei(Queue* r,data x);

//布尔类型
bool buer(Queue* r);
//出队列
void dui_to(Queue* r);

//取队头数据
data qto(Queue* r);

//取队尾数据
data qwei(Queue* r);

//有效个数
data size(Queue* r);

//销毁
void xiaoh(Queue* r);
Queue.c
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"

//初始化
void csh(Queue* r)
{
	assert(r);
	r->to = r->wei = NULL;
	r->size = 0;
}

//入队尾
void dui_wei(Queue* r,data x)
{
	assert(r);
	//申请单链表空间
	queuedata* tab = (queuedata*)malloc(sizeof(queuedata));
	if (tab == NULL)
	{
		perror("malloc");
		exit(1);
	}
	//把x赋值给新申请空间的arr
	tab->arr = x;
	tab->p = NULL;

	//入队
	//判断队尾是不是空
	if (r->wei == NULL)
	{
		//是空,队头队尾指向新申请的空间
		r->to = r->wei = tab;
	}
	else//不是空
	{
		//队尾p指向新申请的空间
		r->wei->p = tab;
		//队尾走到新申请的空间
		r->wei = r->wei->p;
	}
	//有效个数加1
	r->size++;
}
//布尔类型
bool buer(Queue* r)
{
	assert(r);
	return r->to == NULL;
}

//出队,头
void dui_to(Queue* r)
{
	assert(r);
	//布尔类型,!把真变假,把假变真
	assert(!buer(r));
	//判断队头等于队尾,就说明只有一个节点
	if (r->to == r->wei)
	{
		//直接释放空间
		free(r->to);
		//把队头和队尾置为空
		r->to = r->wei = NULL;
	}
	else
	{
		//把队头的下一个节点给tab
		queuedata* tab = r->to->p;
		//释放当前队头节点
		free(r->to);
		//把tab节点给队头
		r->to = tab;
	}
	//有效个数减1
	--r->size;
}

//取队头数据
data qto(Queue* r)
{
	assert(r);
	assert(!buer(r));
	return r->to->arr;
}

//取尾
data qwei(Queue* r)
{
	assert(r);
	assert(!buer(r));
	return r->wei->arr;
}


//有效个数
data size(Queue* r)
{
	assert(r);
	return r->size;
}

//销毁
void xiaoh(Queue* r)
{
	assert(r);
	assert(!buer(r));
	//把队头给tab
	queuedata* tab = r->to;
	//循环销毁单链表
	while (tab != NULL)
	{
		//add保存头节点的下一个节点
		queuedata* add = tab->p;
		//释放头节点
		free(tab);
		//把add给tab
		tab = add;
	}
	//把队头和队尾置为空
	r->to = r->wei = NULL;
	//有效个数赋值为0
	r->size = 0;
}
test.c
cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include"Queue.h"
void p()
{
	Queue add;
	//初始化
	csh(&add);
	//入队,尾
	dui_wei(&add, 1);
	dui_wei(&add, 2);
	dui_wei(&add, 3);
	dui_wei(&add, 4);

	printf("头:%d\n", qto(&add));


	printf("尾:%d\n", qwei(&add));
	printf("size:%d\n", size(&add));
	//销毁
	xiaoh(&add);
}

int main()
{
	p();
	return 0;
}
相关推荐
~yY…s<#>1 小时前
【刷题17】最小栈、栈的压入弹出、逆波兰表达式
c语言·数据结构·c++·算法·leetcode
XuanRanDev2 小时前
【每日一题】LeetCode - 三数之和
数据结构·算法·leetcode·1024程序员节
代码猪猪傻瓜coding2 小时前
力扣1 两数之和
数据结构·算法·leetcode
EricWang13583 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
我是谁??3 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
南宫生4 小时前
贪心算法习题其三【力扣】【算法学习day.20】
java·数据结构·学习·算法·leetcode·贪心算法
希言JY4 小时前
C字符串 | 字符串处理函数 | 使用 | 原理 | 实现
c语言·开发语言
午言若4 小时前
C语言比较两个字符串是否相同
c语言
weixin_432702265 小时前
代码随想录算法训练营第五十五天|图论理论基础
数据结构·python·算法·深度优先·图论
passer__jw7675 小时前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode