栈
1.栈的概念及结构
栈:一种特殊的线性表,只允许在固定的一段进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶,另一端称为栈底。栈中的数据元素遵守先进后出的原则。
压栈:栈的插入操作叫做进栈\压栈,入数据在栈顶。
出栈: 栈的删除操作叫做出栈,出数据也在栈顶。
2.栈的应用: 1.改变元素的次序 2.括号的匹配 3.用栈将递归转换为循环
3.栈的基本操作:
typedef int SData;
//栈中没有任意位置的插入和删除,若要使用,使用顺序表 栈不需要遍历
//动态栈
typedef struct Stack
{
SData* array;
int capacity;
int size; //栈中元素的个数 栈顶
}Stack;
void StackInit(Stack* ps)
{
assert(ps);
ps->array = (SData*)malloc(sizeof(SData) * 10);
if (ps->array == NULL)
{
assert(0);
return;
}
ps->capacity = 10;
ps->size = 0;
}
void CheakCapacity(Stack* ps)
{
assert(ps);
if (ps->capacity == ps->size)
{
//1 开辟新空间
SData* temp = (SData*)malloc(sizeof(SData) * ps->size * 2);
if (temp == NULL)
{
assert(0);
return;
}
//2 拷贝元素
memcpy(temp, ps->array, sizeof(SData) * ps->size * 2);
//3 释放旧空间
free(ps->array);
//4 使用新空间
ps->array = temp;
ps->capacity *= 2;
}
}
//入栈: 尾插
void StackPush(Stack* ps, SData data)
{
//assert(ps);
CheakCapacity(ps);//插入之前一定要检测是否扩容
ps->array[ps->size++] = data;
}
//出栈; 尾插
void StackPop(Stack* ps)
{
if (StackEmpty(ps))
return;
ps->size--;
}
//获取栈顶元素
SData StackTop(Stack* ps)
{
assert(!StackEmpty(ps));//不为空才能获取栈顶元素
return ps->array[ps->size - 1];
}
//获取栈中有效元素的个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->size;
}
//检测栈是否为空
int StackEmpty(Stack* ps)
{
assert(ps);
return ps->size == 0;
}
//销毁栈
void StackDestory(Stack* ps)
{
assert(ps);
free(ps->array);
ps->array = NULL;
ps->capacity = 0;
ps->size = 0;
}
队列
1.队列的概念及结构
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾 出队列:进行删除操作的一端称为队头
2.队列的实现
队列也可以数组和链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
连续空间进行存储:
入队列:相当于在连续空间中进行尾插操作,时间复杂度O(1)
出队列:相当于在连续空间中进行头删
出对列操作:
1.保持队头不动,直接将后序的元素整体往前搬移一个位置,时间复杂度O(N)
2.让队头指针往后移动,优点是不需要搬移元素,时间复杂度O(1),缺点是当rear移动到空间末尾时,不能直接插入元素,否则就会越界
队列的假溢出:空间中还有3个空余位置可以插入元素 -->解决方案:循环队列
队列的真溢出:空间中有效元素个数已经达到空间的最大值
循环队列
循环队列创建好之后,没有向队列中存储任何元素,即空队列,front == rear在同一位置,
注意:内存没有环状,下图是为了方便理解给出的一种图解
队列的插入:
插入元素,每次插入到队尾的位置,即rear的位置,插入完成后让rear往后移动,在插入元素时,当front==rear时,队列已满
注意:当rear移动到空间末尾时,必须将rear置为0回到空间的起始位置。当rear追上front时,说明循环队列中元素已经存满
新的问题:如何判断队列是空还是满?
1.少用一个存储空间,假如满的话用(rear+1)%容量 == front即为空间已满,空的话front == rear
2.用flag标记,将flag的初始值设置为0,每次插入元素时将flag设置为1,每次删除元素时将flag设置为0
队列空:front == rear && flag == 0
队列满:front == rear && flag == 1
3.设置一个计数count,记录队列中有效元素的个数,
对列空:count == 0
队列满:count == 空间容量
队列的模拟实现:
用两个栈模拟实现队列:
typedef int DataType;
typedef struct stack
{
DataType* array;
int capacity;
int size;
}Stack;
//栈的初始化
void StackInit(Stack* ps)
{
assert(ps);
ps->array = (DataType*)malloc(sizeof(DataType)*3);
ps->capacity = 3;
ps->size = 0;
}
void CheckCapacity(Stack* ps)
{
if(ps->size >= ps->capacity)
{
//申请新空间
int newCapacity = ps->capacity * 2;
DataType* temp = (DataType*)malloc(sizeof(DataType)*newCapacity);
if(temp)
{
for(int i = 0; i < ps->size; ++i)
temp[i] = ps->array[i];
//释放旧空间
free(ps->array);
ps->array = temp;
ps->capacity = newCapacity;
}
}
}
//检测栈是否为空
int StackEmpty(Stack* ps)
{
assert(ps);
return 0 == ps->size;
}
//入栈
void StackPush(Stack* ps, DataType data)
{
assert(ps);
CheckCapacity(ps);
//插入元素
ps->array[ps->size] = data;
ps->size++;
}
//出栈
void StackPop(Stack* ps)
{
if(StackEmpty(ps))
return;
ps->size--;
}
//获取栈顶元素
DataType StackTop(Stack* ps)
{
assert(ps);
return ps->array[ps->size - 1];
}
//获取栈中有效元素的个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->size;
}
//销毁
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->array);
ps->capacity = 0;
ps->size = 0;
}
typedef struct {
Stack s1; //模拟入队列
Stack s2; //模拟出队列
} MyQueue;
/** Initialize your data structure here. */
MyQueue* myQueueCreate() {
MyQueue* mq = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&mq->s1);
StackInit(&mq->s2);
return mq;
}
/** Push element x to the back of queue. */
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->s1, x);
}
/** Removes the element from in front of queue and returns that element. */
int myQueuePop(MyQueue* obj) {
if(StackEmpty(&obj->s2))
{
//将s1中的元素搬移到s2中
while(!StackEmpty(&obj->s1))
{
StackPush(&obj->s2, StackTop(&obj->s1));
StackPop(&obj->s1);
}
}
int ret = StackTop(&obj->s2);//将栈顶元素放到ret中
StackPop(&obj->s2);//删除栈顶元素
return ret;
}
/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
if(StackEmpty(&obj->s2))
{
//将s1中的元素搬移到s2中
while(!StackEmpty(&obj->s1))
{
StackPush(&obj->s2, StackTop(&obj->s1));
StackPop(&obj->s1);
}
}
return StackTop(&obj->s2);
}
/** Returns whether the queue is empty. */
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->s1) && StackEmpty(&obj->s2);
}
void myQueueFree(MyQueue* obj) {
//free之前先销毁栈上的数据
StackDestroy(&obj->s1);
StackDestroy(&obj->s2);
free(obj);
}