栈
遵循LIFO原则
数据插入和删除的一端称为栈顶
栈的实现
数组,双向带头循环链表,单链表均可
头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int STDataType;
struct Stack
{
STDataType* a;
int top;//栈顶
int capacity;//容量,方便增容
};
typedef struct Stack Stack;
void StackInit(Stack* pst);
void StackDestroy(Stack* pst);
//性质决定了只能在栈顶出入数据
void StackPush(Stack* pst, STDataType x);
void StackPop(Stack* pst);
STDataType StackTop(Stack* pst);
bool StackEmpty(Stack* pst);
int StackSize(Stack* pst);
初始化和销毁
void StackInit(Stack* pst)
{
assert(pst);
//初始时给一定空间大小方便增容
pst->a = (STDataType*)malloc(sizeof(STDataType)*4);
pst->top = 0;
pst->capacity = 4;
}
void StackDestroy(Stack* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->capacity = pst->top = 0;
}
Push&Pop
//性质决定了只能在栈顶出入数据
void StackPush(Stack* pst, STDataType x)
{
assert(pst);
if (pst->top == pst->capacity)
{
STDataType* tmp = realloc(pst->a, sizeof(STDataType) * pst->capacity * 2);
if (tmp == NULL)
{
printf("realloc fail\n");
exit(-1);//结束整个程序,return是结束当前函数
}
pst->a = tmp;
pst->capacity *= 2;
}
pst->a[pst->top] = x;
pst->top++;
}
void StackPop(Stack* pst)
{
assert(pst);
//非空才能删除
assert(!StackEmpty(pst));
pst->top--;//无需取抹除原来空间的元素,只要访问不到就行
}
是否为空
bool StackEmpty(Stack* pst)
{
assert(pst);
return pst->top == 0;
}
求大小
int StackSize(Stack* pst)
{
assert(pst);
return pst->top;//top恰好就是size大小
}
取栈顶元素
//取栈顶元素
STDataType StackTop(Stack* pst)
{
assert(pst);
//非空才能取值
assert(!StackEmpty(pst));
return pst->a[pst->top-1];
}
Test文件
void Test()
{
Stack st;
StackInit(&st);
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
StackPush(&st, 5);
//栈不支持print接口,因为只能后进先出
while (!StackEmpty(&st))
{
printf("%d ", StackTop(&st));
StackPop(&st);
}
StackDestroy(&st);
}
int main()
{
Test();
return 0;
}
队列
FIFO先进先出
队列的实现
用单链表更合适
头文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
//取队头数据
QDataType QueueFront(Queue* pq);
//取队尾数据
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
初始化&销毁
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
Push&Pop
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));
if (newnode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
//如果没有节点
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
void QueuePop(Queue* pq)
{
//对头出数据,即头删
assert(pq);
assert(!QueueEmpty(pq));//队列为空
if (pq->head->next == NULL)
{
//只有一个节点的情况
free(pq->head);
pq->head = pq->tail = NULL;
}
else
{
QueueNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
取值
//取队头数据
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));//队列为空
return pq->head->data;
}
//取队尾数据
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));//队列为空
return pq->tail->data;
}
判空
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
求大小
int QueueSize(Queue* pq)
{
assert(pq);
int size = 0;
QueueNode* cur = pq->head;
while (cur)
{
size++;
cur = cur->next;
}
return size;
}
Test
void TestQueue()
{
Queue q;
QueueInit(&q);
QueuePush(&q, 1);
QueuePush(&q, 2);
printf("%d ", QueueFront(&q));
QueuePop(&q);
QueuePush(&q, 3);
QueuePush(&q, 4);
printf("%d ", QueueFront(&q));
QueuePop(&q);
QueuePush(&q, 5);
while (!QueueEmpty(&q))
{
//只能出队头
printf("%d ",QueueFront(&q));
QueuePop(&q);
}
printf("\n");
QueueDestroy(&q);
}
练习
20. 有效的括号
bool isValid(char * s)
{
Stack st;
StackInit(&st);
while(*s)
{
//左括号入栈
//右括号找最近的左括号匹配
if(*s == '[' || *s == '(' || *s == '{')
{
StackPush(&st,*s);
s++;
}
else
{
//为空,说明没有前括号
if(StackEmpty(&st))
{
//return之前一定要destroy,防止内存泄露
//编译器自身检查不出来内存泄露
StackDestroy(&st);
return false;
}
char top = StackTop(&st);
if((top =='[' && *s != ']')//不匹配
|| (top =='(' && *s != ')')
|| (top =='{' && *s != '}')
)
{
StackDestroy(&st);
return false;
}
else
{
//匹配的情况
StackPop(&st);
s++;
}
}
}
//如果只有左括号,stack不为空应该返回false
bool ret = StackEmpty(&st);
StackDestroy(&st);
return ret;
}
一定要防止内存泄露
225. 用队列实现栈
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* pst = (MyStack*)malloc(sizeof(MyStack));
//->优先级更高
QueueInit(&pst->q1);
QueueInit(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
//往不为空的队列入数据
if(!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1, x);
}
else
{
QueuePush(&obj->q2, x);
}
}
int myStackPop(MyStack* obj) {
Queue* pEmpty = &obj->q1;
Queue* pNonEmpty = &obj->q2;
if(!QueueEmpty(&obj->q1))
{
pEmpty = &obj->q2;
pNonEmpty = &obj->q1;
}
while(QueueSize(pNonEmpty)>1)
{
QueuePush(pEmpty,QueueFront(pNonEmpty));
//插入到空队列后要pop掉
QueuePop(pNonEmpty);
}
int front = QueueFront(pNonEmpty);
QueuePop(pNonEmpty);
return front;
}
int myStackTop(MyStack* obj) {
if(!QueueEmpty(&obj->q1))
{
//取队尾数据
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
//因为是值传递,不改变实参的值,置空也没用,需要在调用myStackFree接口之后手动置空
//obj = NULL;
}
232. 用栈实现队列
typedef struct {
Stack pushST;
Stack popST;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* q = (MyQueue*)malloc(sizeof(MyQueue));
StackInit(&q->pushST);
StackInit(&q->popST);
return q;
}
void myQueuePush(MyQueue* obj, int x) {
StackPush(&obj->pushST, x);
}
//remove the front element
int myQueuePop(MyQueue* obj) {
int top = myQueuePeek(obj);
StackPop(&obj->popST);
return top;
}
//Get the front element
int myQueuePeek(MyQueue* obj) {
//先判断popST是否为空
if(StackEmpty(&obj->popST))
{
//from pushST to popST
while(!StackEmpty(&obj->pushST))
{
StackPush(&obj->popST, StackTop(&obj->pushST));
//pop the element of pushST
StackPop(&obj->pushST);
}
}
//popST 不为空 直接Top the element
return StackTop(&obj->popST);
}
bool myQueueEmpty(MyQueue* obj) {
return StackEmpty(&obj->pushST) && StackEmpty(&obj->popST);
}
void myQueueFree(MyQueue* obj) {
//要销毁stack先
StackDestroy(&obj->pushST);
StackDestroy(&obj->popST);
free(obj);
//还需要在接口外面将obj置为NULL
}
622. 设计循环队列
- 如果front和tail指向同一个位置,那么空满条件都相同
- 解决:永远空一个位置 tail-> next== front 表示满 头尾相等表示空
typedef struct {
int* a;//数组
int k;//队列最多能存储的元素
int front;
int tail;//尾(队尾数据的下一个)
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
int tailNext = obj->tail+1;
//小心越界
if(tailNext == obj->k+1)
{
tailNext = 0;
}
return tailNext == obj->front;
}
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int)*(k+1));//k+1个空间
obj->front = 0;
obj->tail = 0;
obj->k = k;
return obj;
}
//入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
//判断是否满
if(myCircularQueueIsFull(obj))
{
return false;
}
else
{
obj->a[obj->tail] = value;
obj->tail++;
//超出范围回到0
if(obj->tail == obj->k+1)
{
obj->tail = 0;
}
//取模也行,但尽量不要用% CPU只有加法器
return true;
}
}
//删数据
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//判断是否空
if(myCircularQueueIsEmpty(obj))
{
return false;
}
else
{
obj->front++;
//超出范围回到0
if(obj->front == obj->k+1)
{
obj->front = 0;
}
//取模也行,但尽量不要用% CPU只有加法器
return true;
}
}
//get front element
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->a[obj->front];
}
}
//get rear element
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
int tailPrev = obj->tail-1;
if(tailPrev == -1)
{
tailPrev = obj->k;
}
return obj->a[tailPrev];
}
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
注意复用函数时要注意是否有声明