数据结构基础5:栈和队列的实现。

news2024/9/27 19:20:36

一.栈的基本概念。

一.基本概念

1.基本概念

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

2.模拟实现

我们之前已经了解过顺序表的静态和动态,单链表——双向带头循环链表。这些线性表结构。我们想一想?如果实现栈使用一个什么样的结构作为我们的基础。

内容特性:
请添加图片描述
缓存利用:
----顺序表请添加图片描述
链表的缓存利用:
请添加图片描述

3.综上所述:

使用一个动态开辟的一个顺序表作为我们的栈的基础结构。
1.顺序表:缓存的利用率高。
2.顺序表尾插尾删的效率都比较高。
结构体定义
请添加图片描述

二.函数接口实现

1.初始化

//初始化
void StInit(struct Stack* ps)
{
	//不在初始化开辟空间
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

2.销毁

//销毁
void StDestroy(struct Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

3.入栈

void StPush(struct Stack* ps, Stackinttype x)
{
	assert(ps != NULL);
	
	//容量问题
	if (ps->top == ps->capacity)
	{
		//扩容,开始没有进行扩容
		Stackinttype* tmp = (Stackinttype*)realloc(ps->a, 
			sizeof(Stackinttype) * (ps->capacity>0?(ps->capacity)*2:4));

		if (tmp == NULL)
		{
			perror("realloc file\n");
			exit(-1);
		}
		//动态开辟空间ps->a这个空间没有数据,realloc相当于malloc;
		
		ps->a = tmp;

		if (ps->capacity == 0)
		{
			ps->capacity = 4;
		}
		else
		{
			ps->capacity = (ps->capacity) * 2;
		}
		
	}

	ps->a[ps->top] = x;
	ps->top++;

}

4.出栈

void StPop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0
	assert(ps->top>0);

	ps->a[((ps->top)-1)] = 0;
	ps->top--;
}

5.返回栈顶的数据

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0,这个时候栈中是没有数据的。
	assert(ps->top > 0);

	return (ps->a[(ps->top)-1]);
}

6.返回栈中数据个数

//返回栈中数据个数
int StSize(struct Stack* ps)
{
	//是0就返回0;
	assert(ps != NULL);

	return ps->top;
}

7.检查栈是否为空


//检查栈是否为空
bool StEmpty(struct Stack* ps)
{
	assert(ps != NULL);
	if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}

}

三.整体带码

#define _CRT_SECURE_NO_WARNINGS 1

#include"Stack.h"



//打印数据
void Stprint(struct Stack* ps)
{
	assert(ps);
	//assert(ps->top > 0);

	for (int i = 0; i < ps->top; i++)
	{
		printf("%d->", ps->a[i]);
	}
	printf("栈顶\n");
}

//初始化
void StInit(struct Stack* ps)
{
	//不在初始化开辟空间
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//销毁
void StDestroy(struct Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}


//入栈
void StPush(struct Stack* ps, Stackinttype x)
{
	assert(ps != NULL);
	
	//容量问题
	if (ps->top == ps->capacity)
	{
		//扩容,开始没有进行扩容
		Stackinttype* tmp = (Stackinttype*)realloc(ps->a, 
			sizeof(Stackinttype) * (ps->capacity>0?(ps->capacity)*2:4));

		if (tmp == NULL)
		{
			perror("realloc file\n");
			exit(-1);
		}
		//动态开辟空间ps->a这个空间没有数据,realloc相当于malloc;
		
		ps->a = tmp;

		if (ps->capacity == 0)
		{
			ps->capacity = 4;
		}
		else
		{
			ps->capacity = (ps->capacity) * 2;
		}
		
	}

	ps->a[ps->top] = x;
	ps->top++;

}
//出栈
void StPop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0
	assert(ps->top>0);

	ps->a[((ps->top)-1)] = 0;
	ps->top--;
}

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0,这个时候栈中是没有数据的。
	assert(ps->top > 0);

	return (ps->a[(ps->top)-1]);
}

//返回栈中数据个数
int StSize(struct Stack* ps)
{
	//是0就返回0;
	assert(ps != NULL);

	return ps->top;
}

//检查栈是否为空
bool StEmpty(struct Stack* ps)
{
	assert(ps != NULL);
	if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}

}




#pragma once

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

typedef int Stackinttype;

typedef struct Stack {
	Stackinttype* a;
	int top;
	int capacity;
}ST;


//打印数据
void Stprint(struct Stack* ps);

//初始化
void StInit(struct Stack* ps);

//销毁
void StDestroy(struct Stack* ps);

//入栈
void StPush(struct Stack* ps, Stackinttype x);

//出栈
void StPop(struct Stack* ps);

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps);

//返回栈中数据个数
int StSize(struct Stack* ps);

//检查栈是否为空
bool StEmpty(struct Stack* ps);




#define _CRT_SECURE_NO_WARNINGS 1

#include"Stack.h"

void test()
{
	ST stack;
	//初始化
	StInit(&stack);

	//进入数据
	StPush(&stack, 1);
	StPush(&stack, 2);
	StPush(&stack, 3);
	StPush(&stack, 4);
	StPush(&stack, 5);
	StPush(&stack, 6);

	Stprint(&stack);

	StPop(&stack);//5
	StPop(&stack);//4
	StPop(&stack);//3
	Stprint(&stack);

	//获取栈顶元素
	int a = StTop(&stack);
	printf("%d\n", a);

	StPop(&stack);

	a = StTop(&stack);
	printf("%d\n", a);

	StPush(&stack, 4);
	StPush(&stack, 5);
	StPush(&stack, 6);

	Stprint(&stack);

	//返回栈的的数据个数
	int number = StSize(&stack);
	printf("%d\n", number);

	//判断栈是否为空
	StPop(&stack);
	StPop(&stack);
	StPop(&stack);
	StPop(&stack);
	StPop(&stack);


	if (StEmpty(&stack))
	{
		printf("栈空了!\n");
	}

}
int main()
{
	//测试
	test();
}


二.队列基本概念:

一.基本概念

1.基本概念:

只允许在一端进行插人数据,在另一端删除数据,插入数据的一端是队尾,删除数据的一端是队头.队尾入队头出.(first in first out).

2.模拟实现:

这里我们使用链表不去使用顺序表.
1.顺序表的删除数据,移动数据的时间复杂度是O(1).
2.试用带头单链表或者不带头的单链表都可以.
3.正常的单链表也是需要找尾解决这个问题我们需要创建两个结构体一个是节点的结构体,一个是队列的结构体,队列的结构体保存了,一个队列的头和尾的地址.
4.Queue这个结构体只需要创建一次就是一个队列这样我们
请添加图片描述

二.接口实现

所有的接口都需要判断队列这个结构体指针不可以为空。

1.初始化

1.不去多次的malloc节点,只在入队列进行节点的开辟。
2.初始化队列的个数。

//初始化
void QueueInit(Que* ps)
{
	assert(ps);
	ps->head = ps->tile = NULL;
	ps->size = 0;
}

2.判断队列是否为空

1.ps->tile==NULL说明队列中一个数据都没有。
2.返回bool类型的数值。

//判断队列为空
bool QueueEmpty(Que* ps)
{
	assert(ps);

	if (ps->tile == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

3入队列

1.进入就要开辟节点判断节点开辟是否成功。
2.第一种情况:当队列中没有数据的时候,ps->head=ps->tile=newnode;
3.第二种情况:当队列中有数据的时候就正常队尾入数据。
4.进入数据需要++;

//入队列
void QueuePush(Que* ps,QueueDatatype x)
{
	assert(ps);
	QueN* newnode = (QueN*)malloc(sizeof(QueN));

	if (newnode == NULL)
	{
		perror("malloc file\n");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	//队列中没有数据
	if (ps->tile==NULL)
	{
		ps->head = ps->tile = newnode;
	}
	else
	{
		ps->tile->next = newnode;
		ps->tile = newnode;
	}
	ps->size++;
}

4出队列

1.出去所以队列中有数据才可以出数据。
2.判断队列是否为空。
3.如果队列中没有数据的时候ps->head=ps->tile=NULL;(ps->tile)产生野指针。
4.队列中还有数据的时候,注意入队列创建节点出队列释放节点,否则会产生内存泄漏。

//出队列
void QueuePop(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	if (ps->head == ps->tile)
	{
		free(ps->head);
		ps->head = ps->tile = NULL;
	}
	else
	{
		QueN* next = ps->head->next;
		free(ps->head);
		ps->head = next;
	}
	ps->size--;
}

5.获取队头数据

1.断言:队列是否为空
2.return ps->head->data;

//获取队头数据。
QueueDatatype QueueFront(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->head->data;
}

6.获取队尾数据

1.断言:队列是否为空
2.return ps->tile->data;

//获取队尾数据
QueueDatatype QueueBack(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->tile->data;
}

7.队列的销毁

1.遍历释放每一个节点从头开始。
2.是通过cur=ps->head 遍历数据的。
3.cur为空的时候,所有的节点释放完成。
4.这个时候因为我们还没有对ps->tile没有进行处理的所以产生野指针。
5.ps->head=ps->tile = NULL;ps->size = 0;

//销毁
void QueueDestor(Que* ps)
{
	assert(ps);
	QueN* cur = ps->head;

	while (cur)
	{
		QueN* next = cur->next;
		free(cur);
		cur = NULL;
		cur = next;
	}
	//这个时候tile是一个野指针,指向一个已经被释放的空间
	ps->head=ps->tile = NULL;
	ps->size = 0;
}

8.获取队列有效数据个数据

1.断言:队列是否为空。
2.return ps->size;

//获取队列有效数据个数
int QueueSize(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->size;
}

三.整体代码和测试用例

#pragma once

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

typedef int QueueDatatype;

typedef struct QueueNode {
	QueueDatatype data;
	struct QueueNode* next;
}QueN;

typedef struct Queue {
	QueN* head;
	QueN* tile;
	//队列中元素个数
	int size;
}Que;

//队列打印
void QueuePrint(Que* ps);
//初始化
void QueueInit(Que* ps);
//销毁
void QueueDestor(Que* ps);
//入队列
void QueuePush(Que* ps,QueueDatatype x);
//出队列
void QueuePop(Que* ps);
//判断队列为空
bool QueueEmpty(Que* ps);
//获取队头数据。
QueueDatatype QueueFront(Que* ps);
//获取队尾数据
QueueDatatype QueueBack(Que* ps);
//获取队列有效数据个数
int QueueSize(Que* ps);

#define _CRT_SECURE_NO_WARNINGS 1

#include"Queue.h"
//初始化
void QueueInit(Que* ps)
{
	assert(ps);
	ps->head = ps->tile = NULL;
	ps->size = 0;
}
//销毁
void QueueDestor(Que* ps)
{
	assert(ps);
	QueN* cur = ps->head;

	while (cur)
	{
		QueN* next = cur->next;
		free(cur);
		cur = NULL;
		cur = next;
	}
	//这个时候tile是一个野指针,指向一个已经被释放的空间
	ps->head=ps->tile = NULL;
	ps->size = 0;
}

//判断队列为空
bool QueueEmpty(Que* ps)
{
	assert(ps);

	if (ps->tile == NULL)
	{
		return true;
	}
	else
	{
		return false;
	}
}

//入队列
void QueuePush(Que* ps,QueueDatatype x)
{
	assert(ps);
	QueN* newnode = (QueN*)malloc(sizeof(QueN));

	if (newnode == NULL)
	{
		perror("malloc file\n");
		exit(-1);
	}

	newnode->data = x;
	newnode->next = NULL;

	//队列中没有数据
	if (ps->tile==NULL)
	{
		ps->head = ps->tile = newnode;
	}
	else
	{
		ps->tile->next = newnode;
		ps->tile = newnode;
	}
	ps->size++;
}
//出队列
void QueuePop(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	if (ps->head == ps->tile)
	{
		free(ps->head);
		ps->head = ps->tile = NULL;
	}
	else
	{
		QueN* next = ps->head->next;
		free(ps->head);
		ps->head = next;
	}
	ps->size--;
}
//获取队头数据。
QueueDatatype QueueFront(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->head->data;
}
//获取队尾数据
QueueDatatype QueueBack(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	return ps->tile->data;
}

//获取队列有效数据个数
int QueueSize(Que* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->size;
}

满足队列的特性:
1.队尾入数据.
2.队头出数据并且打印队头的数据.
3.在打印函数传参需要判断队列是否为空.

#define _CRT_SECURE_NO_WARNINGS 1

#include"Queue.h"

void test()
{
	Que st;
	//初始化
	QueueInit(&st);
	//入队列
	QueuePush(&st, 1);
	QueuePush(&st, 2);
	QueuePush(&st, 3);
	QueuePush(&st, 4);
	QueuePush(&st, 5);

	while (!QueueEmpty(&st))
	{
		printf("%d->", QueueFront(&st));
		QueuePop(&st);
	}

	QueueDestor(&st);

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

三.栈和队列的一些面试题目:

题目一:

请添加图片描述
题目链接

主要思路:

1.上面实现的栈可以直接拿过来使用,修改int为char
2.根据栈后进先出的性质。
3.遍历字符串‘{’ ‘[’ ‘(’ 入栈。
4.进行匹配的对应,‘}’ ‘]’ ‘)’ 就应该进行判断,判断获取栈顶元素,判断是否匹配。如果不匹配就返回false。匹配之后删除栈顶元素。
5.只有一个类似‘}’右边的,应该在判断‘}’ ‘]’ ‘)’ 的部分里去判断栈中是否有数据如果没有数据那么有右没有左直接return true
6.这个字符串到\0结束,如果栈中没有数据。说明这个字符串的符号是匹配的。
代码实现:

typedef char Stackinttype;

typedef struct Stack {
	Stackinttype* a;
	int top;
	int capacity;
}ST;
//初始化
void StInit(struct Stack* ps)
{
	//不在初始化开辟空间
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//销毁
void StDestroy(struct Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//入栈
void StPush(struct Stack* ps, Stackinttype x)
{
	assert(ps != NULL);
	
	//容量问题
	if (ps->top == ps->capacity)
	{
		//扩容,开始没有进行扩容
		Stackinttype* tmp = (Stackinttype*)realloc(ps->a, 
			sizeof(Stackinttype) * (ps->capacity>0?(ps->capacity)*2:4));

		if (tmp == NULL)
		{
			perror("realloc file\n");
			exit(-1);
		}
		//动态开辟空间ps->a这个空间没有数据,realloc相当于malloc;
		
		ps->a = tmp;

		if (ps->capacity == 0)
		{
			ps->capacity = 4;
		}
		else
		{
			ps->capacity = (ps->capacity) * 2;
		}
		
	}

	ps->a[ps->top] = x;
	ps->top++;

}
//出栈
void StPop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0
	assert(ps->top>0);

	ps->a[((ps->top)-1)] = 0;
	ps->top--;
}

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0,这个时候栈中是没有数据的。
	assert(ps->top > 0);

	return (ps->a[(ps->top)-1]);
}

//返回栈中数据个数
int StSize(struct Stack* ps)
{
	//是0就返回0;
	assert(ps != NULL);

	return ps->top;
}

//检查栈是否为空
bool StEmpty(struct Stack* ps)
{
	assert(ps != NULL);
	if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}
}
bool isValid(char * s){
    ST stack;
    //初始化
    StInit(&stack);
    
    //入栈
    char* cur=s;

    while(*cur)
    {
        char cmp=(*cur);
        if((cmp=='[')||(cmp=='{')||(cmp=='('))
        {
            StPush(&stack,cmp);
        }
				//栈中没有数据,一个右的可以进入的。
        else if((cmp=='}')||(cmp==']')||(cmp==')'))
        {
            //判断栈为空的情况
						if(StEmpty(&stack))
						{
							return false;
						}
						//获取栈顶的数据
						char tmp = StTop(&stack);

					if ((((cmp == '}') && (tmp != '{'))) ||
				(((cmp == ']') && (tmp != '['))) ||
				(((cmp == ')') && (tmp != '('))))
            {
                return false;
            }
            //出栈 
            StPop(&stack);
        }
        cur++;
    }
    
    //假设只有一个左边的{},[],().
    int number=StSize(&stack);
    if(number==0)
    {
        return true;
    }
    else
    {
        return false;
    }
}

题目二:

请添加图片描述

主要思路:

请添加图片描述
题目链接

typedef int QueueDatatype;

//每一个节点
typedef struct QueueNode {
	QueueDatatype data;
	struct QueueNode* next;
}QueN;

//队列结构体类型
typedef struct Queue {
	QueN* head;
	QueN* tile;
	int size;
}QU;

//初始化
void QueueInit(QU* ps);
//判断队列是否为空
bool QueueEmpty(QU* ps);
//队尾进入
void QueuePush(QU* ps, QueueDatatype x);
//队头出数据
void QueuePop(QU* ps);
//获取队头数据
QueueDatatype QueueFront(QU* ps);
//获取队尾数据
QueueDatatype QueueBack(QU* ps);
//获取有效数据个数
int Queuesize(QU* ps);
//销毁队列
void QueueDestory(QU* ps);

//初始化
void QueueInit(QU* ps)
{
	//给空指针不开辟新的节点
	assert(ps);
	ps->head = ps->tile = NULL;
	ps->size = 0;
}

//判断队列是否为空
bool QueueEmpty(QU* ps)
{
	return ps->head==NULL;
}

//队尾进入
void QueuePush(QU* ps, QueueDatatype x)
{
	assert(ps);
	//1.进入一定需要开辟节点的。
	QueN* newnode = (QueN*)malloc(sizeof(QueN));
	if (newnode == NULL)
	{
		perror("malloc file\n");
		exit(-1);
	}
	newnode->next = NULL;
	newnode->data = x;

	if (ps->tile==NULL)
	{
		ps->head = ps->tile = newnode;
	}
	else
	{
		ps->tile->next = newnode;
		ps->tile = newnode;
	}
	ps->size++;
}
//队头出数据
void QueuePop(QU* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));
	

    if(ps->head==ps->tile)
    {
        free(ps->head);
        ps->head=ps->tile=NULL;
    }
    else
    {
        QueN* next=ps->head->next;
        free(ps->head);
        ps->head=next;
    }
	ps->size--;
}
//获取队头数据
QueueDatatype QueueFront(QU* ps)
{
	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->head->data;
}
//获取队尾数据
QueueDatatype QueueBack(QU* ps)
{

	assert(ps);
	assert(!QueueEmpty(ps));

	return ps->tile->data;
}
//获取有效数据个数
int Queuesize(QU* ps)
{
	assert(ps);

	return ps->size;
}
//销毁队列
void QueueDestory(QU* ps)
{
	assert(ps);
	QueN* cur = ps->head;
	while (cur)
	{
		QueN* next = cur->next;
		free(cur);
		cur = NULL;
		cur = next;
	}
	//容易产生野指针
	ps->head = ps->tile = NULL;
    ps->size=0;
}

typedef struct {
    QU s1;
    QU s2;
} MyStack;


MyStack* myStackCreate() {
    MyStack* pst=(MyStack*)malloc(sizeof(MyStack));

    QueueInit(&pst->s1);
    QueueInit(&pst->s2);

    return pst;
}

void myStackPush(MyStack* obj, int x) {
    //1.两个都为空,有一个为空,一个不为空。
    if(!QueueEmpty(&obj->s1))
    {
        QueuePush(&obj->s1,x);
    }
    else
    {
        QueuePush(&obj->s2,x);
    }
}

int myStackPop(MyStack* obj) {

    //1.假设有和没有数据的队列,确定有和没有。
    QU* have=&obj->s1;
    QU* nonhave=&obj->s2;

    if(QueueEmpty(&obj->s1))
    {
        have=&obj->s2;
        nonhave=&obj->s1;
    }

    //2.倒数据
    while(Queuesize(have)>1)
    {
        //1.获取数据
        int k = QueueFront(have);
        //2.pop数据
        QueuePop(have);
        //2.进入另一个队列
        QueuePush(nonhave,k);
    }

    //1.获取数据
    int k = QueueFront(have);
    //2.pop数据
    QueuePop(have);
    return k;
}

int myStackTop(MyStack* obj) {
    if(!QueueEmpty(&obj->s1))
    {
        return QueueBack(&obj->s1);
    }
    else
    {
        return QueueBack(&obj->s2);
    }
}

bool myStackEmpty(MyStack* obj) {
    return ((QueueEmpty(&obj->s1))&&(QueueEmpty(&obj->s2)));
}

void myStackFree(MyStack* obj) {

    QueueDestory(&obj->s1);
    QueueDestory(&obj->s2);

    free(obj);
}

题目三:

请添加图片描述
题目链接

主要思路:

请添加图片描述

1.使用队列实现栈是需要来回倒数据获取最后一个。
2.我们使用栈实现队列你需要规定哪一个是用来进入数据的push栈,和用来出数据的pop栈。
3.只有当Pop栈数据为空的时候才可以把push栈的数据倒到pop栈里面。
4.peek和pop两个函数的区别,一个删除队头一个不删除队头,如果上来使用peek那么peek函数是需要倒数据这个操作,如果没有这个操作我们获取不到正确的队头数据的。!!!!

typedef int Stackinttype;

typedef struct Stack {
	Stackinttype* a;
	int top;
	int capacity;
}ST;
//初始化
void StInit(struct Stack* ps);

//销毁
void StDestroy(struct Stack* ps);

//入栈
void StPush(struct Stack* ps, Stackinttype x);

//出栈
void StPop(struct Stack* ps);

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps);

//返回栈中数据个数
int StSize(struct Stack* ps);

//检查栈是否为空
bool StEmpty(struct Stack* ps);

//初始化
void StInit(struct Stack* ps)
{
	//不在初始化开辟空间
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}

//销毁
void StDestroy(struct Stack* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = 0;
	ps->top = 0;
}
//入栈
void StPush(struct Stack* ps, Stackinttype x)
{
	assert(ps != NULL);
	
	//容量问题
	if (ps->top == ps->capacity)
	{
		//扩容,开始没有进行扩容
		Stackinttype* tmp = (Stackinttype*)realloc(ps->a, 
			sizeof(Stackinttype) * (ps->capacity>0?(ps->capacity)*2:4));

		if (tmp == NULL)
		{
			perror("realloc file\n");
			exit(-1);
		}
		//动态开辟空间ps->a这个空间没有数据,realloc相当于malloc;
		
		ps->a = tmp;

		if (ps->capacity == 0)
		{
			ps->capacity = 4;
		}
		else
		{
			ps->capacity = (ps->capacity) * 2;
		}
		
	}

	ps->a[ps->top] = x;
	ps->top++;

}
//出栈
void StPop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0
	assert(ps->top>0);

	ps->a[((ps->top)-1)] = 0;
	ps->top--;
}

//返回栈顶的数据
Stackinttype StTop(struct Stack* ps)
{
	assert(ps != NULL);
	//访问数组空间下标至少是0,这个时候栈中是没有数据的。
	assert(ps->top > 0);

	return (ps->a[(ps->top)-1]);
}

//返回栈中数据个数
int StSize(struct Stack* ps)
{
	//是0就返回0;
	assert(ps != NULL);

	return ps->top;
}

//检查栈是否为空
bool StEmpty(struct Stack* ps)
{
	assert(ps != NULL);
	if (ps->top == 0)
	{
		return true;
	}
	else
	{
		return false;
	}

}

typedef struct {
    ST Pushst;
    ST Popst;
} MyQueue;

MyQueue* myQueueCreate() {
    MyQueue* pq=(MyQueue*)malloc(sizeof(MyQueue));
    if(pq==NULL)
    {
        perror("malloc file\n");
        exit(-1);
    }

    StInit(&pq->Pushst);
    StInit(&pq->Popst);

		return pq;
}

void myQueuePush(MyQueue* obj, int x) {
    assert(obj);

    StPush(&obj->Pushst,x);
}

int myQueuePop(MyQueue* obj) {
    assert(obj);

    if(StEmpty(&obj->Popst))
    {
        //3.倒一下顺序
        int sz=StSize(&obj->Pushst);
        while(sz--)
        {
            int x=StTop(&obj->Pushst);
            StPop(&obj->Pushst);
            StPush(&obj->Popst,x);
        }
    }

    int x=StTop(&obj->Popst);
    StPop(&obj->Popst);
		
    return x;
}

int myQueuePeek(MyQueue* obj) {
    assert(obj);

		 if(StEmpty(&obj->Popst))
    {
        //3.倒一下顺序
        int sz=StSize(&obj->Pushst);
        while(sz--)
        {
            int x=StTop(&obj->Pushst);
            StPop(&obj->Pushst);
            StPush(&obj->Popst,x);
        }
    }

    return StTop(&obj->Popst); 
}

bool myQueueEmpty(MyQueue* obj) {
    return (StEmpty(&obj->Pushst) && StEmpty(&obj->Popst));
}

void myQueueFree(MyQueue* obj) {
    StDestroy(&obj->Pushst);
    StDestroy(&obj->Popst);

    free(obj);
}

题目四:

请添加图片描述
题目链接

主要思路一:

请添加图片描述

//节点的结构体
typedef struct list{
    struct list* next;
    struct list* prev;
    int data;
}Li;

//队列的结构体
typedef struct {
    Li* head;
    Li* tile;
    int size;
    int capcity;
} MyCircularQueue;

//自己的初始化函数需要构建+连接
void CirQueuInit(MyCircularQueue* pst,int k)
{
    assert(pst);
    //多一个节点:
    int n=k+1;

    Li* newnode=(Li*)malloc(sizeof(Li));
    newnode->prev=NULL;
    newnode->next=NULL;
    newnode->data=0;
    //节点的默认处理:

     if(pst->head==pst->tile)
    {
        pst->head=pst->tile=newnode;
    }

    //前面这个部分构建我们的第一个节点,第一个节点head和tile在同一个位置。

    while(k--)//k个节点的构建:
    {
        Li* newnode=(Li*)malloc(sizeof(Li));
        newnode->prev=NULL;
        newnode->next=NULL;
        newnode->data=0;

        //数据的前后连接+tile的移动。
        pst->tile->next=newnode;
        newnode->prev=pst->tile;
        pst->tile=newnode;
    }

    //结尾的时候,tile到了k+1个节点和头的前后连接。
    pst->tile->next=pst->head;
    pst->head->prev=pst->tile;

    pst->tile=pst->head;

    //初始化队列的数据
    pst->capcity=n-1;
    pst->size=0;
}

MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* pst=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //初始化一下这个队列。
    CirQueuInit(pst,k);
    return pst;
}

//判断空和满对于队头插数据和队尾删数据是比较重要的。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    //使用头尾节点的位置和有效数据个数比较判断的结果是相同的。
    if((obj->head==obj->tile)&&(obj->size==0))
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    //两个判断条件可以任意出现一个也可以同时出现。
    if((obj->head->prev==obj->tile)&&(obj->size==obj->capcity))
    {
        return true;
    }
    else
    {
        return false;
    }
}
//添加函数
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    
    obj->tile->data=value;
    obj->tile=obj->tile->next;
    obj->size++;

    return true;
}
//删除函数
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
        return false;
    

    obj->head->data=0;
    obj->head=obj->head->next;
    obj->size--;

    return true;
}

//取队头数据
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->head->data;
}
//取队尾数据,使用双向循环。
int myCircularQueueRear(MyCircularQueue* obj) {
     if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return ((obj->tile)->prev)->data;
}

//有节点的初始化就有节点的销毁防止内存泄漏
void CirQueuDestory(MyCircularQueue* pst)
{
    Li* cur=pst->head;
    int n=pst->capcity;
    while(n--)
    {
        Li* next=cur->next;
        free(cur);
        cur=next;
    }
    pst->size=0;
}
//释放队列:
void myCircularQueueFree(MyCircularQueue* obj) {
    //释放内部节点
    CirQueuDestory(obj);
    //释放外部队列。
    free(obj);
}

主要思路二:

优化部分:
1.单链表这个结构体的双向循环构建和销毁是比较麻烦的。
2.开辟的空间比较多,单链表的效率比顺序表要底。
3.尝试使用顺序表解决这个循环队列的问题。
4.判断空和满的时候的计算不要改变原来的数值。
5.获取数据使用的判断空和满的函数使用需要细心。

请添加图片描述
请添加图片描述

typedef struct {
    int* queu;
    //存下表的。
    int head;
    int tile;
    int k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) {
    //创建一个节点:
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    int* newhead=(int*)malloc(sizeof(int)*(k+1));
    if(newhead==NULL)
    {
        perror("malloc file\n");
        exit(-1);
    }
    //一个顺序表
    obj->queu=newhead;
    //其他值的初始化
    obj->head=0;
    obj->tile=0;
    obj->k=k;

    return obj;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    assert(obj);
    if(obj->head==obj->tile)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    assert(obj);
    
    //作为判断使用不应该改变数值的。
    int k=(((obj->tile)+1)%((obj->k)+1));
    if(obj->head==k)
    {
        return true;
    }
    else
    {
        return false;
    }
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    assert(obj);
    if(myCircularQueueIsFull(obj))
        return false;
    else
    {
        (obj->tile)%=((obj->k)+1);
        obj->queu[obj->tile]=value;
        obj->tile++;
        (obj->head)%=((obj->k)+1);
    }
     return true;  
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    assert(obj);
    if(myCircularQueueIsEmpty(obj))
        return false;
    else
    {
        (obj->head)%=((obj->k)+1);
        obj->head++;
        (obj->head)%=((obj->k)+1);
    }  
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
    assert(obj);
    //队列为空才会返回-1
    if(myCircularQueueIsEmpty(obj))
        return -1;
    else
    {
        return obj->queu[obj->head];
    }
}

int myCircularQueueRear(MyCircularQueue* obj) {
    assert(obj);
    //队列为空才会返回-1.
    if(myCircularQueueIsEmpty(obj))
         return -1;
    else
    {
       return obj->queu[((obj->tile)-1)];
    }
}

void myCircularQueueFree(MyCircularQueue* obj) {
    assert(obj);
    free(obj->queu);
    obj->head=0;
    obj->tile=0;
    obj->k=0;
    free(obj);
}

希望文章可以帮助到大家!!

我会继续写出更加优质的文章的

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

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

相关文章

java静默打印PDF(可实现生产环境下服务器写入PDF模板,然后调用客户端打印机打印)

java静默打印PDF可实现生产环境下服务器写入PDF模板&#xff0c;然后调用客户端打印机打印 一、简需求实现步骤 二、代码实现0、打印模板1、服务器部分 &#xff08;端口&#xff1a;8090&#xff09;1.1、maven依赖1.2、实体1.2.1、接口返回类1.2.2、标签纸页面参数类1.2.3、P…

【EI/SCOPUS检索】第四届应用力学与机械工程国际学术会议(ICAMME 2023)

第四届应用力学与机械工程国际学术会议&#xff08;ICAMME 2023&#xff09; 2023 4th International Conference on Applied Mechanics and Mechanical Engineering (ICAMME 2023) 第四届应用力学与机械工程国际学术会议&#xff08;ICAMME 2023&#xff09;将于2023年11月10…

期刊和会议缩写查询网站

1.https://pubmed.ncbi.nlm.nih.gov/?termMedicalImageComputingandComputer-AssistedIntervention 2. http://www.letpub.com.cn/index.php?pagejournalapp&viewsearch 3. https://blog.csdn.net/weixin_44557349/article/details/120825927 https://blog.csdn.net/ret…

Kafka:安装和配置

producer&#xff1a;发布消息的对象&#xff0c;称为消息产生者 &#xff08;Kafka topic producer&#xff09; topic&#xff1a;Kafka将消息分门别类&#xff0c;每一个消息称为一个主题&#xff08;topic&#xff09; consumer&#xff1a;订阅消息并处理发布消息的对象…

【solon生态】- solon.cloud.micrometer插件使用指南及micrometer详解

solon.cloud.micrometer插件使用指南 solon是什么solon的cloud生态图快速入门 micrometer指南micrometer是什么监控系统 Supported Monitoring Systems注册表 Registry度量 Meters度量名 Naming Meters度量标签 Tag Naming通用标签 Common Tags 指标过滤器 MeterFilter聚合速率…

LeetCode_01 精度丢失

1281. 整数的各位积和之差 给你一个整数 n&#xff0c;请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。 示例 输入&#xff1a;n 234 输出&#xff1a;15 解释&#xff1a; 各位数之积 2 * 3 * 4 24 各位数之和 2 3 4 9 结果 24 - 9 15示例 …

vue中使用this.$refs获取不到子组件的方法,属性方法都为undefined的解决方法

问题描述 vue2中refs获取不到子组件中的方法&#xff1f;&#xff0c;而获取到的是undefined 原因及解决方案&#xff1a; 第一种、在循环中注册了很多个ref 因为注册了多个ref&#xff0c;获取是不能单单知识refs.xxx&#xff0c;需要使用数组和索引来获取具体一个组件refs[…

限流式保护器在高校宿舍电气防火的应用

安科瑞 华楠 引言 14日早晨6时10分左右&#xff0c;上海商学院徐汇校区学生宿舍楼发生火灾&#xff0c;4名女生从六楼宿合阳台跳下逃生当场死亡&#xff0c;酿成近年来惨烈的校园事故。宿舍火灾初步判断缘起于寝室里使用热得快导致电器故障并将周围可燃物引燃。 任何条生命都是…

【方法】7Z压缩包如何解压?

你知道7Z压缩包如何解压吗&#xff1f; 7Z是一种主流高效的压缩格式&#xff0c;它可以用多种压缩解压软件来解压&#xff0c;像7-Zip、WinRAR等常用的解压缩软件都可以解压7Z压缩包。 首先我们可以从官网或者软件商店里免费下载7-Zip或者WinRAR解压缩软件&#xff0c;再安装…

PXE-kickstart无人值守安装操作系统

PXE的概念&#xff1a; PXE&#xff08;Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff09;是由Intel公司开发的最新技术&#xff0c;工作于C/S的网络模式&#xff0c;支持工作站通过网络从远端服务器下载映像&#xff0c;并由此支持通过网络启动操作系统…

leetcode 2616. 最小化数对的最大差值

在数组nums中找到p个数对&#xff0c;使差值绝对值的和最小。 思路&#xff1a; 最小差值应该是数值相近的一对数之间产生&#xff0c;让数值相近的数字尽量靠在一起方便计算&#xff0c;所以需要排序。 这里不去直接考虑一对对的数字&#xff0c;而是直接考虑差值的取值。 …

msvcp120.dll丢失的解决方法,哪种解决方法更实用

msvcp120.dll是Microsoft Visual C 2013库中的一个动态链接库文件。它包含了在使用Visual C 2013编译的应用程序中所需的函数和资源。这个文件通常用于在Windows操作系统上运行使用Visual C 2013编写的软件。如果缺少或损坏了msvcp120.dll文件&#xff0c;可能会导致相关软件无…

Wav2Lip实践

1. 安装 1.1 安装 conda以指定python版本运行环境 下载&#xff1a;Index of /https://repo.anaconda.com/archive/index.html 1.2 如按旧项目基于python3.6版本对话&#xff0c;会有很多包找不到的情况&#xff0c;经摸索后以python3.9构建成功&#xff0c; conda instal…

js代码加密,也能在vs code中进行?

在vs code中对js代码混淆加密 Vs code是常用的js代码编辑工具。本文演示如何在vs code中调用jshaman扩展&#xff0c;实现非常方便的js代码加密。 打开vs code&#xff1a; 点击左侧的“扩展”&#xff0c;打开后搜索“jshaman”。 &#xff08;JShaman是业界很有名的JS代码…

Stable Diffusion - 底部视角 (From Below) 拍摄的图像 LoRA 与配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132192139 图像来源自 哥特风格 与 底部视角 的结合&#xff0c;更具有视觉冲击力。 从下面或底部 (From Below) 拍摄人物&#xff0c;可以创造出…

学C语言 | 位运算符<<的高级用法

前言 在上一篇文章中&#xff0c;我们介绍了~运算符的高级用法&#xff0c;本篇文章&#xff0c;我们将介绍<< 运算符的一些高级用法。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿…

流量分析日志查看

一流量分析 buuctf wireshark 从题目出发&#xff0c;既然是上传登录信息&#xff0c;就直接过滤post请求&#xff0c;即搜索 http.request.methodPOST&#xff0c;因为上传用户登录信息使用的一定是http里的post方法 模式过滤 http.request.method “GET” http.request.…

数据要素市场之破四化建四化,拆墙又砌墙

摘要&#xff1a;8月8日&#xff0c;首届贵州科技节“2023数据要素流通关键技术论坛”在贵阳举行。此次论坛由贵州省科学技术协会指导&#xff0c;贵州省计算机学会主办&#xff0c;中国计算机学会贵阳会员活动中心、贵州轻工职业技术学院、贵州电子科技职业学院、贵州省大数据…

基于kubeadm部署K8S集群

目录 基于kubeadm部署K8S集群 一、环境准备 1、主机初始化配置 2、配置主机名并绑定hosts&#xff0c;不同主机名称不同 3、主机配置初始化 二、部署docker环境 1、三台主机上分别部署 Docker 环境 2、镜像加速器&#xff08;所有主机配置&#xff09; 三、部署kubern…

模拟实现消息队列

目录 1. 需求分析1.1 介绍一些核心概念核心概念1核心概念2 1.2 消息队列服务器&#xff08;Broker Server&#xff09;要提供的核心 API1.3 交换机类型1.3.1 类型介绍1.3.2 转发规则&#xff1a; 1.4 持久化1.5 关于网络通信1.5.1 客户端与服务器提供的对应方法1.5.2 客户端额外…