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

一.栈的基本概念。

一.基本概念

1.基本概念

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

2.模拟实现

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

内容特性:
数据结构基础5:栈和队列的实现。_第1张图片
缓存利用:
----顺序表数据结构基础5:栈和队列的实现。_第2张图片
链表的缓存利用:
数据结构基础5:栈和队列的实现。_第3张图片

3.综上所述:

使用一个动态开辟的一个顺序表作为我们的栈的基础结构。
1.顺序表:缓存的利用率高。
2.顺序表尾插尾删的效率都比较高。
结构体定义
数据结构基础5:栈和队列的实现。_第4张图片

二.函数接口实现

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
#include
#include
#include

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这个结构体只需要创建一次就是一个队列这样我们
数据结构基础5:栈和队列的实现。_第5张图片

二.接口实现

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

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
#include
#include
#include

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;
}

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

题目一:

数据结构基础5:栈和队列的实现。_第6张图片
题目链接

主要思路:

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;
    }
}

题目二:

数据结构基础5:栈和队列的实现。_第7张图片

主要思路:

数据结构基础5:栈和队列的实现。_第8张图片
题目链接

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);
}

题目三:

数据结构基础5:栈和队列的实现。_第9张图片
题目链接

主要思路:

数据结构基础5:栈和队列的实现。_第10张图片

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);
}

题目四:

数据结构基础5:栈和队列的实现。_第11张图片
题目链接

主要思路一:

数据结构基础5:栈和队列的实现。_第12张图片

//节点的结构体
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.获取数据使用的判断空和满的函数使用需要细心。

数据结构基础5:栈和队列的实现。_第13张图片
数据结构基础5:栈和队列的实现。_第14张图片

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);
}

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

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

你可能感兴趣的:(数据结构)