栈和队列(顺序表、单链表形式)

news2024/11/23 16:49:14

栈和队列

    • 栈.顺序表
      • 结构体的设计
      • 栈的初始化
      • 栈的销毁
      • 入栈
      • 出栈
      • 获取栈顶数据
      • 判断栈空
      • 栈中有效元素的个数
        • Stack.h
        • Stack.c
        • test.c
    • 栈.单链表
      • 结构体设计
      • 栈的初始化
      • 栈的销毁
      • 入栈
      • 出栈
      • 获取栈顶元素
      • 判断栈是否为空
      • 获取栈中元素个数
        • Stack.h
        • Stack.c
        • test.c
  • 队列
    • 队列.顺序表
      • 结构体的设计
      • 队列的初始化
      • 队列的销毁
      • 入队
      • 出队
      • 获取队头
      • 获取队尾元素
      • 获取队列有效元素
      • 判断队列是否为空
        • Queue.h
        • Queue.c
        • test.c
    • 队列.单列表
      • 结构体设计
      • 初始化
      • 链表的销毁
      • 入队
      • 出队
      • 获取队头元素
      • 获取队尾元素
      • 获取队列元素个数
      • 判断队列是否为空
        • Queue.h
        • Queue.c
        • test.c
  • 结束语

栈的主要特点:后进先出

在这里插入图片描述

栈顶是动态的,栈底是静态的。即只能从栈顶进,从栈顶出。
还是看不懂,可以想一下弹夹
找了半天只看到这个,后进去的子弹先出来

在这里插入图片描述

栈的存储结构可以是顺序表,也可以是单链表。
不管栈还是队列,操作方面都是基于顺序表和单链表,换而言之,这两个存储结构的基本操作,你必须掌握。操作并不是这一篇博客的重点,重点是思路和分析易错的地方

栈.顺序表

如果选取顺序表,顺序表的优点是尾插,尾删的时间复杂度O(1),所以说栈顶是在尾部。这里是高级货色,是动态版本的顺序表改版,换句话说,你需要对动态内存管理的函数要有了解,特别是realloc。上过热榜的C动态管理

在这里插入图片描述

结构体的设计

将元素类型重命名好处:当元素是其他类型时候,只要改动一行代码就可以了。

typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int sz;
	int top;//栈顶
}Stack;

内存布局
在这里插入图片描述

栈的初始化

这里存在两种设计,栈顶top的初始值是-1还是0。当top ==-1时,top表示栈顶元素,当top == 0时,top表示栈顶下一个元素,这里采用的top == 0

在这里插入图片描述

刚开始a = NULL,是通过下面入栈操作去开辟空间,你也可以直接先申请空间,再去扩容

void StackInit(Stack* pst)
{
	pst->a = NULL;
	pst->top = 0;//指向栈顶元素的下一个
	pst->sz = 0;
}

栈的销毁

将堆区的空间释放并且置为NULL

void StackDestroy(Stack* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->sz = 0;
	pst->top = 0;
}

入栈

C动态内存管理

三个注意事项:
①:realloc:当传入NULL功能和malloc一样。
②:realloc:开辟空间的大小 = 扩容大小+原来空间大小
③: memset:来初始化,要注意起始位置。
assert的作用:如果pst是空指针就报错。

在这里插入图片描述

//添加空间
void AddSpace(Stack* pst)
{
	STDataType* p = (STDataType*)realloc(pst->a, \
		sizeof(STDataType) * (pst->sz + 3));
	if (NULL == p)
	{
		perror("AddSpace::\n");
	}
	
	memset(p + pst->sz, 0, sizeof(STDataType) * 3);
	pst->a = p;
	pst->sz += 3;
}
//入栈
void StackPush(Stack* pst, STDataType x)
{
	assert(pst);
	if (pst->top >= pst->sz)
	{
		AddSpace(pst);
	}
	pst->a[pst->top] = x;//top是栈顶元素的下一个
	pst->top++;
}

出栈

除了assert(pst);还要考虑当栈空的时候,还能出栈吗?肯定是不能,所以assert(pst->top > 0);暴力检测。

void StackPop(Stack* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}

获取栈顶数据

注意top是栈顶的下一个元素,所以需要-1

STDataType TopPop(Stack* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}

判断栈空

bool类型是用来判断真假的,只存在两个值truefalsetrue == 1表示真,false == 0表示假。栈非空为真,栈空为假。

bool StackEmpty(Stack* pst)
{
	assert(pst);
	return  !(0 == pst->top);
}

栈中有效元素的个数

int StackSize(Stack* pst)
{
	assert(pst);
	return pst->top;
}

Stack.h

#pragma once
#include<stdbool.h>
#include<stdlib.h>
#include<stdio.h>
#include<assert.h>
#include<string.h>
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int sz;
	int top;//栈顶
}Stack;

//对栈初始化
void StackInit(Stack* pst);
//销毁
void StackDestroy(Stack* pst);
//压栈
void StackPush(Stack* pst, STDataType x);
//出栈
void StackPop(Stack* pst);
//弹出栈顶元素
STDataType StackTop(Stack* pst);
//判断栈空
bool StackEmpty(Stack* pst);
//计算栈中的元素
int StackSize(Stack* pst);

Stack.c

#include"Stack.h"
//栈的初始化
void StackInit(Stack* pst)
{
	pst->a = NULL;
	pst->top = 0;//指向栈顶元素的下一个
	pst->sz = 0;
}
//栈的销毁
void StackDestroy(Stack* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->sz = 0;
	pst->top = 0;
}
//添加空间
void AddSpace(Stack* pst)
{
	STDataType* p = (STDataType*)realloc(pst->a, \
		sizeof(STDataType) * (pst->sz + 3));
	if (NULL == p)
	{
		perror("AddSpace::\n");
	}
	
	memset(p + pst->sz, 0, sizeof(STDataType) * 3);
	pst->a = p;
	pst->sz += 3;
}
//压栈
void StackPush(Stack* pst, STDataType x)
{
	assert(pst);
	if (pst->top >= pst->sz)
	{
		AddSpace(pst);
	}
	pst->a[pst->top] = x;//top是栈顶元素的下一个
	pst->top++;
}
//出栈
void StackPop(Stack* pst)
{
	assert(pst);
	assert(pst->top > 0);
	pst->top--;
}
//获取栈顶数据
STDataType TopPop(Stack* pst)
{
	assert(pst);
	assert(pst->top > 0);
	return pst->a[pst->top - 1];
}
//判断栈空
bool StackEmpty(Stack* pst)
{
	assert(pst);
	return  !(0 == pst->top);
}
//栈中的大小
int StackSize(Stack* pst)
{
	assert(pst);
	return pst->top;
}

test.c

#include"Stack.h"

int main()
{
	Stack st;
	StackInit(&st);
	for (int i = 1; i < 6; i++)
	{
		StackPush(&st, i);
	}
	int ret = TopPop(&st);
	printf("第一次取栈顶元素:%d \n", ret);
	for (int i = 1; i < 3; i++)
	{
		StackPop(&st);
	}

	ret = TopPop(&st);
	printf("第二次取栈顶元素:%d \n", ret);

	int sz = StackSize(&st);
	printf("总大小:%d\n", sz);
	
	if (StackEmpty(&st))
		printf("栈非空\n");
	else
		printf("栈空\n");

	StackDestroy(&st);
	return 0;
}

在这里插入图片描述

栈.单链表

单链表适合头插,头插的时间复杂度为O(1),换句话说,栈顶应该指向链表第一个节点,把栈顶当作头指针使用即可。

结构体设计

这样设计以后,一个好处:上面顺序表是对应,意思和顺序表的Stack.cStack.h更换,主函数不变,运行结果还是一样的效果。另一个好处,结构分明。

typedef int STDataType;
typedef struct StNode
{
	STDataType data;
	struct StNode* next;
}StNode;
typedef struct Stack
{
	StNode* top;//栈顶
	StNode* bottom;
}Stack;

在这里插入图片描述

栈的初始化

void StackInit(Stack* st)
{
	assert(st);
	st->top = NULL;
	st->bottom = NULL;
}

栈的销毁

销毁完成后,指针需要置为NULL

void StackDestroy(Stack* st)
{
	assert(st);
	StNode* p = st->top;
	while (p)
	{
		StNode* tmp = p;
		p = p->next;
		free(tmp);
	}
	st->bottom = NULL;
	st->top = NULL;
}

入栈

将开辟节点和初始化节点,封装成函数,看起来更舒服一点,用起来也很方便。
这里是没有哨兵位头节点,当一开始指针指向NULL的时候要特殊处理。

//开辟节点
StNode* AollocStNode(STDataType x)
{
	StNode* newnode = (StNode*)malloc(sizeof(StNode));
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}
//入栈
void StackPush(Stack* st, STDataType x)
{
	assert(st);
	StNode* newnode = AollocStNode(x);
	if (st->bottom == NULL)
		st->bottom = newnode;
	//头插
	if (st->top == NULL)
		st->top = newnode;
	else
	{
		newnode->next = st->top;
		st->top = newnode;
	}
}

出栈

出栈操作就是释放第一个节点,然后让top指向下一个节点
当最后一个节点也出栈了,别忘记bottom也要置为NULL
栈空的时候,也不能出栈,因此assert(st->top)暴力检测一下。

void StackPop(Stack* st)
{
	assert(st);
	assert(st->top);
	StNode* p = st->top;
	st->top = p->next;
	free(p);
	if (st->top == NULL)
		st->bottom = NULL;
}

获取栈顶元素

栈空了不能获取,因此也要assert检查一下。

STDataType TopPop(Stack* st)
{
	assert(st);
	assert(st->top);
	return st->top->data;
}

判断栈是否为空

栈空返回false,栈非空返回true

bool StackEmpty(Stack* st)
{
	assert(st);
	return !(st->top == NULL);
}

获取栈中元素个数

可别直接拿top去循环,不然top指向会改变,找不到原来的第一个节点了,需要一个中间变量。

int StackSize(Stack* st)
{
	assert(st);
	int count = 0;
	StNode* p = st->top;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

Stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDataType;
typedef struct StNode
{
	STDataType data;
	struct StNode* next;
}StNode;
typedef struct Stack
{
	StNode* top;//栈顶
	StNode* bottom;
}Stack;

//初始化
void StackInit(Stack* st);
//销毁
void StackDestroy(Stack* st);
//压栈
void StackPush(Stack* st,STDataType x);
//出栈
void StackPop(Stack* st);
//弹出栈顶元素
STDataType TopPop(Stack* st);
//判断栈空
bool StackEmpty(Stack* st);
//判断栈中有效元素
int StackSize(Stack* st);

Stack.c

#include"Stack.h"
//初始化
void StackInit(Stack* st)
{
	assert(st);
	st->top = NULL;
	st->bottom = NULL;
}
//销毁
void StackDestroy(Stack* st)
{
	assert(st);
	StNode* p = st->top;
	while (p)
	{
		StNode* tmp = p;
		p = p->next;
		free(tmp);
	}
	st->bottom = NULL;
	st->top = NULL;
}
//开辟节点
StNode* AollocStNode(STDataType x)
{
	StNode* newnode = (StNode*)malloc(sizeof(StNode));
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}
//压栈
void StackPush(Stack* st, STDataType x)
{
	assert(st);
	StNode* newnode = AollocStNode(x);
	if (st->bottom == NULL)
		st->bottom = newnode;
	if (st->top == NULL)
		st->top = newnode;
	else
	{
		newnode->next = st->top;
		st->top = newnode;
	}
}

//出栈
void StackPop(Stack* st)
{
	assert(st);
	assert(st->top);
	StNode* p = st->top;
	st->top = p->next;
	free(p);
	if (st->top == NULL)
		st->bottom = NULL;
}
//获取栈顶元素
STDataType TopPop(Stack* st)
{
	assert(st);
	assert(st->top);
	return st->top->data;
}
//判断栈是否为空
bool StackEmpty(Stack* st)
{
	assert(st);
	return !(st->top == NULL);
}
//返回有效的元素个数
int StackSize(Stack* st)
{
	assert(st);
	int count = 0;
	StNode* p = st->top;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

test.c

#include"Stack.h"

int main()
{
	Stack st;
	StackInit(&st);
	for (int i = 1; i < 6; i++)
	{
		StackPush(&st, i);
	}
	printf("第一次获取栈顶元素%d \n", TopPop(&st));
	StackPop(&st);
	printf("第二次获取栈顶元素%d \n", TopPop(&st));

	printf("栈中有效元素%d \n", StackSize(&st));
	
	if (StackEmpty(&st))
		printf("栈非空\n");
	else
		printf("栈空\n");

	StackDestroy(&st);
	return 0;
}

在这里插入图片描述

队列

队列的主要特点:先进先出。

在这里插入图片描述

队列.顺序表

下面哪一种更好呢?第一种。比如1,2,3,4要入队,第一种看起来更直接,操作也方便,只要尾插就行。而第二种,需要前插时间复杂度就大了。我用的是第一种。

在这里插入图片描述

在这里插入图片描述

结构体的设计

这就和栈那里的设计相差无几了.

typedef int QDataType;
typedef struct Queue
{
	QDataType* a;
	int capacity;
	int rear;//队尾
	//队头下标为0处
}Queue;

队列的初始化

void QueueInit(Queue* q)
{
	q->a = NULL;
	q->capacity = 0;
	q->rear = 0;//也存在两种初始化-1和0
	//0:队尾的下一个元素
}

队列的销毁

void QueueDestroy(Queue* q)
{
	assert(q);
	free(q->a);
	q->a = NULL;
	q->capacity = 0;
	q->rear = 0;
}

入队

单个\是续行符,同样是三个注意事项,不再赘述。

void AddSpace(Queue* q)
{
	QDataType* p = (QDataType*)realloc(q->a, \
		sizeof(QDataType) * (3 + q->capacity));
	if (NULL == p)
		perror("AddSpace::\n");
	memset(p + q->capacity, 0, sizeof(QDataType) * 3);
	q->a = p;
	q->capacity += 3;
}
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	if (q->rear >= q->capacity)
		AddSpace(q);
	q->a[q->rear] = x;
	q->rear++;
}

出队

队列为空的时候不能出队,因此加上assert(q->rear > 0)检测

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	for (int i = 0; i < q->rear-1; i++)
	{
		q->a[i] = q->a[i + 1];
	}
	q->rear--;
}

获取队头

队列为空时,不可获取

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	return q->a[0];
}

获取队尾元素

QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	return q->a[q->rear - 1];
}

获取队列有效元素

int QueueSize(Queue* q)
{
	assert(q);
	return q->rear;
}

判断队列是否为空

队列为空返回false,队列非空返回true

bool QueueEmpty(Queue* q)
{
	assert(q);
	return   !(0 == q->rear);
}

Queue.h

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

typedef int QDataType;

typedef struct Queue
{
	QDataType* a;
	int capacity;
	int rear;//队尾
	//队头下标为0处
}Queue;
//初始化
void QueueInit(Queue* q);
//入队
void QueuePush(Queue* q, QDataType x);
//出队
void QueuePop(Queue* q);
//获取队头元素
QDataType QueueFront(Queue* q);
//获取队尾元素
QDataType QueueBack(Queue* q);
//判断队空
bool QueueEmpty(Queue* q);
//获取队列有效元素
int QueueSize(Queue* q);

Queue.c

#include"Queue.h"

//初始化
void QueueInit(Queue* q)
{
	q->a = NULL;
	q->capacity = 0;
	q->rear = 0;//也存在两种初始化-1和0
	//队尾的下一个元素
}
void QueueDestroy(Queue* q)
{
	assert(q);
	free(q->a);
	q->a = NULL;
	q->capacity = 0;
	q->rear = 0;
}
//入队
void AddSpace(Queue* q)
{
	QDataType* p = (QDataType*)realloc(q->a, \
		sizeof(QDataType) * (3 + q->capacity));
	if (NULL == p)
		perror("AddSpace::\n");
	memset(p + q->capacity, 0, sizeof(QDataType) * 3);
	q->a = p;
	q->capacity += 3;
}
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	if (q->rear >= q->capacity)
		AddSpace(q);
	q->a[q->rear] = x;
	q->rear++;
}

//出队
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	for (int i = 0; i < q->rear-1; i++)
	{
		q->a[i] = q->a[i + 1];
	}
	q->rear--;
}
//获取队头
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	return q->a[0];
}
//获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear > 0);
	return q->a[q->rear - 1];
}
//获取队列有效元素
int QueueSize(Queue* q)
{
	assert(q);
	return q->rear;
}
//判断队列是否为空
bool QueueEmpty(Queue* q)
{
	assert(q);
	return   !(0 == q->rear);
}

test.c

#include"Queue.h"

int main()
{
	Queue q;
	QueueInit(&q);
	for (int i = 1; i < 5; i++)
	{
		QueuePush(&q, i);
	}
	printf("第一次获取队头元素%d \n", QueueFront(&q));
	printf("第一次获取队尾元素%d \n", QueueBack(&q));
	QueuePop(&q);
	QueuePop(&q);

	printf("第二次获取队头元素%d \n", QueueFront(&q));
	printf("第二次获取队尾元素%d \n", QueueBack(&q));
	if (QueueEmpty(&q))
		printf("队列非空\n");
	else
		printf("队列空\n");

	printf("队列中有效个数%d \n", QueueSize(&q));
	QueueDestroy(&q);
	return 0;
}

在这里插入图片描述

队列.单列表

队列用单链表去写才是最好的,设计巧妙的话,入队和出队时间复杂度可以O(1)。
用带哨兵位头节点的双向循环链表,出队和入队的时间复杂度是O(1),可以尝试写一写
下面这种形式,入队和出队能时间复杂度为O(1),入队:通过rear进行尾插,因为rear指向链表尾部。出队:用front进行头删。
1,2,3,4入队

在这里插入图片描述

在这里插入图片描述

下面这种,入队只能头插O(1),出队尾删O(n)。1,2,3,4入队

在这里插入图片描述

结构体设计

Stack设计是差不多的

typedef int QDataType;
typedef struct QListNode
{
	QDataType data;
	struct QListNode* next;

}QNode;
typedef struct Queue
{
	QNode* front;
	QNode* rear;
}Queue;

初始化

void QueueInit(Queue* q)
{
	assert(q);
	q->front = NULL;//队头是链表的头
	q->rear = NULL;//队尾是链表的尾
}

链表的销毁

void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* p = q->front;
	while (p)
	{
		QNode* tmp = p;
		p = p->next;
		free(tmp);
	}
	q->front = NULL;
	q->rear = NULL;
}

入队

入队是尾插。需要注意,第一次入队的时候,两个指针都是NULL,需要特殊处理一下。

//开辟节点
QNode* AollocQNode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
//入队
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = AollocQNode(x);

	if (NULL == q->front)
		q->front = newnode;
	if (NULL == q->rear)
		q->rear = newnode;
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
}

出队

头删操作,当删除最后一个节点的时候,不能忘记rear也要置为NULL

void QueuePop(Queue* q)
{
	assert(q);
	assert(q->front);
	QNode* p = q->front;//头指针
	q->front = q->front->next;
	free(p);
	if (q->front == NULL)
		q->rear = NULL;
}

获取队头元素

QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->front);
	return q->front->data;
}

获取队尾元素

QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear);
	return q->rear->data;
}

获取队列元素个数

需要中间变量,去遍历队列,不能改变front的指向

int QueueSize(Queue* q)
{
	assert(q);
	QNode* p = q->front;
	int count = 0;
	while (p)
	{
		p = p->next;
		count++;
	}
	return count;
}

判断队列是否为空

bool QueueEmpty(Queue* q)
{
	assert(q);
	return !(q->rear == NULL);
}

Queue.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int QDataType;
// 链式结构:表示队列 
typedef struct QListNode
{
	QDataType data;
	struct QListNode* next;

}QNode;

// 队列的结构 
typedef struct Queue
{
	QNode* front;
	QNode* rear;
}Queue;

//初始化
void QueueInit(Queue* q);
//销毁
void QueueDestroy(Queue* q);
//入队
void QueuePush(Queue* q, QDataType x);
//出队
void QueuePop(Queue* q);
//获取队头元素
QDataType QueueFront(Queue* q);
//获取队尾元素
QDataType QueueBack(Queue* q);
//获取队列中有效元素
int QueueSize(Queue* q);
//判断队列是否为空
bool QueueEmpty(Queue* q);


Queue.c

#include"Queue.h"

//初始化
void QueueInit(Queue* q)
{
	assert(q);
	q->front = NULL;//队头是链表的尾
	q->rear = NULL;//队尾是链表的头
}
//销毁
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* p = q->front;
	while (p)
	{
		QNode* tmp = p;
		p = p->next;
		free(tmp);
	}
	q->front = NULL;
	q->rear = NULL;
}
//开辟节点
QNode* AollocQNode(QDataType x)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}
//入队
void QueuePush(Queue* q, QDataType x)
{
	assert(q);
	QNode* newnode = AollocQNode(x);

	if (NULL == q->front)
		q->front = newnode;
	if (NULL == q->rear)
		q->rear = newnode;
	else
	{
		q->rear->next = newnode;
		q->rear = newnode;
	}
}
//出队
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->front);
	QNode* p = q->front;//头指针
	q->front = q->front->next;
	free(p);
	if (q->front == NULL)
		q->rear = NULL;
}


//获取队头元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(q->front);
	return q->front->data;
}
//获取队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(q->rear);
	return q->rear->data;
}
int QueueSize(Queue* q)
{
	assert(q);
	QNode* p = q->front;
	int count = 0;
	while (p)
	{
		p = p->next;
		count++;
	}
	return count;
}
bool QueueEmpty(Queue* q)
{
	assert(q);
	return !(q->rear == NULL);
}

test.c

#include"Queue.h"

int main()
{
	Queue q;
	QueueInit(&q);
	for (int i = 1; i < 6; i++)
	{
		QueuePush(&q, i);
	}
	int ret = QueueFront(&q);
	printf("第一次取队头元素:%d\n", ret);
	ret = QueueBack(&q);
	printf("第一次取队尾元素:%d\n", ret);
	QueuePop(&q);
	ret = QueueFront(&q);
	printf("第二次取队头元素:%d\n", ret);
	ret = QueueBack(&q);
	printf("第二次取队尾元素:%d\n", ret);

	ret = QueueSize(&q);
	printf("队列中有效元素:%d \n", ret);

	if (QueueEmpty(&q))
		printf("队列非空\n");
	else
		printf("队列空\n");

	//for (int i = 1; i < 5; i++)
	//{
	//	QueuePop(&q);
	//}

	if (QueueEmpty(&q))
		printf("队列非空\n");
	else
		printf("队列空\n");

	QueueDestroy(&q);
	return 0;
}

结束语

还等什么,还不打开vs,埋头苦干起来,要是没看的太明白,建议先熟练顺序表和单链表的基本操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/5055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

学生HTML个人网页作业作品 简单的IT技术个人简历模板html下载 简单个人网页设计作业 静态HTML个人博客主页

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

Python老手也会犯的20个新手级错误

Python编码时应避免的常见错误 编程&#xff08;不仅Python&#xff0c;也包括其它编程语言&#xff09;最好的一点是&#xff0c;有多种方法来实现同一解决方案。 使用不同的方法来达到相同的结果&#xff08;图像由作者绘制&#xff09; 由于下述原因&#xff0c;有些方法会比…

几款很好看的爱心表白代码(动态)

分享几款好看的爱心表白代码❤️爱心代码❤️&#xff08;C语言&#xff09;❤️流动爱心❤️&#xff08;htmlcssjs&#xff09;❤️线条爱心❤️&#xff08;htmlcssjs&#xff09;❤️biu表白爱心❤️&#xff08;htmlcssjs&#xff09;❤️matlab爱心函数❤️&#xff08;需…

Java类和对象(一)

&#x1f380;作者&#xff1a;爱塔居的博客_CSDN博客-领域博主 &#x1f32d;专栏&#xff1a;JavaSE &#x1f367;作者简介&#xff1a;大三学生&#xff0c;想要努力地变得更好&#xff01; 附上一张可可爱爱的猫猫图~ &#x1f353;&#x1f353;&#x1f353;&#x1f35…

论文学习——多度量水文时间序列相似性分析

文章目录摘要1 研究背景1.1 主要研究内容1.2 研究背景1.3 启发2 基于改进BORDA投票法的多度量水文时间序列相似性分析2.1 研究方法2.2 BORDA投票法的改进2.2.1 BORDA 的缺点2.2.2 改进的BORDA投票法3 实验验证与分析3.1 实验数据3.2 实验结果分析4 结语多度量组合可以提高相似性…

关于使用GB28181协议实现与大华摄像机的语音对讲功能小记

目前只测试了与大华摄像机的语音对讲功能&#xff0c;在此记录下对接工程中遇到的问题和收获。 首先我们需要理清下思路&#xff1a; 第一步要熟悉语音对讲的协议流程&#xff0c;下图为国标28181中的参考图&#xff1a; 这里我们可以简化下流程&#xff0c;只参与与摄像机的…

计算机网络第二章知识点回顾(自顶向下)

第二章知识点回顾1.应用层1.1网络应用架构1.1.1客户-服务器架构1.1.2P2P架构1.1.3两种架构的对比1.2不同终端上的进程通信1.3进程与网络的接口&#xff1a;套接字1.4进程如何标识自己&#xff1a;进程编址1.5因特网提供的传输服务小结1.6Web应用画像1.7 HTTP协议1.7.1HTTP使用T…

大数据技术基础实验十三:Kafka实验——订阅推送示例

大数据技术基础实验十三&#xff1a;Kafka实验——订阅推送示例 文章目录大数据技术基础实验十三&#xff1a;Kafka实验——订阅推送示例一、前言二、实验目的三、实验要求四、实验原理1、Kafka简介2、Kafka使用场景五、实验步骤1、配置各服务器之间的免密登录2、安装ZooKeeper…

【C++】优先级队列 priority_queue的使用模拟实现 | 仿函数

&#x1f308;欢迎来到C专栏~~优先级队列的使用 & 模拟实现 (꒪ꇴ꒪(꒪ꇴ꒪ )&#x1f423;,我是Scort目前状态&#xff1a;大三非科班啃C中&#x1f30d;博客主页&#xff1a;张小姐的猫~江湖背景快上车&#x1f698;&#xff0c;握好方向盘跟我有一起打天下嘞&#xff01…

聚乙二醇衍生物MAL-PEG-NH2,Maleimide-PEG-amine,CAS:1207751-12-9​

英文&#xff1a;MAL-PEG-NH2&#xff0c;Maleimide-PEG-amine 中文&#xff1a;马来酰亚胺-聚乙二醇-氨基 2、CAS编号&#xff1a;1207751-12-9 3、所属分类&#xff1a;Amine PEG Maleimide PEG 4、分子量&#xff1a;可定制&#xff0c;5000、2000、3400、20000、10000、…

【附源码】Python计算机毕业设计汽车租赁网站

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

eBPF学习笔记(一)—— eBPF介绍内核编译

eBPF学习笔记&#xff08;一&#xff09;—— eBPF介绍&内核编译eBPF介绍eBPF基础代码验证即时编译eBPF开发工具BCCbpftracelibbpf C/C库eBPF Go库内核编译查看内核版本下载内核源码安装依赖项安装最新版llvm和clang配置内核编译内核BPF示例程序常见问题问题一&#xff1a;…

C++ 堆、大顶堆、小顶堆、堆排序

目录一、什么是堆&#xff1f;1.1 大顶堆1.2 小顶堆1.3 自定义greater1.4 堆索引的特点1.5 堆操作添加元素删除最大元素检查序列是否是堆检查部分序列为堆对堆进行排序升序降序问题&#xff1a;sort()和sort_heap()有什么区别二、排序算法&#xff1a;堆排序2.1 堆排序原理创建…

Bootstrap框架(全)

Bootstrap中文网&#xff1a;点我直达 Bootstrap菜鸟教程&#xff1a;点我直达 目录&#xff1a;&#xff08;一&#xff09;Bootstrap标准模板&#xff1a;&#xff08;二&#xff09;CSS样式区&#xff1a;一、布局容器&#xff1a;二、栅格系统&#xff1a;1.列组合&#x…

<Linux> 软件包管理器yum及编辑器vim的使用

文章目录一、yum的背景知识1. 商业生态2. 开源生态3. 软件生态本土化二、yum 的基本使用1. 查看软件包2. 安装、卸载、搜索软件实现Windows下和Linux下文件互传三、vim的基本使用1. vim 的基本概念2. vim 的基本操作2.1.模式间切换2.2.插入模式2.3.命令模式2.4.底行模式四、vim…

nginx(四十二)access阶段的模块学习

一 ngx_http_access ① 基本描述 场景&#xff1a; 限制某些ip来源的访问;基于ip进行限制细节点&#xff1a; 基于$remote_addr进行判断的 ② allow deny ③ 官方案例 说明&#xff1a; 按照配置文件中allow|deny的先后顺序,只要匹配上则停止继续匹配 ④ 经典应用场…

Rust机器学习之ndarray

Rust机器学习之ndarray 众所周知&#xff0c;Python之所以能成为机器学习的首选语言&#xff0c;与其丰富易用的库有很大关系。某种程度上可以说是诸如numpy、pandas、scikit-learn、matplotlib、pytorch、networks…等一系列科学计算和机器学习库成就了Python今天编程语言霸主…

Vue项目实战——【基于 Vue3.x + NodeJS】实现的课程表排课系统二(week-title)

文章目录基于 Vue3.x NodeJS实现的课程表排课系统&#xff08;二&#xff09;初始化样式封装axios处理数据表格头部&#xff08;周几&#xff09;子组件写入根组件App.vue浅拿一下数据基于 Vue3.x NodeJS实现的课程表排课系统&#xff08;二&#xff09; 初始化样式 src/ass…

当 AI 遇上 web3,会碰撞出什么火花?

2020 年之前&#xff0c;Web3 的路是创造者们铺好的。但 Web3 遇上了金融&#xff0c;这出乎了每个创造者的意料之外&#xff0c;稳定币、AMM 和借贷突其来地点燃了2020年的那个夏天。之后 Web3 又遇到了 NFT、游戏和元宇宙。不过因为技术限制&#xff0c;除了金融之外&#xf…

AVL树详解(附带旋转步骤图,手把手带你上分)

文章目录&#x1f44d; AVL树的概念先了解一下&#x1f601;AVL树节点的定义&#x1f60a;AVL树插入节点&#x1f91e;AVL树为什么要旋转&#x1f60d;AVL树的四种旋转左单旋右单旋左右双旋右左双旋❤️结语关于AVL树的讲解 &#x1f44d; AVL树的概念先了解一下 它的左右子树…