栈和队列的模拟实现

1.栈的模拟实现

1.1变量和函数接口声明

#ifndef _STACK_H_
#define _STACK_H_

#include <windows.h>
#include <stdio.h>
#include <assert.h>

typedef int STDataType;

typedef struct Stack
{
    
    
	STDataType *arr;
	int _top;
	int _capacite;
}stack;


void StackInit(stack *ps);//初始化
void StackDestory(stack *ps);//销毁
void StackPush(stack *ps,STDataType data);//入栈
STDataType StackTop(stack *ps);//获取栈顶元素
void StackPop(stack *ps);//出栈
int StackSize(stack *ps);//获取栈内元素个数
int StackEmpty(stack *ps);//判断是否为空

#endif

1.2初始化

栈的特性是先进后出,即在栈顶操作,因此我们可以利用顺序表进行实现,因为顺序表的尾插尾删的复杂度都为O(1);

void StackInit(stack *ps)//初始化
{
    
    
	assert(ps);
	STDataType *node = (STDataType*)malloc(sizeof(STDataType)* 2);
	assert(node);
	ps->arr = node;
	ps->_top = 0;
	ps->_capacite = 2;
}

1.3销毁

直接释放我们的顺序表,这是传1级指针的原因是为了保持接口的一致性,至于外部的野指针问题,我觉得既然调用了销毁接口就应该明白不能再次引用;

void StackDestory(stack *ps)//销毁
{
    
    
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->_top = ps->_capacite = 0;
}

1.4入栈

栈是由顺序表进行实现的,入栈很简单,直接在数组的尾端加入元素即可,只是需要判定下空间的容量是否足够;

void StackPush(stack *ps,STDataType data)//入栈
{
    
    
	assert(ps);

	if (ps->_top == ps->_capacite)
	{
    
    
		ps->_capacite *= 2;
		ps->arr = (STDataType*)realloc(ps->arr, sizeof(STDataType)*ps->_capacite);
	}
	ps->arr[ps->_top++] = data;

}

1.5获取栈顶元素、出栈、获取栈内元素个数、判空

我们给定的栈的结构体中函数有顺序表的元素个数,因此实现这些结接口是非常方便的;

STDataType StackTop(stack *ps)//获取栈顶元素
{
    
    
	assert(ps);
	assert(ps->_top != 0);
	return ps->arr[ps->_top-1];
}
void StackPop(stack *ps)//出栈
{
    
    
	assert(ps);
	assert(ps->_top != 0);
	ps->_top--;
}
int StackSize(stack *ps)//获取栈内元素个数
{
    
    
	assert(ps);
	return ps->_top;
}
int StackEmpty(stack *ps)//判断是否为空
{
    
    
	assert(ps);
	if (ps->_top == 0)
		return 1;
	else
		return 0;
}

2.队列的实现

2.1 变量和函数接口声明

#ifndef _QUEUE_H_
#define _QUEUE_H_

#include <stdio.h>
#include <windows.h>
#include <assert.h>

typedef BTNode* QDataType;

typedef struct QListNode
{
    
    
	QDataType _data;
	struct QListNode* _next;
}QNode;

typedef struct Queue
{
    
    
	QNode *_front;
	QNode *_rear;
}Queue;

void QueueInit(Queue *q);//初始化
void QueueDestory(Queue *q);//销毁
void QueuePush(Queue *q,QDataType data);//入队
void QueuePop(Queue *q);//出队
QDataType QueueFront(Queue *q);//获取队首元素
QDataType QueueBack(Queue *q);//获取队尾元素
int QueueSize(Queue *q);//获取元素个数
int QueueEmpty(Queue *q);//判断是否为空

#endif

2.2初始化

队列的性质是先进先出,因此我们用给定尾指针的单向链表来实现。因为数组的头插和头删的时间复杂度都为O(1),相对来说用链表来实现更佳;

初始化时,头尾指针都指向NULL,此时的队列为空

void QueueInit(Queue *q)//初始化
{
    
    
	assert(q);
	q->_front = q->_rear = NULL;
}

2.3销毁

由于队列是链表结构,因此我们需要利用循环对其进行销毁,销毁后尾指针的位置需要进行更新;

void QueueDestory(Queue *q)//销毁
{
    
    
	assert(q);
	QNode *cur = q->_front;
	QNode *next = NULL;
	while (cur)
	{
    
    
		next = cur->_next;
		free(cur);
		cur = next;
	}
	q->_front = q->_rear = NULL;
}

2.4入队

入队即在链表的位段链接一个节点,此时需要判定下当前队列的头尾指针是否都指向空;

void QueuePush(Queue *q, QDataType data)//入队
{
    
    
	QNode *node = (QNode*)malloc(sizeof(QNode));
	assert(node);
	
	node->_data = data;
	node->_next = NULL;

	if (q->_front == NULL)//第一个
	{
    
    
		q->_front = q->_rear = node;
	}
	else
	{
    
    
		q->_rear->_next = node;
		q->_rear = node;
	}

}

2.5出队

出队即通过操作头指针向后一个节点进行移动,释放前面一个节点,如果全部释放完了,尾指针需要置空;

void QueuePop(Queue *q)//出队
{
    
    
	assert(q);
	assert(q->_front);
	
	QNode *next = q->_front->_next;
	free(q->_front);
	q->_front = next;

	if (q->_front == NULL)
		q->_rear = NULL;//队为空

}

2.6获取队首队尾元素

判空后直接通过首尾指针进行获取;

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

2.7获取元素的个数

给一个计数器变量,通过循环的方式获取节点的个数;

int QueueSize(Queue *q)//获取元素个数
{
    
    
	assert(q);
	QNode *cur = q->_front;
	int size = 0;
	while (cur)
	{
    
    
		cur = cur->_next;
		size++;
	}
	return size;
}

2.8判断是否为空

判断是否为空,即头指针是否指向NULL;

int QueueEmpty(Queue *q)//判断是否为空
{
    
    
	assert(q);
	if (q->_front == NULL)
		return 1;
	else
		return 0;
}

猜你喜欢

转载自blog.csdn.net/ych9527/article/details/112305462