数据结构——栈和队列
栈是只允许在一端进行插入或删除操作的线性表
n个不同元素进栈,出栈元素不同排列的个数为Cn2n/n+1
顺序栈
//顺序栈的定义 typedef struct{ ElemType data[MaxSize]; int top;//栈顶指针,指向栈顶元素,返回数组下标压入4各元素该指针就是4 }SqStack; //判断栈空 bool StackEmpty(SqStack S){ if(S.top==-1) return true; else return false; } //初始化 void InitStack(SqStack &S){ S.top=-1; } //新元素入栈 bool Push(SqStack &S ,ElemType x){ if(S.top==MaxSize-1)//栈满 S.top=S.top+1;// S.data[S.top]=x;//S.data[++S.top]=x; return true; } //出栈操作 bool Push(SqStack &S ,ElemType &x){ if(S.top==-1)//栈空 return false; x=S.data[S.top];// S.top=S.top-1;//x=S.data[S.top--]; return true; } //读栈顶元素 bool Push(SqStack &S ,ElemType &x){ if(S.top==-1)//栈空 return false; x=S.data[S.top];//x记录栈顶元素 return true; } void testStack(){ SqStack S;//声明一个顺序栈 InitStack(S); }
链栈
队列
队列是只允许在一端进行插入,在另一端删除的线性表
!注意
rear在队尾元素下一位:先赋值再移动指针
rear指向队尾元素:先移动指针再赋值,在初始化时front指向0位置,rear指向n-1位置
顺序存储
//队列的顺序实现 typedef struct{ ElemType data[MaxSize]; int front,rear; }SqQueue; //判空 bool QueueEmpty(SqQueue Q){ if(Q.rear==Q.front) return true; else return false; } //入队 bool QueueEmpty(SqQueue &Q,ElemType x){ if((Q.rear+1)%MaxSize==Q.front)//队满条件:队尾指针的再下一个位置是队头 return false; Q.data[Q.rear]=x;//x插入对尾 Q.rear=(Q.rear+1)%MaxSize;//让rear指针循环往复 return true; } // bool QueueEmpty(SqQueue &Q,ElemType &x){ if(Q.rear==Q.front)//队满条件:队尾指针的再下一个位置是队头 return false; x=Q.data[Q.rear];//x插入对尾 Q.rear=(Q.rear+1)%MaxSize;//让rear指针循环往复 return true; }
链式存储
//队列的链式实现 typedef struct{ //链式队列结点 ElemType data; struct LinkNode *next; }LinkNode; typedef struct{ //链式队列 LinkNode *front,*rear; }LinkNodeQueue; //初始化 带头节点 void InitQueue(LinkQueue &Q){ Q.fronr=Q.rear=(LinkNode*)malloc(sizeof(LinkNode)); Q,front->next=NULL; } //判空 Q.front==Q.rear //初始化 不带头节点 void InitQueue(LinkQueue &Q){ Q,front=NULL; Q.rear=NULL; } //判空 Q.front==NULL //入队(带头节点) void EnQueue(LinkNodeQueue &Q,ElemType x){ LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode)); s->data=x; s->next=NULL;//插入到队尾,所以连接NULL Q,rear->next=s; Q.rear=s;//rear指向新的表尾节点 } //入队(不带头节点) void EnQueue(LinkNodeQueue &Q,ElemType x){ LinkNode *s=(LinkNode*)malloc(sizeof(LinkNode)); s->data=x; s->next=NULL;//插入到队尾,所以连接NULL if(Q.front == NULL){ //在空队中插入第一个元素 Q.front=s;//修改对头队尾指针 Q.rear=s; }else{ Q,rear->next=s; Q.rear=s;//rear指向新的表尾节点 } } //出队(带头节点) bool DeQueue(LinkNodeQueue &Q,ElemType &x){ if(Q.front==Q.rear) return false; LinkNode *p=Q.front->next;//指向头结点的后面一个节点即要删除的节点 x=p->data;//x返回队头元素 Q.front->next=p->next; if(Q.rear==p)//此次是最后一个节点出队 Q.rear=Q.front; free(p); return true; } //出队(不带头节点) bool DeQueue(LinkNodeQueue &Q,ElemType &x){ if(Q.front==Q.rear) return false; LinkNode *p=Q.front;//指向头结点的后面一个节点即要删除的节点 x=p->data;//x返回队头元素 Q.fron=p->next; if(Q.rear==p)//此次是最后一个节点出队 Q,front=NULL; Q.rear=NULL; free(p); return true; }
队列的应用:树的层次遍历、图的广度遍历,多个进程抢占系统资源时先来先服务 eg:数据缓冲区
特殊矩阵的压缩存储
栈在表达式求值中的应用
栈在递归中的应用
适合用递归算法解决:可以把原始问题转换为属性相同,但规模较小的问题
实现递归算法需要注意:(1)递归表达式(2)递归出口
每进入一层递归,就将递归调用所需信息压入栈顶
每退出一层递归,就从栈顶弹出相应信息
缺点:效率低,太多层递归可能会导致栈溢出;可能包含很多重复计算
//计算正整数 n! int factoral(int n){ if(n==0 || n==1) return 1; else return n*factoral(n-1); } int main(){ int x=factoral(10); }//计算正整数 n! int factoral(int n){ if(n==0 || n==1) return 1; else return n*factoral(n-1); } int main(){ int x=factoral(10); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报