#pragma once
#include
#include
#include
#include
/*
要改的永远是栈结构体中的成员变量,
改结构体中的成员变量只需要传入结构体地址即可
参数用一级指针即可
而删除stack时,也只需要把内部数组释放
*/
typedef int STDataType;
typedef struct Stack
{
STDataType* _a; // 用指针类型 用数组 这是动态的 且栈一般定义的是动态的
int _top; // 栈顶
int _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
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
// 数据结构中,一般获取任何值都需要调函数,不要直接输出top之类的值
// 且不同操作不同函数,是一种低耦合 解耦,即不同函数,代码不同
#include"ds_2_stack.h"
// 栈的初始化:做栈数组大小初始化,以及指针在-1还是0,-1和0的区别是 插入和删除时,先动针还是先动数
void StackInit(Stack* ps)
{
// 栈不可以为空
assert(ps);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
// 因为初始 top和capacity相等所以插入要扩容
if (ps->_top == ps->_capacity)
{
int newCapacity = ps->_capacity ==0?4:ps->_capacity*2;
// realloc:(原始数组名,新大小)
STDataType* tmp = (STDataType*)realloc(ps->_a, newCapacity*sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->_a = tmp;
// 容量是多少
ps->_capacity = newCapacity;
}
// 直接给数组值:因top初始为0,0可放,所以先放再加
ps->_a[ps->_top] = data;
ps->_top++;
}
void StackPop(Stack* ps)
{
assert(ps);
// asset中放希望,希望栈不空,所以是 !empty
assert(!StackEmpty(ps));
ps->_top--;
}
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->_a[ps->_top-1]; // 在前一个位置
}
bool StackEmpty(Stack* ps)
{
assert(ps);
// top在0为空
return ps->_top == 0;
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->_top;
}
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->_a); // 释放
ps->_a = NULL; //防止野指针
ps->_top = ps->_capacity = 0; // top归0 容量清0
}
// 判断括号匹配
#define _CRT_SECURE_NO_WARNINGS
#include"ds_2_stack.h"
void TestStack()
{
Stack st;
StackInit(&st); // 一级指针,所以传入地址
/*
数据结构如果直接访问,可能会出错,因为你不知道内部实现,比如这里的top,初始化不确定是0或1
if (st._top > 0)
{
;
}*/
StackPush(&st, 1);
StackPush(&st, 2);
StackPush(&st, 3);
StackPush(&st, 4);
int cur;
while (!StackEmpty(&st))
{
cur = StackTop(&st);
StackPop(&st);
printf("出去的是%d \n", cur);
}
StackDestroy(&st);
}
int main()
{
TestStack();
return 0;
}
注意:
该队列每个元素存在链表节点中,求size时,直接遍历一遍,也可以直接
#include
#include
#include
#include
#include
typedef int QDataType;
typedef struct QListNode
{
// 队列每个元素是链表节点,而链表节点内应该是 next和data
struct QListNode* _next;
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
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_rear = NULL;
}
/* 注意两个错误:1.节点的data给值
* 2. 给node->next =NULL
* 3. 另外注意做push要区分是第一次push还是后push
*/
void QueuePush(Queue* q, QDataType data)
{
assert(q);
// 先申请队列的每个元素:链表节点
struct QListNode* node = (struct QListNode*)malloc(sizeof(struct QListNode));
// 每次创建新节点 应该让next为NULL
node->_next = NULL;
if (node == NULL)
{
perror("push_malloc fail");
exit(-1);
}
// 没有给它值 犯了错了 没给data
// 如果是第一次
if (q->_front == NULL)
{
q->_front = q->_rear = node; // next不用置空
q->_front->_data = data;
}
else
{
q->_rear->_next = node;
q->_rear = node;
q->_rear->_data = data;
}
}
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
出队,或删除,一定要单独拿出这个节点,free更直接,不然front先做next
struct QListNode* head = q->_front;
// 头变节点的下一个
q->_front = q->_front->_next;
free(head);
// 如果出队完,应该防止尾变野指针,所以置NULL
if (!q->_front)
{
q->_front = q->_rear = NULL;
}
// 只有一个节点
/*if (q->_front->_next == NULL)
{
free(q->_front);
q->_front = q->_rear = NULL;
}
else
{
QNode* del = q->_front;
q->_front = q->_front->_next;
free(del);
}*/
}
QDataType QueueFront(Queue* q)
{
assert(q);
// 头指针为空,也要报错
assert(!QueueEmpty(q));
return q->_front->_data;
}
// 把Empty换bool吧
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_rear->_data;
}
bool QueueEmpty(Queue* q)
{
assert(q);
// 头尾等且其一为NULL
return q->_front == q->_rear && q->_rear == NULL;
}
int QueueSize(Queue* q)
{
assert(q);
int size = 0;
QNode* cur = q->_front;
// 从来没有给尾巴后面练过NULL,这里会不会错
while (cur)
{
++size;
cur = cur->_next;
}
return size;
}
void QueueDestroy(Queue* q)
{
assert(q);
// 一个个节点来出来删
struct QListNode* cur = q->_front;
while (cur)
{
struct QListNode* next = cur->_next;
free(cur);
cur = next;
}
// 最后都置空
q->_front = q->_rear = NULL;
}
注意点:(本人犯过的错误):
return q->_front == q->_rear && q->_rear == NULL;
return q->_front == q->_rear && q->_rear == NULL;
循环数组是怎样循环起来的:我们定义结构体,内部使用动态数组a开辟固定长度。循环队列大小常常固定不变。此外,连接起来是因为我们在做入队操作和出队操作时,通过+N再加上对N取模,与实际空间位置无关,它之所以循环,是因为队列等数据结构具逻辑性。即:人为赋予逻辑关系。
typedef struct {
int front;
int rear;
int* a;// 用数组来开辟空间
} MyCircularQueue;
// 内核是数组
typedef struct {
int front;
int rear;
int* a; // 用数组来开辟空间
int N; // 空间(比size大1)
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (struct MyCircularQueue*)malloc(sizeof(MyCircularQueue));
// k是队列元素个数 真实空间要大1
obj->a = (int*)malloc(sizeof(int)*(k+1));
obj->front = 0;
obj->rear = 0;
obj->N = k+1; // 空间
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear + 1)%(obj->N) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
// 没有满,才能插
if (myCircularQueueIsFull(obj))
{
return false;
}
// 没满就放了++
else
{
obj->a[obj->rear] = value;
obj->rear++;
// 防止obj在最后超过一圈
obj->rear %= obj->N;
return true;
}
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
return false;
else
{
// 数组删数据不需要清
obj->front++;
obj->front %= obj->N;
return true;
}
}
int myCircularQueueFront(MyCircularQueue* obj) {
// 空返回-1
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->a[obj->front];
}
}
// ** 4 第2点: 注意巧妙的写法 ***
int myCircularQueueRear(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
// 取队尾 应是减1位,但是可能rear在0位置
// 只能判断back是不是0
return obj->a[(obj->rear - 1 + obj->N) % obj->N];
}
}
// 注意这里有两个malloc,所以就malloc两次
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
return ;
}
leetcode232
typedef struct Stack
{
int* stk; // 栈内核也是数组
int top; // 栈大小也就是指针
int stkCapacity; //栈的容量
// 奇怪它不用指针吗
}Stack;
// 栈的大小
// param:输入栈大小
Stack* stackCreate(int capacity)
{
// 用malloc 注意:栈和队列,均要用两次malloc,结构体本身和内部的stk
Stack* ret = (struct Stack*)malloc(sizeof(Stack));
ret->stk = (int*)malloc(sizeof(int)*capacity);
ret->stkCapacity = capacity;
ret->top = 0; // 让起始位置为0 所以先存再++
return ret;
}
// 这里先不做满的判断
void stackPush(Stack* st, int val) {
// 容量:top从0开始
printf("给位置%d存值\n", st->top);
st->stk[st->top] = val;
printf("push栈时接收到的val:%d\n", val);
st->top++;
}
void stackPop(Stack* st)
{
// 因为是数组,直接减
st->top--;
}
int stackTop(Stack* st)
{
return st->stk[st->top-1];
}
bool stackEmpty(Stack* st)
{
return st->top==0;
}
void stackFree(Stack* st)
{
// 这里我比leetcode答案多写了一行
free(st->stk);
free(st);
}
// 队列使用栈实现:需要的是出的栈的指针和入的栈的指针
typedef struct {
Stack* ins; // 接收放
Stack* outs; // 发送放
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* ret = (MyQueue*)malloc(sizeof(MyQueue));
ret->ins = stackCreate(100);
ret->outs = stackCreate(100);
return ret;
}
// 1. 只要栈的发送方有,就都给栈接收方
void out2to(MyQueue* que)
{
// 只要发送栈不空
printf("这里是out2in\n");
while (!stackEmpty(que->outs))
{
int val = stackTop(que->outs);
stackPop(que->outs);
printf("out2in调用了pop\n");
printf("out2in时,对ins做push\n");
stackPush(que->ins, val);
}
}
void myQueuePush(MyQueue* obj, int x) {
// 入队,给ins->val
printf("que_push\n");
printf("que的push应该先给outs,下面是outs在做push\n");
stackPush(obj->outs, x);
printf("outs_push完了\n");
}
// 队列做出队,我们要出接收方,而接收方如果没有就不能出队,所以先做发送,如果有,就直接发送
int myQueuePop(MyQueue* obj) {
// 出队应该出接收方
if(stackEmpty(obj->ins))
{
out2to(obj);
}
// 判断完是否空,下面的是一定要做的操作
int val;
val = stackTop(obj->ins);
printf("这里是que的pop,下面调用了ins做pop\n");
stackPop(obj->ins);
return val;
}
// 队列的队首:如果ins没有了,就直接做发送操作
// 最后必须做的肯定是返回top值
int myQueuePeek(MyQueue* obj) {
if (stackEmpty(obj->ins))
{
printf("peek调用了out2in\n");
out2to(obj);
}
return stackTop(obj->ins);
}
bool myQueueEmpty(MyQueue* obj) {
return stackEmpty(obj->ins)&&stackEmpty(obj->outs);
}
void myQueueFree(MyQueue* obj) {
stackFree(obj->outs);
stackFree(obj->ins);
}
收获:1. empty判断
2. malloc,总结:
3. 得不到某些值,或者某些值特别大:是因为我压根没给值,或者我st->top = 。应该是st->a[st->top] = val;
leetcode225
我今天使用单链表实现一次试试。
方法(一) : C++版本:使用STL库,该库中的队列是循环队列。
思路(一):
做法:1. 队栈做push,把x插到队尾。利用循环,pop一下push一下,至队尾之前所有元素。
class MyStack {
public:
// 使用队自带循环队列的库
queue<int> que;
MyStack() {
}
void push(int x) {
// 放元素,先入队,此时新元素在队尾
que.push(x);
// 先push后,做1~size-1次后移
for(int i = 1; i <que.size();i++)
{
que.push(que.front());
que.pop();
}
}
int pop() {
// pop返回队首元素
int t = que.front();
que.pop();
return t;
}
int top() {
// 要栈首,返回队首即可
return que.front();
}
bool empty() {
// 队空即栈空
return que.empty();
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
方法(二):用两个队列(单链表)去实现栈。
一般情况下,两个队列永远是一个有值,一个无值。
push:
#include
#include
#include
#include
#include
typedef int QDataType;
typedef struct QListNode
{
// 队列每个元素是链表节点,而链表节点内应该是 next和data
struct QListNode* _next;
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
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);
void QueueInit(Queue* q)
{
assert(q);
q->_front = q->_rear = NULL;
}
/* 注意两个错误:1.节点的data给值
* 2. 给node->next =NULL
* 3. 另外注意做push要区分是第一次push还是后push
*/
void QueuePush(Queue* q, QDataType data)
{
assert(q);
// 先申请队列的每个元素:链表节点
struct QListNode* node = (struct QListNode*)malloc(sizeof(struct QListNode));
// 每次创建新节点 应该让next为NULL
node->_next = NULL;
if (node == NULL)
{
perror("push_malloc fail");
exit(-1);
}
// 没有给它值 犯了错了 没给data
// 如果是第一次
if (q->_front == NULL)
{
q->_front = q->_rear = node; // next不用置空
q->_front->_data = data;
}
else
{
q->_rear->_next = node;
q->_rear = node;
q->_rear->_data = data;
}
}
void QueuePop(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
出队,或删除,一定要单独拿出这个节点,free更直接,不然front先做next
struct QListNode* head = q->_front;
// 头变节点的下一个
q->_front = q->_front->_next;
free(head);
// 如果出队完,应该防止尾变野指针,所以置NULL
if (!q->_front)
{
q->_front = q->_rear = NULL;
}
// 只有一个节点
/*if (q->_front->_next == NULL)
{
free(q->_front);
q->_front = q->_rear = NULL;
}
else
{
QNode* del = q->_front;
q->_front = q->_front->_next;
free(del);
}*/
}
QDataType QueueFront(Queue* q)
{
assert(q);
// 头指针为空,也要报错
assert(!QueueEmpty(q));
return q->_front->_data;
}
// 把Empty换bool吧
QDataType QueueBack(Queue* q)
{
assert(q);
assert(!QueueEmpty(q));
return q->_rear->_data;
}
bool QueueEmpty(Queue* q)
{
assert(q);
// 头尾等且其一为NULL
return q->_front == q->_rear && q->_rear == NULL;
}
int QueueSize(Queue* q)
{
assert(q);
int size = 0;
QNode* cur = q->_front;
// 从来没有给尾巴后面练过NULL,这里会不会错
while (cur)
{
++size;
cur = cur->_next;
}
return size;
}
void QueueDestroy(Queue* q)
{
assert(q);
// 一个个节点来出来删
struct QListNode* cur = q->_front;
while (cur)
{
struct QListNode* next = cur->_next;
free(cur);
cur = next;
}
// 最后都置空
q->_front = q->_rear = NULL;
}
// 匿名结构体定义成MyStack
// 结构体S需要两个成员que
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj = (MyStack*)malloc(sizeof(MyStack));
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
// 哪个que不空,就给哪个插
void myStackPush(MyStack* obj, int x) {
if (!QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1, x);
}
else
{
QueuePush(&obj->q2, x);
}
}
// 哪个队不空 就出队哪个
int myStackPop(MyStack* obj) {
Queue* empty = &obj->q1;
Queue* nonempty = &obj->q2;
if (!QueueEmpty(&obj->q1))
{
empty = &obj->q2;
nonempty = &obj->q1;
}
// 只要大于1,就把队列数据前n-1个导入空队列 剩下一个是站定元素
while (QueueSize(nonempty) > 1)
{
QueuePush(empty, QueueFront(nonempty));
QueuePop(nonempty);
}
// 从非空中拿第一个
int top = QueueFront(nonempty);
QueuePop(nonempty);
return top;
}
// 做题默认不会出现空时的调用
// 这里再想想玩什么吧
int myStackTop(MyStack* obj) {
if (!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
printf("都空了吗%d\n", QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2));
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
// 只要是分开的空间,利用了多个malloc就需要挨个去free,
// 直接free(某个值节点不可以)
void myStackFree(MyStack* obj) {
// 因为stack中的que是结构体,所以需要传&取地址
QueueDestroy(&obj->q2);
QueueDestroy(&obj->q1);
free(obj);
}
/**
* Your MyStack struct will be instantiated and called as such:
* MyStack* obj = myStackCreate();
* myStackPush(obj, x);
* int param_2 = myStackPop(obj);
* int param_3 = myStackTop(obj);
* bool param_4 = myStackEmpty(obj);
* myStackFree(obj);
*/
int main()
{
MyStack* st;
st = myStackCreate();
myStackPush(st, 1);
int val = myStackTop(st);
printf("top:%d\n", val);
int p_val = myStackPop(st);
printf("pop:%d\n", val);
printf("empty:%d", myStackEmpty(st));
return 0;
}
“方法(三)”:错误的,不可取, 利用C语言自写单向队列:只使用一个队列时,单项队列的头和尾,一直在变化,这个题会非常复杂。
typedef int STDataType;
typedef struct Stack
{
STDataType* _a; // 用指针类型 用数组 这是动态的 且栈一般定义的是动态的
int _top; // 栈顶
int _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 StackDestroy(Stack* ps);
// 栈的初始化:做栈数组大小初始化,以及指针在-1还是0,-1和0的区别是 插入和删除时,先动针还是先动数
void StackInit(Stack* ps)
{
// 栈不可以为空
assert(ps);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
void StackPush(Stack* ps, STDataType data)
{
assert(ps);
// 因为初始 top和capacity相等所以插入要扩容
if (ps->_top == ps->_capacity)
{
int newCapacity = ps->_capacity ==0?4:ps->_capacity*2;
// realloc:(原始数组名,新大小)
STDataType* tmp = (STDataType*)realloc(ps->_a, newCapacity*sizeof(STDataType));
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->_a = tmp;
// 容量是多少
ps->_capacity = newCapacity;
}
// 直接给数组值:因top初始为0,0可放,所以先放再加
ps->_a[ps->_top] = data;
ps->_top++;
}
void StackPop(Stack* ps)
{
assert(ps);
// asset中放希望,希望栈不空,所以是 !empty
assert(!StackEmpty(ps));
ps->_top--;
}
STDataType StackTop(Stack* ps)
{
assert(ps);
assert(!StackEmpty(ps));
return ps->_a[ps->_top-1]; // 在前一个位置
}
int StackEmpty(Stack* ps)
{
assert(ps);
// top在0为空
return ps->_top == 0;
}
int StackSize(Stack* ps)
{
assert(ps);
return ps->_top;
}
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->_a); // 释放
ps->_a = NULL; //防止野指针
ps->_top = ps->_capacity = 0; // top归0 容量清0
}
bool isValid(char* s) {
struct Stack* st;
st = (Stack*)malloc(sizeof(Stack));;
StackInit(st);
while (*s)
{
if (*s == '(' || *s == '[' || *s == '{')
{
StackPush(st, *s);
}
else
{
// 右括号多的情况:即栈内空了,当前是右括号
if(StackEmpty(st))
{
return false;
}
char t = StackTop(st);
if (*s == ')')
{
if (t != '(')
{
return false;
}
}
else if (*s == ']')
{
if (t != '[')
{
return false;
}
}
else if (*s == '}')
{
if (t != '{')
{
return false;
}
}
StackPop(st);
}
s++;
}
// 最后栈不空,肯定里面是因为有左括号,所以就直接返回错
if (!StackEmpty(st))
{
return false;
}
return true;
}