栈和队列的互相实现
栈
栈一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶。
栈的实现可以是顺序表,也可以是链表,主要还是看使用者的个人喜好,各有利弊。
顺序表实现栈的基本结构
typedef int STDataType;
#define MAX 50
typedef struct Stack
{
STDataType* arr;
STDataType top;
STDataType capacity;
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps);
初始化栈,顺序表的动态扩容
// 初始化栈
void StackInit(Stack* ps)
{
assert(ps);
ps->capacity = MAX;
ps->arr = (STDataType*)calloc(ps->capacity,sizeof(STDataType));
ps->top = 0;
}
//扩容
void AddCapacity(Stack* ps)
{
assert(ps);
ps->capacity *= 2;
ps->arr = (STDataType*)realloc(ps->arr, sizeof(STDataType)*ps->capacity);
}
入栈,出栈
// 入栈
void StackPush(Stack* ps, STDataType data)
{
assert(ps && data);
if (ps->top == ps->capacity)
{
AddCapacity(ps);
}
ps->arr[ps->top++] = data;
}
// 出栈
void StackPop(Stack* ps)
{
assert(ps);
if (ps->top == 0)
{
return;
}
ps->top--;
}
获取栈顶元素,判断栈是否为空,栈中元素个数
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
assert(ps);
return ps->arr[ps->top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
assert(ps);
return ps->top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0
int StackEmpty(Stack* ps)
{
assert(ps);
return ps->top == 0 ? 1 : 0;
}
队列
队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出 FIFO(First In First Out) 的特点
- 入队列:进行插入操作的一端称为队尾
- 出队列:进行删除操作的一端称为队头
和栈相同的一点就是,队列可以用链式结构来实现,也可以用顺序结构来实现,还可以实现循环队列,让队头和队尾逻辑上建立一个循环。
简单实现以下队列(链式结构)的操作
typedef int QDataType;
// 链式结构:表示队列
typedef struct QListNode
{
struct QListNode* _pNext;
QDataType _data;
}QNode;
// 队列的结构
typedef struct Queue
{
QNode* _front;
QNode* _rear;
}Queue;
// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
初始化队列,入队和出队
// 初始化队列
void QueueInit(Queue* q)
{
assert(q);
q->_rear = q->_front = NULL;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
assert(q);
QNode* node = (QNode*)malloc(sizeof(QNode));
node->_data = data;
node->_pNext = NULL;
if (!q->_rear)
{
q->_front = q->_rear = node;
}
else
{
q->_rear->_pNext = node;
q->_rear = node;
}
}
// 队头出队列
void QueuePop(Queue* q)
{
assert(q);
if (!q->_front)
{
return;
}
if (q->_front == q->_rear)
{
q->_front = q->_rear = NULL;
}
else
{
q->_front = q->_front->_pNext;
}
}
队头队尾元素获取,队列的判空,队列的销毁
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
assert(q->_front);
return q->_front->_data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
assert(q->_rear);
return q->_rear->_data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
assert(q);
int num = 0;
QNode* node = q->_front;
while (node)
{
num++;
node = node->_pNext;
}
return num;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
int QueueEmpty(Queue* q)
{
assert(q);
return q->_front ? 0 : 1;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->_front;
while (cur != NULL)
{
QNode* next = cur->_pNext;
free(cur);
cur = next;
}
q->_front = q->_rear = NULL;
}
栈和队列既然都是数据的存储结构,那么也有一种可能,就是可以用栈来模拟一个队列的操作,也可以用队列来模拟一个栈。
栈模拟队列
用栈来模拟队列先进先出的特点,前提就是要让栈顶指针指向最先进入的元素,而栈是先进后出,这就需要另一个栈来当做一个容器,将先进栈的元素,变成后进栈的元素,再利用栈的出栈来实现队列的出栈。
这时栈2就出现了一个合理的队列,栈1可以当做入队列的栈,当栈2为空时,再把栈1的元素倒进栈2。
typedef struct {
Stack s1;
Stack s2;
} MyQueue;
void myQueuePush(MyQueue* obj, int x) {
Stack* a,*b;
//a为空栈,入栈时使用 b为有值时的栈,出栈时使用
a=&(obj->s1);
b=&(obj->s2);
StackPush(a,x);
}
/**从队列前面移除元素并返回该元素。 */
int myQueuePop(MyQueue* obj) {
Stack* a,*b;
//a为空栈,入栈时使用 b为有值时的栈,出栈时使用
a=&(obj->s1);
b=&(obj->s2);
int num=0;
if(StackEmpty(b))
{
while(StackSize(a)!=1)
{
StackPush(b,StackTop(a));
StackPop(a);
}
num=StackTop(a);
StackPop(a);
}
else
{
num=StackTop(b);
StackPop(b);
}
return num;
}
/** 得到前面的元素. */
int myQueuePeek(MyQueue* obj) {
Stack* a,*b;
//a为空栈,入栈时使用 b为有值时的栈,出栈时使用
a=&(obj->s1);
b=&(obj->s2);
int num=0;
if(StackEmpty(b))
{
while(StackSize(a)!=0)
{
StackPush(b,StackTop(a));
StackPop(a);
}
}
num=StackTop(b);
return num;
}
/** 返回队列是否为空. */
bool myQueueEmpty(MyQueue* obj) {
Stack* a,*b;
//a为空栈,入栈时使用 b为有值时的栈,出栈时使用
a=&(obj->s1);
b=&(obj->s2);
if(StackSize(a)+StackSize(b)==0)
{
return true;
}
return false;
}
/** 队列的销毁 **/
void myQueueFree(MyQueue* obj) {
Stack* a,*b;
//a为空栈,入栈时使用 b为有值时的栈,出栈时使用
a=&(obj->s1);
b=&(obj->s2);
free(a->arr);
free(b->arr);
free(obj);
}
队列来模拟一个栈
用队列模拟一个栈,和用栈模拟一个队列原理相仿,只是,队列先进先出的特点,在弹栈的时候,不能直接将队列全部倒到另一个队列中,应该只留下一个队尾元素,然后出队列完成弹栈操作
typedef struct {
Queue Q1;
Queue Q2;
} MyStack;
/** 在这里初始化数据结构。 */
MyStack* myStackCreate() {
MyStack* my = (MyStack*)malloc(sizeof(MyStack));
/*my->Q1 = (Queue*)malloc(sizeof(Queue));
my->Q2 = (Queue*)malloc(sizeof(Queue));*/
QueueInit(&(my->Q1));
QueueInit(&(my->Q2));
return my;
}
/** 将元素x推入堆栈。 **/
void myStackPush(MyStack* obj, int x) {
Queue* a ;
Queue* b ;
if (QueueEmpty(&(obj->Q1)))
{
a = &(obj->Q1);
b = &(obj->Q2);
}
else
{
a = &(obj->Q2);
b = &(obj->Q1);
}
QueuePush(b, x);
}
/** 删除堆栈顶部的元素并返回该元素. */
int myStackPop(MyStack* obj) {
Queue* a;
Queue* b;
if (QueueEmpty(&(obj->Q1)))
{
a = &(obj->Q1);
b = &(obj->Q2);
}
else
{
a = &(obj->Q2);
b = &(obj->Q1);
}
if (QueueSize(b) == 0)
{
return 0;
}
while (QueueSize(b) > 1)
{
QueuePush(a, QueueFront(b));
QueuePop(b);
}
QDataType ans = QueueFront(b);
QueuePop(b);
return ans;
}
/** 获取顶部元素. */
int myStackTop(MyStack* obj) {
Queue* a;
Queue* b;
if (QueueEmpty(&(obj->Q1)))
{
a = &(obj->Q1);
b = &(obj->Q2);
}
else
{
a = &(obj->Q2);
b = &(obj->Q1);
}
return QueueBack(b);
}
/** 返回堆栈是否为空. */
bool myStackEmpty(MyStack* obj) {
Queue* a;
Queue* b;
if (QueueEmpty(&(obj->Q1)))
{
a = &(obj->Q1);
b = &(obj->Q2);
}
else
{
a = &(obj->Q2);
b = &(obj->Q1);
}
if (QueueEmpty(b))
{
return true;
}
return false;
}
/** 销毁栈. */
void myStackFree(MyStack* obj) {
Queue* a;
Queue* b;
if (QueueEmpty(&(obj->Q1)))
{
a = &(obj->Q1);
b = &(obj->Q2);
}
else
{
a = &(obj->Q2);
b = &(obj->Q1);
}
QueueDestroy(b);
free(obj);
}