数据结构----栈和队列
Posted 4nc414g0n
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构----栈和队列相关的知识,希望对你有一定的参考价值。
栈和队列
栈
栈
:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out
)的原则
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据也在栈顶
栈的实现一般可以使用数组或者链表实现,相对而言数组的结构实现更优一些。因为数组在尾上插入数据的代价比较小。
栈的接口实现
结构
typedef int STDatatype; typedef struct Stack { STDatatype *a; int top; int capacity; }ST;
入栈
void StackPush(ST* ps, STDatatype x) { assert(ps); // 检查空间够不够,不够就增容 if (ps->top == ps->capacity) { int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2; STDatatype* tmp = (STDatatype*)realloc(ps->a, >sizeof(STDatatype)*newcapacity); if (tmp == NULL) { printf("rellaoc fail\\n"); exit(-1); } ps->a = tmp; ps->capacity = newcapacity; } ps->a[ps->top] = x; ps->top++; }
初始化和销毁
void StackInit(ST* ps) { assert(ps); ps->a = NULL; ps->top = 0; // -1 ps->capacity = 0; } void StackDestroy(ST* ps) { assert(ps); if (ps->a) { free(ps->a); } ps->a = NULL; ps->top = 0; ps->capacity = 0; }
出栈
void StackPop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); --ps->top; }
判空 大小 栈顶
bool StackEmpty(ST* ps) { assert(ps); return ps->top == 0; } int StackSize(ST* ps) { assert(ps); return ps->top; } STDatatype StackTop(ST* ps) { assert(ps); assert(!StackEmpty(ps)); return ps->a[ps->top - 1]; }
队列
队列
:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First In First Out
)
入队列:进行插入操作的一端称为队尾
出队列:进行删除操作的一端称为队头
队列也可以数组和链表的结构实现,使用链表的结构实现更优
一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低
队列的接口实现
结构
typedef int QDataType; typedef struct QueueNode { struct QueueNode* next; QDataType data; }QueueNode; typedef struct Queue { QueueNode* phead; QueueNode* ptail; }Queue;
初始化 销毁
void QueueInit(Queue* pq) { assert(pq); pq->phead = NULL; pq->ptail = NULL; } void QueueDestory(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); QueueNode* cur = pq->phead; while (cur->next) { QueueNode* next = cur->next; free(cur); cur = next; } pq->phead = pq->ptail = NULL; }
入队
void QueuePush(Queue* pq, QDataType x) { assert(pq); QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode)); newnode->next = NULL; newnode->data = x; if (newnode == NULL) { perror("Push"); exit(-1); } if (pq->phead == NULL) pq->phead = pq->ptail = newnode; else { pq->ptail->next = newnode; pq->ptail = pq->ptail->next; } }
出队
void QueuePop(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); if (pq->phead->next == NULL) { free(pq->phead); //free(pq->ptail);//重复释放会崩溃 pq->phead = NULL; pq->ptail = NULL; } else { QueueNode* next = pq->phead->next; free(pq->phead); pq->phead = next; } }
大小 队头 队尾 判空
int QueueSize(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); QueueNode* cur = pq->phead; int size = 0; while (cur->next) { size++; cur = cur->next; } } QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->phead->data; } QDataType QueueBack(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->ptail->data; } bool QueueEmpty(Queue* pq) { assert(pq); return pq->phead == NULL && pq->ptail == NULL; }
总结
链表要改变传入的指针(
改变头
):
- 传二级指针
- 带哨兵位(避开改变)
- 返回值接收新的地址
- 结构体包裹(详见上面队列的实现)
队列拓展(环形队列)
循环队列是一种线性数据结构,其操作表现基于 FIFO原则 并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
环形队列可以使用数组实现,也可以使用循环链表实现
我们下面使用数组实现
我们定义两个节点(头尾 front rear)为区分满的状态和空的状态,我们需要额外增加一个空的空间作为满的标识(rear+1=front)
注意:
当rear在数组位时额外讨论
((obj->front)%=(obj->k+1))取模
实现接口
结构
typedef struct { int *a;//动态数组 int front; int rear; int k;//最多存放元素个数 } MyCircularQueue;
初始化 释放
MyCircularQueue* myCircularQueueCreate(int k) { MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue)); obj->a=(int*)malloc(sizeof(int)*(k+1)); obj->k=k; obj->front=0; obj->rear=0; return obj; } void myCircularQueueFree(MyCircularQueue* obj) { assert(obj); free(obj->a); free(obj); }
判空判满
bool myCircularQueueIsEmpty(MyCircularQueue* obj) { assert(obj); if(obj->front==obj->rear) return true; else return false; } bool myCircularQueueIsFull(MyCircularQueue* obj) { assert(obj); if((obj->rear+1)%(obj->k+1)==obj->front)//当rear在数组尾时(数组有>k+1个元素,下标最大为k) return true; else return false; }
入队出队
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { assert(obj); if(myCircularQueueIsFull(obj)) return false; obj->a[obj->rear]=value; (obj->rear)++; (obj->rear)%=(obj->k+1); return true; } bool myCircularQueueDeQueue(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) return false; obj->front++; (obj->front)%=(obj->k+1); return true; }
头尾元素
int myCircularQueueFront(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) return -1; return obj->a[obj->front]; } int myCircularQueueRear(MyCircularQueue* obj) { assert(obj); if(myCircularQueueIsEmpty(obj)) return -1; return obj->rear==0?obj->a[obj->k]:obj->a[obj->rear-1]; //当rear为0的时候减1会出现问题 }
用队列实现栈
分析
:
- 定义两个队列
- 入栈操作相当于给非空队列进行入队操作
- 出栈操作相当于非空队列的队尾元素出队,此时需要把非空队列除最后一个元素之外的其余元素入队到空队列,然后出队最后一个队尾元素
typedef struct {
Queue q1;
Queue q2;
} MyStack;
/** Initialize your data structure here. */
MyStack* myStackCreate() {
MyStack* mstk=(MyStack*)malloc(sizeof(MyStack));
QueueInit(&mstk->q1);
QueueInit(&mstk->q2);
return mstk;
}
/** Push element x onto stack. */
void myStackPush(MyStack* obj, int x) {
assert(obj);
QueueNode* newnode=(QueueNode*)malloc(sizeof(QueueNode));
if(!QueueEmpty(&obj->q1)){
QueuePush(&obj->q1,x);
}
else{
QueuePush(&obj->q2,x);
}
}
/** Removes the element on top of the stack and returns that element. */
int myStackPop(MyStack* obj) {
assert(obj);
Queue* empty=&obj->q1;
Queue* nonempty=&obj->q2;
if(QueueEmpty(&obj->q2))
{
empty=&obj->q2;
nonempty=&obj->q1;
}
while(QueueSize(nonempty)>1)
{
QueuePush(empty,QueueFront(nonempty));
QueuePop(nonempty);
}
int front=QueueFront(nonempty);
QueuePop(nonempty);
return front;
}
/** Get the top element. */
int myStackTop(MyStack* obj) {
assert(obj);
if(QueueEmpty(&obj->q2))
return QueueBack(&obj->q1);
else
return QueueBack(&obj->q2);
}
/** Returns whether the stack is empty. */
bool myStackEmpty(MyStack* obj) {
assert(obj);
return (QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2));
}
void myStackFree(MyStack* obj) {
assert(obj);
QueueDestory(&obj->q1);
QueueDestory(&obj->q2);
free(obj);
}
用栈实现队列
分析
:
- 创建两个栈,一个栈进行入队操作,另一个栈进行出队操作
- 出队操作: 当出队的栈不为空是,直接进行出栈操作,如果为空,需要把入队的栈元素全部导入到出队的栈,然后再进行出栈操作
typedef struct {
//入队栈
Stack pushST;
//出队栈
Stack popST;
} MyQueue;
/** Initialize your data structure here. */
MyQueue* myQueueCreate(int maxSize) {
MyQueue* pqueue = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&pqueue->pushST, maxSize);
StackInit(&pqueue->popST, maxSize);
return pqueue;
}
/** Push element x to the back of queue. */
void myQueuePush(MyQueue* obj, int x) {
//入队栈进行入栈操作
StackPush(&obj->pushST, x);
}
/** Removes the element from in front of queue and returns that element. */
int myQueuePop(MyQueue* obj) {
//如果出队栈为空,导入入队栈的元素
if(StackEmpty(&obj->popST) == 0)
{
while(StackEmpty(&obj->pushST) != 0)
{
StackPush(&obj->popST, StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
int front = StackTop(&obj->popST);
//出队栈进行出队操作
StackPop(&obj->popST);
return front;
}
/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
//类似于出队操作
if(StackEmpty(&obj->popST) == 0)
{
while(StackEmpty(&obj->pushST) != 0)
{
StackPush(&obj->popST, StackTop(&obj->pushST));
StackPop(&obj->pushST);
}
}
return StackTop(&obj->popST);
}
/** Returns whether the queue is empty. */
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST) ==以上是关于数据结构----栈和队列的主要内容,如果未能解决你的问题,请参考以下文章