一、栈
1.1栈的定义
一种可以实现“先进后出”的存储结构。
栈类似于箱子
1.2栈的分类
-
静态栈
-
动态栈
1.3算法
出栈
入栈(压栈)
删除
插入
初始化:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
typedef struct Node{
int data;
struct Node * pNext;
}NODE, * PNODE;
typedef struct Stack{
PNODE pTop;
PNODE pBottom;//栈底元素下一个没有实际意义的元素
}STACK, * PSTACK;
void init(PSTACK);
void push(PSTACK,int);
void traverse(PSTACK);
bool pop(PSTACK, int *);
bool empt(PSTACK pS);
void clear(PSTACK);
int main(void){
STACK S;//STACK等价于struct Stack
int val;
init(&S);//造出一个空栈
push(&S,1);//压栈
push(&S,2);
push(&S,3);
push(&S,4);
traverse(&S);//遍历输出
// clear(&S);
if(pop(&S,&val)){
printf("出栈成功,出栈的元素是%d\n",val);
}
else{
printf("出栈失败!\n");
}
traverse(&S);//遍历输出
return 0;
}
void init(PSTACK pS){
pS->pTop=(PNODE)malloc(sizeof(NODE));
if(NULL==pS->pTop){
printf("动态内存分配失败!\n");
exit(-1);
}
else{
pS->pBottom=pS->pTop;
pS->pTop->pNext=NULL;
}
}
void push(PSTACK pS,int val){
PNODE pNew=(PNODE)malloc(sizeof(NODE));
pNew->data=val;
pNew->pNext=pS->pTop;
pS->pTop=pNew;
return;
}
void traverse(PSTACK pS){
PNODE p=pS->pTop;
while(p!=pS->pBottom){
printf("%d\n",p->data);
p=p->pNext;
}
return ;
}
bool empt(PSTACK pS){
if(pS->pTop==pS->pBottom){
return true;
}
else
return false;
}
//把pS所指向的栈出栈一次,并把出栈的元素存入pVal形参所指向的变量中,如果出栈失败返回false,否则返回true
bool pop(PSTACK pS, int * pVal){
if(empt(pS)){
return false;
}
else{
PNODE r=pS->pTop;
* pVal=r->data;
pS->pTop=r->pNext;
free(r);
r=NULL;
return true;
}
}
void clear(PSTACK pS){
// int val;
// while(!empt(pS)){
// pop(pS,&val);
// }//自己写的不知道对不对
if(empt(pS)){
return ;
}
else{
PNODE p=pS->pTop;
PNODE q=NULL;
while(p!=pS->pBottom){
q=p->pNext;
free(p);
p=q;
}
pS->pTop=pS->pBottom;
}
}
1.4应用
- 函数调用
- 中断
- 表达式求值
- 内存分配
- 缓冲处理
- 迷宫
二、队列
2.1定义
一种可以实现“先进先出”的存储结构
2.2分类
- 链式队列 — 用链表实现
- 静态队列 — 用数组实现
静态队列通常都必须是循环队列
循环队列的讲解:
-
静态队列为什么必须是循环队列
-
循环队列需要几个参数来确定
两个参数:front,rear
这两个参数在不同场合有不同的含义 -
循环队列各个参数的含义
1)队列初始化:front和rear的值都是0
2)队列非空:front代表的是队列的第一个元素,rear代表的是队列的最后一个 有效元素的下一个元素
3)队列空:front和rear的值相等,但不一定是0 -
循环队列入队伪算法讲解
1 .将值存入rear代表的位置
2 .rear=(rear+1)%数组的长度 -
循环队列出队伪算法讲解
front=(front+1)%数组长度 -
如何判断循环队列是否为空
如果front和rear的值相等,则该队列一定为空
-
如何判断循环队列是否已满
预备知识:front和rear的大小关系并不固定
两种方式:
1 .多增加一个表标识参数
2 .少用一个元素(如果rear和front紧挨着,则队列已满)
2.3队列算法
入队
出队
2.4代码实现
#include<stdio.h>
#include<malloc.h>
typedef struct Queue{
int * pBase;
int front;
int rear;
}QUEUE;
void init(QUEUE *);
bool en_queue(QUEUE *,int);
bool out_queue(QUEUE *,int *);
void traverse_queue(QUEUE *);
bool full_queue(QUEUE *);
bool emput_queue(QUEUE * pQ);
int main(void){
QUEUE Q;
int val;
init(&Q);
en_queue(&Q,1);
en_queue(&Q,2);
en_queue(&Q,3);
en_queue(&Q,4);
en_queue(&Q,5);
en_queue(&Q,6);
traverse_queue(&Q);//1 2 3 4 5
if(out_queue(&Q,&val)){
printf("出队成功,队列出队的元素是:%d\n",val);//出队成功,队列出队的元素是:1
}
else{
printf("出队失败");
}
traverse_queue(&Q);//2 3 4 5
return 0;
}
void init(QUEUE * pQ){
pQ->pBase=(int *)malloc(sizeof(int)*6);
pQ->front=0;
pQ->rear=0;
}
bool full_queue(QUEUE * pQ)
{
if((pQ->rear+1)%6==pQ->front)
return true;
else
return false;
}
bool en_queue(QUEUE * pQ,int val){
if(full_queue(pQ)){
return false;
}
else{
pQ->pBase[pQ->rear]=val;
pQ->rear=(pQ->rear+1)%6;
return true;
}
}
void traverse_queue(QUEUE * pQ){
int i=pQ->front;
while(i!=pQ->rear){
printf("%d ",pQ->pBase[i]);
i=(i+1)%6;
}
printf("\n");
return;
}
bool emput_queue(QUEUE * pQ){
if(pQ->front==pQ->rear){
return true;
}
else
return false;
}
bool out_queue(QUEUE * pQ,int * pVal){
if(emput_queue(pQ)){
return false;
}
else{
* pVal=pQ->pBase[pQ->front];
pQ->front=(pQ->front+1)%6;
}
return true;
}
2.5队列的具体应用
所有和时间和有关的操作都有队列的影子