栈和队列——数据结构学习笔记

栈和队列

栈(Stack)

定义与特点

栈是一种特殊的线性表,只能从一端进行插入和删除------>后进后出 LIFO结构

表尾(an) 称为栈顶Top 表头(a1)称为栈底Base

插入元素到栈顶 的操作称为入栈

删除栈顶 最后一个元素的操作称为出栈

抽象类型定义

ADT Stack{
数据对象:
		D = {ai|ai∈ElemSet,i=1,2,3,...n,n≥0}
数据关系:
		R1 = {<ai-1,ai>|ai-1,ai∈D,i=2...,n}
		约定an端为栈顶,a1端为栈底
基本操作:
		初始化,进栈,出栈,取栈元素等
}ADT Stack

基础操作

InitStack(&S):初始化一个空栈S。
StackEmpty(S):判断一个栈是否为空
StackLength(S):求栈长度
Push(&S, x):进栈------栈的插入操作
Pop(&S, &x):出栈------栈的删除操作
GetTop(S, &e):读栈顶元素
ClearStack(&S):栈置空
DestroyStack(&S):栈销毁

顺序栈

为方便top指针指向栈顶元素之上的下标地址

stacksize ------> 栈可使用的最大容量

空栈的标志:base == top

栈满的标志: top - base == stacksize ------------ 元素个数计算即top - base

上溢:栈满进行插入 下溢:栈空继续弹出

顺序栈的数据类型定义

#define MAXSIZE 100
typedef struct{
		SElemType *base;//栈底指针
		SElemType *top;//栈顶指针
		int stacksize;//栈可用最大容量
}SqStack;

顺序栈的初始化

Status lnitStack(SqStack &S)
{
	S.base = new SElemType[MAXSIZE];
	if(!S.base) exit (OVERFLOW);//存储分配成功
	S.top = S.base;
	S.stacksize = MAXSIZE;
	return OK;
}

判断顺序栈是否为空

Status StackEmpty(SqStack S)
{
	if(S.top == S.base)
		return TURE;
	else
		return FALSE;
}

求顺序栈的长度

int StackLength(SqStack S)
{
	return S.top - S.base;
}

清空顺序栈

Status ClearStack(SqStack S){
	if(S.base) S.top = S.base;
	return OK;
}

销毁顺序栈

Status DestroyStack(SqStack &S){
	if(S.base){
		delete S.base;
		S.stacksize == 0;
		S.base = S.top = NULL;
	}
	return OK;
}

顺序栈的入栈

1.判断栈是否满,若满则出差(上溢)

2.元素e压入栈顶

3.栈顶指针加1

Status Push(SqStack &S, SElemType e){
	if(S.top - S.base == S.stacksize)
		return ERROR;
	*S.top++ = e;	//先e赋值给*S.top再移动指针++
	return OK;
	}
}

顺序栈的出栈

1.判断栈是否为空,空则出错(下溢)

2.获取栈顶元素e

3.栈顶指针-1

Status Pop(SqStack &S, SElemType &e){
	if(S.top == S.base)
		return ERROP;
	e = *--S.top;
	return OK;
}

链栈

链栈指针方向与链表方向相反

· 链表的头指针就是栈顶

· 不需要头节点

· 基本不存在栈满的情况

· 空栈相当于头指针指向空

· 插入和删除仅在栈顶处执行

数据类型定义

typedef struct StackNode{
	SElemType date;
	struct StackNode *next;
}StackNode,*LinkStack;
LinkStack S;

初始化

void lnitStack(LinkStack &S){
	S = NULL;
	return OK;
}

判断链栈是否为空

Status StackEmpty(LinkStack S){
	if(S == NULL) return TURE;
	else return FlASE;
}

链栈入栈

Status Push(LinkStac &S,SElemType e){
	p = new StackNode;
	p -> date = e;
	P -> next = S;
	S = p;
	return OK;
}

链栈出栈

Status Pop(LinkStac &S,SElemType &e){
	if(S == NULL) return ERROR;
	e = S -> date;
	p = S;
	S = S -> next;
	delete p;
	return OK;
}

取栈顶元素

SElemType GetTop(LinkStack S){
	if(S!= NULL)
		return S -> date;
}

栈与递归

一个对象包含自己或自己给自己定义

一个过程直接或间接调用自己

分治法求递归问题算法的一般形式

void p(参数表){
	if(递归结束条件) 可以直接求解步骤; ------基本项
	else p(较小的参数);  ------归纳项  
}

队列(queue)

队列是一种先进先出的线性表(FIFO)

一端插入一端删除

抽象类型定义

ADT Queue{
数据对象:
		D = {ai|ai∈ElemSet,i=1,2,3,...n,n≥0}
数据关系:
		R1 = {<ai-1,ai>|ai-1,ai∈D,i=2...,n}
		约定a1端为队列头,an端为队列尾
基本操作:
		初始化,入队,出队等
}ADT Queue

基础操作

InitQueue (&Q)    构造空队列
DestroyQueue (&Q)  销毁队列
ClearQueue (&Q)      清空队列
QueueEmpty(Q)       判空. 空=TRUE,
QueueLength(Q)      取队列长度
GetHead (Q,&e)      取队头元素,
EnQueue (&Q,e)      入队列
DeQueue (&Q,&e)     出队列
QueueTraverse(Q,visit())      遍历

顺序队列

一维数组base[MAXQSIZE]表示

#define MAXQSIZE 100 //最大队列长度
Typedef struct{
		QElemType *base; //初始化的动态分配存储空间
		int front;	//头指针
		int rear; //尾指针
}SqQueue

初始状态 front = rear = 0

rear = MAXQSIZE 时发生溢出

front = 0 rear = MAXQSIZE时再入队 则为真溢出

front != 0 rear = MAXQSIZE时再入队 则为假溢出

对于假上溢如何解决 >>>

1.将对内元素依次向队头方向移动 (浪费时间)
2.循环:
		思路:base[0] 接在 base[MAXQSIZE-1] 之后 ,若 rear + 1 == MAXQSIZE, 则令 rear = 0;
		具体实现:用%的运算
插入元素:Q.base[Q.rear] = x;
		Q.rear = (Q.rear + 1) % MAXQSIZE;
删除元素:x = Q.base[Q.front]
		Q.front = (Q.front + 1 ) % MAXQSIZE

对于判断循环队空队满 >>>

当循环队列中队空队满都为 front == rear 如何解决
1.设标记
2.记录个数
3.少用一个元素空间 则队满: (rear + 1) % MAXQSZIE == front

初始化

Status lnitQueue(SqQueue &Q){
	Q.base = new QElemType[MAXQSIZE];
	if(!Q.base) exit(OVERFLOW);
	Q.front = Q.rear = 0;
	return OK;
}

求队列长度

int QueueLength(SqQueue Q){
	return ((Q.rear - Q.front + MAXQSZIE) % MAXQZIE);
}

入队

Status EnQueue(SqQueue &Q, QElemType e){
	if((Q.rear + 1) % MAXQSIZE == Q.front) return ERROR;
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXSIZE;
	return OK;
}

出队

Status DeQueue(SqQueue &Q, QElemType &e){
	if(Q.rear = Q.front) return ERROR;
	e = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSZIE;
	return OK;
} 

取队头元素

SElemType GetHead(SqQueue Q){
	if(Q.rear = Q.front)
		return Q.base[Q.front];
} 

链队

当无法估计长度时,则宜采用链队列

类型定义

#define MAXQSIZE 100
typedef struct Qnode{
	QElemType data;
	stuct Qnode *next;
}QNode,*QueuePtr;

typedef struct{
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;

初始化

Status lnitQueue(LinkQueue &Q){
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if(!Q.front) exit(OVERFLOW);
	Q.front -> next = NULL;
	return OK;
}

销毁链队列

Status DestroyQueue(LinkQueue &Q){
	while(Q.front){
		p = Q.front -> next;
		free(Q.front);
		Q.front = p;
	}//Q.rear = Q.front -> next; free(Q.front); Q.front = Q.rear;
	return OK;
}

入队

Status EnQueue(LinkQueue &Q, QElemType e){
	p = (QueuePtr)malloc(sizeof(QNode));
	if(!p) exit(OVERFLOW);
	p -> data = e;
	p -> next = NULL;
	Q.rear -> next = p;
	Q.rear = p;
	return OK;
}

出队

Status DeQueue(LinkQueue &Q, QElemType e){
	if(Q.front == Q.rear) return ERROR;
	p = Q.front -> next;
	e = p -> data;
	Q.front -> next = p ---> next;
	if(Q.rear == p) Q.rear = Q.front;
	delepe p;
	return OK;
}

求链队列的队头元素

Status GetHead(LinkQueue Q, QElemType &e){
	if(Q.front == Q.rear) return ERROR;
	e = Q.front -> next -> data;
	return OK;
}
相关推荐
PYSpring20 分钟前
数据结构-LRU缓存(C语言实现)
c语言·数据结构·缓存
qq_4218336729 分钟前
计算机网络——应用层
笔记·计算机网络
云端奇趣35 分钟前
探索 3 个有趣的 GitHub 学习资源库
经验分享·git·学习·github
Mr Aokey40 分钟前
双向无头非循环链表的简单实现及介绍
数据结构
我感觉。41 分钟前
【信号与系统第五章】13、希尔伯特变换
学习·dsp开发
知识分享小能手1 小时前
mysql学习教程,从入门到精通,SQL 修改表(ALTER TABLE 语句)(29)
大数据·开发语言·数据库·sql·学习·mysql·数据分析
冰榫2 小时前
9.30学习记录(补)
学习
@qike2 小时前
【C++】—— 日期类的实现
c语言·c++·笔记·算法·学习方法
IG工程师2 小时前
关于 S7 - 1200 通过存储卡进行程序更新
经验分享·笔记·自动化
霸王蟹2 小时前
Vue3 项目中为啥不需要根标签了?
前端·javascript·vue.js·笔记·学习