栈
栈的定义:
栈就像一个货板,增加和取出都只能在尾部进行
栈的ADT
ADT 栈 stack
Data:
同线性表。数据元素为零个或者有限个,中间元素只有一个前驱一个后驱,首元素只有后驱;尾元素只有前驱
Opration:
InitStack(*s); 初始化一个空栈
Push(*s,e); 栈的元素插入,入栈,值为e
Pop(*s,*e); 栈元素的删除,出站,e返回值
ClearStack(*s); 清空栈
StackLength(s); 栈的元素个数
DestroyStack1(*s); 栈存在,则销毁
GetTop(*s,*e); 返回栈顶元素
IsEmptyStack(s) 判断栈是否为空
endADT
栈的顺序存储结构
栈是一种特殊的线性表,线性表的存储结构使用数组,顺序存储结构需要有三个元素:maxsize、data、length;顺序栈也需要这样的元素
typedef struct
{
SElem data[MAXSIZE];
int top;
}SqStack;
入栈操作:
1.top++
2.赋值
status Push(SqStack *s,SElem e)
{
if (s->top==MAXSIZE-1)
return ERROR;
s->top++;
s->data[s->top]=e;
return OK;
}
出栈操作:
1.top--
2.赋值
status Pop(SqStack *s,SElem *e)
{
if (s->top==-1) //判断是否为空栈
return ERROR;
*e=s->data[s->top];
s->top--;
return OK;
}
两栈共享空间
typedef struct
{
SElem data[MAXSIZE];
int top1;
int top2;
}sqDStack;
//栈的空间共享的实现-入栈
status PushDStack(sqDStack *s,SElem e,int stackNumber)
{
if (s->top1+1==s->top2)
{
return ERROR;
}
if (stackNumber=1) //往栈一入
{
s->top1++;
s->data[s->top1]=e;
}
else if (stackNumber=2)
{
s->top2++;
s->data[s->top2]=e;
}
return OK;
}
栈的链式存储结构
说明:栈的链式存储是线性表的链式存储的一种特殊结构;栈中只有栈顶进行插入和删除,因此比普通的单链表简单;由于栈顶有头指针,而链表也有头指针,因此可以考虑将链表的头作为栈顶,这样链表的头指针便可作为栈的头指针;头结点便不需要了,因为有栈顶指针。
//链栈的结点
typedef struct stackNode
{
SElem data;
struct stackNode *next;
}stackNode,*LinkStackPtr; //指向结点指针
//链栈的结构
typedef struct LinkStack
{
LinkStackPtr top; //头指针为栈顶指针
int count;
}LinkStack;
入栈操作:
1.先将新结点s->next指向栈顶结点
2.再将栈顶结点移动至s
status PushLinkStack(LinkStack *ls,SElem e)
{
LinkStackPtr s = (LinkStackPtr)malloc(sizeof(stackNode)); //新建一个结点
s->data=e;
s->next=ls->top; //先将s->next指向栈顶结点
ls->top=s; //在将栈顶结点移动至s
ls->count++;
return OK;
}
出栈操作:
1.先将栈顶元素赋值给e
2.再将栈顶元素向下移动
//链栈的出栈操作
status PopLinkStack(LinkStack *ls,SElem *e)
{
LinkStackPtr s =ls->top;
*e = s->data;
ls->top=s->next;
ls->count--;
return OK;
}
栈的应用
递归:后续补充
四则运算:后续补充
队列
队列的定义
街边新开了一家奶茶店,人太多只能排队取餐;新来的人排在后面,先到的人先买到奶茶;所有的人形成一个队列,遵循先进先出的原则;
队列的ADT
/*
ADT 队列 queue
Data:
同线性表
Operation:
IniteQueue(*Q); //初始化一个队列
ClearQueue(*Q); //清空队列的元素
DestroyQueue(Q); //销毁队列
IsEmptyQueue(Q); //判断队列是否为空
GetHeadQueue(*Q,e); //获取头元素,返回给e
AddQueue(*Q,e); //将e插入队尾
DeleteQueue(*Q,*e); //删除队列的头,相当于出队
LengthQueue(*Q); //获取队列的长度
endADT
*/
队列的顺序存储结构
队列的顺序存储结构与线性表一致,按照以往的存储方式,出队时所有的位置都要变化,为此,可以使用循环队列,循环队列就是出队后其他位置不变化,循环队列设置front表示队头,设置rear表示队尾的下个位置;满队的条件:(rear+1)%maxsize=front;长度公式为:(rear-front+maxsize)%maxsize
//循环队列的顺序存储结构
typedef int QElem;
typedef struct
{
QElem data[MAXSIZE];
int front; //队头的位置
int rear; //队尾的下一位置
}SqQueue;
队列顺序存储的操作
入队、出队、长度
//初始化空循环队列
status InitQueue(SqQueue *q)
{
q->front=0;
q->rear=0;
return OK;
}
//循环队列的入队,将队列元素e插入队尾
status AddQueue(SqQueue *q,QElem e)
{
//判断是否队满
if (q->front==(q->rear+1)%MAXSIZE)
{
return ERROR;
}
q->data[q->rear]=e;
q->rear=(q->rear+1)%MAXSIZE; //rear指向下个位置,如果满了则从头开始
return OK;
}
//循环队列的长度
int LengthQueue(SqQueue *q)
{
return (q->rear-q->front+MAXSIZE)%MAXSIZE;
}
//循环队列的出队,将队首元素删除,并赋值给e
status DeleteQueue(SqQueue *q,QElem *e)
{
//判断队列为空
if (q->front==q->rear)
{
return ERROR;
}
*e = q->data[q->front];
q->front = (q->front+1)%MAXSIZE; //front向后移动,若为对尾,则向头移动
return OK;
}
//循环队列打印
status PrintQueue(SqQueue *q)
{
if (q->front==q->rear)
{
return ERROR;
}
int flag = q->front; //记录起始位置
for(int i=0;i<LengthQueue(q);i++)
{
printf("%d ",q->data[flag]);
flag =(flag+1)%MAXSIZE;
}
}
队列的链式存储
结构:队头指针指向头结点,队尾指针指向终端结点
//链队列的实现
typedef struct QNode
{
QElem data;
struct QNode *next;
}QNode, *QueuePtr;
//队头指针指向头结点,对尾指针指向终端结点
typedef struct
{
QueuePtr front,rear; //队头、队尾指针
}LinkQueue;
//链队的存储结构=入队
status AddLinkQueue(LinkQueue *q,QElem e)
{
QueuePtr s = (QueuePtr)malloc(sizeof(QNode));
if (!s)
{
exit(OVERFLOW); //溢出
}
s->data=e;
s->next=NULL; //新结点赋值
q->rear->next=s; //1队尾结点的next指向新结点
q->rear=s; //2队尾rear指向s
return OK;
}
//链队的存储结构-出队
status DeleteLinkQueue(LinkQueue *q,QElem e)
{
QueuePtr p;
if (q->front==q->rear)
{
return ERROR;
}
p=q->front->next; //p为对首后面的链表
e=p->data; //队首元素赋值给e
q->front->next=p->next; //1头指针指向队首后面的结点
if (q->rear==p) //只有一个元素的情况
{
q->rear=q->front; //尾指针指向头结点
}
free(p);
return OK;
}