栈:是一种特殊的·线性表,其只允许在固定的一端进行插入和删除元素操作
进行数据插入和删除操作的一端成为栈顶,另一端成为栈底。
栈遵循的原则:是先进后出。
栈的实现一般可以使用数组或者链表来实现,相对而言数组的结构实现会更优, 因为在数组在尾上插入数据的代价比较小。
注意:栈不能遍历
常用操作的模拟实现:
初始化、入栈、出栈、获取元素的个数、判空、获取栈定元素。
我们实现的是支持动态增长的栈
.h文件
# pragma once
typedef int DataType;
typedef struct stack
{
DataType* arr;
int capacity;
//表示栈中有多少元素——栈顶
int size;
}stack;
//初始化栈
void StackInit(stack* ps);
//入栈
void StackPush(stack* ps, DataType data);
//出栈
void StackPop(stack* ps);
//获取栈顶元素
DataType StackTop(stack* ps);
//获取栈中有效个数
int StackSize(stack* ps);
//检测栈是否为空
int StackEmpty(stack* ps);
//销毁栈
void StackDestroy(stack* ps);
int Capacity(stack* ps);
.c文件
# include
# include
# include
# include "ZList.h"
//栈的初始化
void StackInit(stack* ps)
{
assert(ps);
ps->arr = (DataType*)malloc(sizeof(DataType)* 3);
if (NULL == ps->arr)
{
assert(0);
return;
}
ps->capacity = 3;
ps->size = 0;
}
//自动给栈扩容
void Checkcapacity(stack* ps)
{
assert(ps);
if (ps->size == ps->capacity)
{
ps->arr = (DataType*)realloc(ps->arr, sizeof(DataType)*ps->capacity * 2);
if (NULL == ps->arr)
{
assert(0);
return;
}
ps->capacity *= 2;
}
}
int Capacity(stack* ps)
{
assert(ps);
return ps->capacity;
}
//入栈
void StackPush(stack* ps, DataType data)
{
assert(ps);
Checkcapacity(ps);
ps->arr[ps->size++] = data;
}
//出栈
void StackPop(stack* ps)
{
assert(ps);
if (StackEmpty(ps))
return;
ps->size--;
}
//获取栈顶元素
DataType StackTop(stack* ps)
{
assert(ps&&!StackEmpty(ps));
return ps->arr[ps->size - 1];
}
//获取栈中有效元素
int StackSize(stack* ps)
{
assert(ps);
return ps->size;
}
//检测链表是否为空
int StackEmpty(stack* ps)
{
assert(ps);
return 0 == ps->size;
}
//销毁栈
void StackDestroy(stack* ps)
{
assert(ps);
if (ps->arr)
{
free(ps->arr);
ps->arr = NULL;
ps->capacity = 0;
ps->size = 0;
}
}
void TestStack()
{
stack s;
StackInit(&s);
StackPush(&s, 1);//入栈
StackPush(&s, 2);
StackPush(&s, 3);
StackPush(&s, 4);
StackPush(&s, 5);
StackPush(&s, 6);
StackPush(&s, 7);
printf("capacity = %d\n", Capacity(&s));
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", StackTop(&s));
StackPop(&s);//出栈
StackPop(&s);
StackPop(&s);
StackPop(&s);
StackPop(&s);
printf("capacity = %d\n", Capacity(&s));
printf("size = %d\n", StackSize(&s));
printf("top = %d\n", StackTop(&s));
StackDestroy(&s);
}
int main()
{
TestStack();
}
解题思路:
1.依次获取每个括号
2.检测该括号是左括号还是右括号
是左括号则入栈
是右括号----如果是有效匹配则之前一定有和之匹配的左括号
3.检测该括号和栈顶的括号是否匹配
)和( }和{ ]和[
匹配的话:栈顶的左括号出栈
否则:括号不匹配
程序部分:
核心代码
bool isValid(char * s)
{
bool flag=false;
stack st;
StackInit(&st);
//"(" ")"
for(int i=0;i<strlen(s);++i)
{
//如果是左括号,
if('('==s[i]||'['==s[i]||'{'==s[i])
{
//入栈
StackPush(&st,s[i]);
}
else
{
//如果拿到右括号
//但是栈刚好是空的
if(StackEmpty(&st))
{
StackDestroy(&st);
return false;
}
//检测该括号和栈顶的括号是否匹配
char top=StackTop(&st);
if(s[i]==')'&&top=='('||
s[i]==']'&&top=='['||
s[i]=='}'&&top=='{')
{
StackPop(&st);
}
else
{
break;
}
}
}
if(StackEmpty(&st))
{
flag=true;
}
StackDestroy(&st);
return flag;
}
队列:只允许在一端进行插入数据的操作,在另一端进行数据删除的特殊线性表。进行插入一端称为队尾;进行删除的一段成为队头。
遵循原则:先进先出
队列也可以用数组和链表结构实现,不过在使用链表的结构实现更好,因为,使用数组的结构,出队列的效率会比较低。
入队列的操作时间复杂度尾 O(N),因为需要将元素整体搬移。
所以这里采用带头单向链表实现队列:
核心代码
.h文件
#pragma once
// 此处采用带头单链表来实现队列
typedef int DataType;
//节点的结构
typedef struct QNode
{
struct QNode* next;
DataType data;
}QNode;
//队列的结构
typedef struct Queue
{
QNode* front;
QNode* rear;
}Queue;
//队列的初始化
void QueueInit(Queue* q);
// 入队列
void QueuePush(Queue* q, DataType data);
// 出队列
void QueuePop(Queue* q);
// 获取队头元素
DataType QueueFront(Queue* q);
// 获取队尾元素
DataType QueueBack(Queue* q);
// 获取队列中有效元素的个数
int QueueSize(Queue* q);
// 检测队列是否为空
int QueueEmpty(Queue* q);
// 将队列销毁掉
void QueueDestroy(Queue* q);
void TestQueue();
.c文件
#include "DLList.h"
#include
#include
#include
QNode* BuyQueueNode(DataType data)
{
QNode* node = (QNode*)malloc(sizeof(QNode));
if (NULL == node)
{
assert(0);
return NULL;
}
node->data = data;
node->next = NULL;
return node;
}
void QueueInit(Queue* q)
{
assert(q);
q->front = q->rear = BuyQueueNode(0);
}
// 入队列
void QueuePush(Queue* q, DataType data)
{
//从尾部插入
assert(q);
q->rear->next = BuyQueueNode(data);
q->rear = q->rear->next;
}
// 出队列
void QueuePop(Queue* q)
{
QNode* delNode = NULL;
if (QueueEmpty(q))
return;
delNode = q->front->next;
q->front->next = delNode->next;
// 队列中只有1个元素,将该元素删除之后,需要让rear指向头节点的位置
if (NULL == delNode->next)
q->rear = q->front;
free(delNode);
}
// 获取队头元素
DataType QueueFront(Queue* q)
{
assert(!QueueEmpty(q));
//q->front为头节点->next为第一个节点->data 值域的值
return q->front->next->data;
}
// 获取队尾元素
DataType QueueBack(Queue* q)
{
assert(!QueueEmpty(q));
return q->rear->data;
}
// 获取队列中有效元素的个数
int QueueSize(Queue* q)
{
assert(q);
int count = 0;
QNode* cur = q->front->next;
while (cur)
{
++count;
cur = cur->next;
}
return count;
}
// 检测队列是否为空
int QueueEmpty(Queue* q)
{
assert(q);
return NULL == q->front->next;
}
// 将队列销毁掉
void QueueDestroy(Queue* q)
{
assert(q);
QNode* cur = q->front;
while (cur)
{
q->front = cur->next;
free(cur);
cur = q->front;
}
q->front = q->rear = NULL;
}
void TestQueue()
{
Queue q;
QueueInit(&q);//初始化
QueuePush(&q, 1);//入队列
printf("size = %d\n", QueueSize(&q));//有效元素个数
printf("front = %d\n", QueueFront(&q));//对头元素
printf("back = %d\n", QueueBack(&q));//队尾元素
QueuePush(&q, 2);
QueuePush(&q, 3);
QueuePush(&q, 4);
QueuePush(&q, 5);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);//出队列
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
QueuePop(&q);
QueuePop(&q);
printf("size = %d\n", QueueSize(&q));
printf("front = %d\n", QueueFront(&q));
printf("back = %d\n", QueueBack(&q));
QueuePop(&q);
printf("size = %d\n", QueueSize(&q));
if (QueueEmpty(&q))
{
printf("EMPTY!!!\n");
}
else
{
printf("Error!!!\n");
}
QueueDestroy(&q);
}
int main()
{
TestQueue();
}
该题的思路我用图文加文字的形式:
程序部分:
核心代码
typedef struct {
Queue q1;
Queue q2;
} MyStack;
/** Initialize your data structure here. */
MyStack* myStackCreate() {
//这个位置需要用malloc从堆上开辟空间
MyStack* ms=(MyStack*)malloc(sizeof(MyStack));
if(NULL==ms)
{
return NULL;
}
QueueInit(&ms->q1);
QueueInit(&ms->q2);
return ms;
}
//入栈
/** Push element x onto stack. */
void myStackPush(MyStack* obj, int x) {
//插入非空的队列
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) {
int ret=0;
if(!QueueEmpty(&obj->q1))
{
//需要将q1中前n-1个元素导入到q2中
while(QueueSize(&obj->q1)>1)
{
QueuePush(&obj->q2, QueueFront(&obj->q1));
QueuePop(&obj->q1);
}
ret=QueueFront(&obj->q1);
QueuePop(&obj->q1);
}
else
{
//需要将q2中前n-1个元素导入到q2中
while(QueueSize(&obj->q2)>1)
{
QueuePush(&obj->q1, QueueFront(&obj->q2));
QueuePop(&obj->q2);
}
//将最后一个元素保存起来
ret=QueueFront(&obj->q2);
//将最后一个数据删除掉
QueuePop(&obj->q2);
}
return ret;
}
//取栈顶
/** Get the top element. */
int myStackTop(MyStack* obj) {
//哪个不空取队尾元素
if(!QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else{
return QueueBack(&obj->q2);
}
}
/** Returns whether the stack is empty. */
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
在这里以图文加解释的方式给出
程序部分:
核心代码
typedef struct {
stack s1;//模拟队尾 ,入队列
stack s2;//模拟队头,出队列
} MyQueue;
/** Initialize your data structure here. */
MyQueue* myQueueCreate() {
MyQueue* mq=(MyQueue*)malloc(sizeof(MyQueue));
if(NULL==mq)
{
return NULL;
}
StackInit(&mq->s1);
StackInit(&mq->s2);
return mq;
}
//入栈q1,模拟入队列
/** 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) {
//s2模拟出队列
//如果s2是空的,将s1中的元素搬移到s2中
if(StackEmpty(&obj->s2))
{
while(!StackEmpty(&obj->s1))
{
StackPush(&obj->s2,StackTop(&obj->s1));
StackPop(&obj->s1);
}
}
int ret=StackTop(&obj->s2);
StackPop(&obj->s2);
return ret;
}
//获取队头元素
/** Get the front element. */
int myQueuePeek(MyQueue* obj) {
if(StackEmpty(&obj->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) {
StackDestroy(&obj->s1);
StackDestroy(&obj->s2);
free(obj);
}
解题思路:
循环队列是为了解决队列假溢出的情况,使开辟的空间不被浪费。
判断循环队列是空还是满?
1.少存储一个数据
2.使用计数 count
count= =0,是为空
count= =NULL,则为满。
循环队列主要的实现:入队和出队。
入队中的实现:先判断队列是否满了,如果不满则有两种情况:
如果队尾刚好在空间的末尾则将队尾的元素放在0号下标的位置。
如果正常入队,则是将元素尾插进去,然后将尾的位置rear向后移动。
出队的实现:先判断队列是否为空,如果不为空将头的位置front向后移动,
如果front移到了最后一个位置则将front放在0的下标号。
front每移动一个,count就减少一个。
获取队尾的位置:如果rear在0号标号,则返回最后一个元素,
否则,返回rear-1;
剩余步骤的实现则较为常规。
程序部分:
核心代码
typedef struct {
int* arr;
int capacity;
int front;
int back;
int count;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* mq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//在堆上创建了结构体变量
if(NULL==mq)
{
return NULL;
}
mq->arr=(int*)malloc(sizeof(int)*k);
if(NULL==mq->arr)
{
return NULL;
}
mq->capacity=k;
mq->front=mq->back=mq->count=0;
return mq;
}
//判空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->count==0;
}
//队列满了
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return obj->count==obj->capacity;
}
//入队
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
{
return false;
}
//rear可能刚好在队列的末尾位置
if(obj->back == obj->capacity)
{
obj->back=0;
}
obj->arr[obj->back++]= value;
obj-> count++;
return true;
}
//出队
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
if(obj->front==obj->capacity)
{
obj->front=0;
}
obj->count--;
return true;
}
//获取队列首元素
int myCircularQueueFront(MyCircularQueue* obj){
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->arr[obj->front];
}
//队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
//如果rear在下标号为0的位置
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
//if(0==obj->back)
// {
// return obj->arr[obj->capacity-1];
// }
// else
//{
//return obj->arr[obj->back-1];
//}
return obj->arr[(obj->back-1+obj->capacity)%obj->capacity];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
将自己所学的知识进行总结,归纳,需要改进的地方还有许多,继续加油吧!!!