当前位置: 首页 > ops >正文

每日算法题【栈和队列】:栈和队列的实现、有效的括号、设计循环队列

(1)栈的实现
// 支持动态增长的栈
typedef int STDatatype;
typedef struct Stack
{STDatatype* a;int top;		// 栈顶int capacity;  // 容量 
}Stack;// 初始化栈 
void StackInit(Stack* ps){//判空assert(ps);//初始化ps->a = NULL;ps->top = ps->capacity = 0;	//top = 0,top指向的是下一个要插入的位置
}// 入栈 
void StackPush(Stack* ps, STDatatype data){assert(ps);//如果没有空间插入需要申请空间扩容if(ps->top == ps->capacity){//先给容量标志位更新到扩容之后的容量int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//再给数组进行扩容STDatatype* tmp = (STDatatype*)realloc(ps->a,newcapacity*sizeof(STDatatype));//检查是否扩容成功if(tmp == NULL){perror("realloc fail");return;}//成功就进行更新ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->top] = data;ps->top++; 
}// 出栈 
void StackPop(Stack* ps){assert(ps);//删除数据之前确保有数据assert(ps->top > 0);ps->top--;
}// 获取栈顶元素 
STDatatype StackTop(Stack* ps){assert(ps);assert(pd->top > 0);return ps->a[ps->top-1];
}// 获取栈中有效元素个数 
int StackSize(Stack* ps){assert(ps);return ps->top;
} // 检测栈是否为空,如果为空返回true,如果不为空返回fasle
int StackEmpty(Stack* ps){assert(ps);if(ps->top == 0){return true;}else{return false;}
}// 销毁栈 
void StackDestroy(Stack* ps){assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}

(2)括号匹配问题
  • [20. 有效的括号 - 力扣(LeetCode)]:

  • 解题思路:

    • 如果是左括号就入栈,如果是右括号就出栈进行比较,如果比较相同类型就出栈并继续这一步骤,如果是不同类型或者栈为空就报错
    • 当s全部被遍历一遍之后,查看栈中是否还有符号,有就报错,没有就返回true
    bool isValid(char* s) {Stack st;StackInit(&st);while(*s){//如果是左括号就入栈if(*s == '('|| *s == '{'|| *s == '['){StackPush(&st,*s);++s;}else{//如果是右括号就出栈进行比较//如果栈中没有左括号,则不匹配if(StackEmpty(&st) == true){StackDestroy(&st);return false;}//如果出栈的括号不匹配也返回falseSTDatatype top = StackTop(&st);StackPop(&st);if((*s == '}' && top != '{')|| (*s == ')' && top != '(')|| (*s == ']' && top != '[')){StackDestroy(&st);return false;}else{++s;}}}//当s全部被遍历一遍之后,查看栈中是否还有符号,有就报错,没有就返回truebool ret = StackEmpty(&st);StackDestroy(&st);return ret == false ? false : true;}
    

(3)队列的实现
// 链式结构:表示队列 
//队列中的节点
typedef struct QListNode 
{ struct QListNode* next; QDatatype val; 
}QNode; // 队列的结构 
typedef struct Queue 
{ QNode* head; //链表头QNode* tail;  //链表尾int size;	//记录队列中的元素个数
}Queue; // 初始化队列 
void QueueInit(Queue* q){assert(q);q->head = NULL;q->tail = NULL;q->size = 0;
}// 队尾入队列 
void QueuePush(Queue* q, QDatatype x){assert(q);//为新节点申请空间QNode* newnode = (QNode*)malloc(sizeof(QNode));if(newnode == NULL){perror("malloc fail");return;}//对新节点进行初始化newnode->next = NULL;newnode->val = x;//如果队列链表为空if(q->tail == NULL){q->head = q->tail = newnode;}else{//如果队列链表不为空q->tail->next = newnode;q->tail = newnode;}q->size++;
}// 队头出队列 
void QueuePop(Queue* q){assert(q);assert(q->tail != NULL); //不能对空链表进行头删//如果链表只有一个节点if(q->size == 1){free(q->head); //释放点head指针所指的节点q->head = q->tail = NULL;}else{//如果链表有多个节点QNode* Next = q->head->next;free(q->head);q->head = Next;}q->size--;   
}// 获取队列头部元素 
QDatatype QueueFront(Queue* q){assert(q);assert(q->tail != NULL);return q->head->val;
}// 获取队列队尾元素 
QDatatype QueueBack(Queue* q){assert(q);assert(q->tail != NULL);return q->tail->val;   
}// 获取队列中有效元素个数 
int QueueSize(Queue* q){assert(q);return q->size;
}// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q){assert(q);    return q->size == 0; //队列为空返回TRUE 不为空返回FALSE
}// 销毁队列 
void QueueDestroy(Queue* q){assert(q);//循环遍历释放队列链表的每一个节点QNode* cur = q->head;while(cur){QNode* Next = cur->next;free(cur);cur = Next;}q->head = NULL;q->tail = NULL;q->size = 0;
}

(4)设计循环队列
  • [622. 设计循环队列 - 力扣(LeetCode)]:

  • 解题思路:

    循环队列的结构:
    在普通的线性队列中,队列指针(如队头指针和队尾指针)的范围是从 0 到队列容量减一。而在循环队列中,队尾指针在达到队列容量时不再继续增加,而是从队列的开头重新开始,形成了一个环形结构。

    取模运算的作用:
    在循环队列中,我们使用取模运算(%)来实现队列指针的循环移动。具体来说,当队尾指针需要向后移动时,我们计算新的队尾位置为 (tail + 1) % capacity,其中 tail 是当前队尾指针的位置,capacity 是队列的容量。这样可以保证当队尾指针达到队列容量时,取模运算会使其重新回到队列的开头,实现了环形结构。

    #include<stdio.h>
    #include<stdlib.h>
    #include<stdbool.h>typedef struct {int * array; //数组指针int front; //队头指针int rear; //队尾指针int capacity; //容量int size; //有效元素个数    
    } MyCircularQueue; //先进先出结构// 函数前向声明
    MyCircularQueue* myCircularQueueCreate(int k);
    bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);
    bool myCircularQueueDeQueue(MyCircularQueue* obj);
    int myCircularQueueFront(MyCircularQueue* obj);
    int myCircularQueueRear(MyCircularQueue* obj);
    bool myCircularQueueIsEmpty(MyCircularQueue* obj);
    bool myCircularQueueIsFull(MyCircularQueue* obj);
    void myCircularQueueFree(MyCircularQueue* obj);//创建环形队列
    MyCircularQueue* myCircularQueueCreate(int k) {//申请循环队列结构体的内存空间MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//申请队列数组的内存空间obj->array = (int*)malloc(k * sizeof(int));obj->capacity = k;obj->size = 0;obj->front = 0;obj->rear = -1; //初始化队尾指针为-1,这样第一个元素的下标正好是0return obj;
    }//插入值
    bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {// 如果队列已满,则返回 falseif (myCircularQueueIsFull(obj)) {return false;}// 队尾指针后移一位,考虑到环形结构,使用取模运算确保指针位置在合法范围内(尾进)obj->rear = (obj->rear + 1) % obj->capacity;// 将元素值插入到队尾指针所指向的位置obj->array[obj->rear] = value;obj->size++;  // 更新队列的当前元素个数return true;
    }//删除值
    bool myCircularQueueDeQueue(MyCircularQueue* obj) {// 如果队列为空,则返回 falseif (myCircularQueueIsEmpty(obj)) {return false;}// 队头指针后移一位,考虑到环形结构,使用取模运算确保指针位置在合法范围内(头出)obj->front = (obj->front + 1) % obj->capacity;obj->size--;  // 更新队列的当前元素个数return true;
    }//返回队首元素
    int myCircularQueueFront(MyCircularQueue* obj) {return myCircularQueueIsEmpty(obj) ? -1 : obj->array[obj->front]; //如果队列为空返回-1
    }//返回队尾元素
    int myCircularQueueRear(MyCircularQueue* obj) {return myCircularQueueIsEmpty(obj) ? -1 : obj->array[obj->rear]; //如果队列为空返回-1
    }//判断队列是否为空
    bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->size == 0;
    }//判断队列是否为满
    bool myCircularQueueIsFull(MyCircularQueue* obj) {return obj->size == obj->capacity;
    }//循环队列的销毁
    void myCircularQueueFree(MyCircularQueue* obj) {free(obj->array);  // 先释放数组内存free(obj);         // 再释放结构体内存
    }/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
    */
    
http://www.xdnf.cn/news/19286.html

相关文章:

  • [软考中级]嵌入式系统设计师—考核内容分析
  • Redis持久化之AOF(Append Only File)
  • Java基础知识(十二)
  • 8.31【Q】CXL-DMSim:
  • vue3+vite+ts 发布npm 组件包
  • Deep Think with Confidence:llm如何进行高效率COT推理优化
  • 第24章学习笔记|用正则表达式解析文本文件(PowerShell 实战)
  • zkML-JOLT——更快的ZK隐私机器学习:Sumcheck +Lookup
  • Pytest 插件介绍和开发
  • leetcode 260 只出现一次的数字III
  • COLA:大型语言模型高效微调的革命性框架
  • 免费电脑文件夹加密软件
  • 基于Adaboost集成学习与SHAP可解释性分析的分类预测
  • 【K8s】整体认识K8s之存储--volume
  • 在win服务器部署vue+springboot + Maven前端后端流程详解,含ip端口讲解
  • Transformer架构三大核心:位置编码(PE)、前馈网络(FFN)和多头注意力(MHA)。
  • 学习Python中Selenium模块的基本用法(12:操作Cookie)
  • TFS-2005《A Possibilistic Fuzzy c-Means Clustering Algorithm》
  • 使用 Python 自动化检查矢量面数据的拓扑错误(含导出/删除选项)
  • 算法题(196):最大异或对
  • 特殊符号在Html中的代码及常用标签格式的记录
  • Qt组件布局的经验
  • 线程池、锁策略
  • 机器视觉opencv教程(四):图像颜色识别与颜色替换
  • Linux中的ss命令
  • kotlin - 2个Activity实现平行视图,使用SplitPairFilter
  • 网络流量分析——使用Wireshark进行分析
  • Shell脚本编程——变量用法详解
  • Ruoyi-vue-plus-5.x第二篇MyBatis-Plus数据持久层技术:2.2 分页与性能优化
  • DAY17-新世纪DL(DeepLearning/深度学习)战士:Q(机器学习策略)2