数据结构详解之栈和队列

栈的基本概念

栈是只允许在一端进行插入或删除操作的线性表,是一种限制存取点的线性表。
栈顶top:线性表允许插入删除的一端
栈底bottom:固定的,不允许插入删除
栈的操作特性:先进后出
栈的数学特性:n个不同元素进栈,出栈元素不同排列的个数为(1/n+1)C(2n)n

栈的基本操作

InitStack(&S) 初始化一个空栈
StackEmpty(S) 判断栈是否为空
Push(&S,x) 进栈,栈未满时,加入x成为新栈顶
Pop(&S,x) 出栈,栈非空时,弹出栈顶元素,用x返回
GetTop(S,&x) 读栈顶元素,栈非空时,用x返回栈顶元素(栈不变)
DestoryStack(&S) 销毁栈,释放栈S的存储空间

栈的顺序存储结构

顺序栈

一组地址连续的存储单元存放自栈底到栈顶的数据元素,并附设一个指针top指示当前栈顶元素的位置
栈的顺序存储类型描述

#define MaxSize 50
typedef char ElemType;
typedef struct 
{
	ElemType data[MaxSize];//存放栈元素
	int top;				//栈顶指针
}SqStack;

栈顶指针初始化:S.top = -1
栈顶元素:S.data[S.top]
进栈:栈不满时,栈顶指针先加1,再送值到栈顶元素
出栈:栈非空时,先取栈顶元素值,再将栈顶指针减1
栈空条件:S.top == -1 栈满条件:S.top= = MaxSize-1 栈长:S.top+1

顺序栈的基本运算

初始化一个空栈

//InitStack(&S)
void InitStack(SqStack &S)
{
	S.top = -1;
}

判断栈是否为空

//StackEmpty(S)	
bool StackEmpty(SqStack S)
{
	if (S.top == -1)
		return true;
	return false;
}

进栈

//Push(&S, x)	进栈,栈未满时,加入x成为新栈顶
bool Push(SqStack &S, ElemType x)
{
	if (S.top == MaxSize - 1)
		return false;
	S.data[++S.top] = x;
	return true;
}

出栈

//Pop(&S, x)	出栈,栈非空时,弹出栈顶元素,用x返回
bool Pop(SqStack& S, ElemType x)
{
	if (S.top == - 1)
		return false;
	x = S.data[S.top--];
	return true;
}

读栈顶元素

//GetTop(S, &x)	 读栈顶元素,栈非空时,用x返回栈顶元素(栈不变)
bool GetTop(SqStack S, ElemType& x)
{
	if (S.top == -1)
		return false;
	x = S.data[S.top];
	return true;
}

共享栈

利用栈底位置相对不变的特性,让两个顺序栈共享一个一维数组空间,栈底分别设置在共享空间的两端。
top0 = -1时,0号栈为空,top1 = MaxSize时,1号栈为空
当两个栈顶指针相邻即top1-top0 = 1时,栈满
共享栈的优点:更有效利用存储空间,存取数据的时间复杂度为O(1)

栈的链式存储结构

通常采用单链表实现,很少用也少考
链栈没有头结点,Lhead指向栈顶元素,所有操作在表头进行
优点: 1.便于多个栈共享存储空间和提高效率 2.不存在栈满上溢的情况
栈的链式存储类型描述

typedef struct
{
	ElemType data;
	struct SNode* next;
}*LiStack;

链栈的操作与链表相似

队列

队列的基本概念

队列是只允许在一端进行插入,另一端删除操作的线性表,也是一种限制存取点的线性表。操作特性是先进先出(FIFO)
队头:允许删除的一端,也称队首
队尾:允许插入的一端

队列的基本操作

InitQueue(&Q) 初始化队列,构造一个空队列
QueueEmpty(Q) 判断队列是否为空
EnQueue(&Q,x) 入队,队列未满时,将x加入到队尾
DeQueue(&Q,&x) 出队,队列非空时,删除队头元素,用x返回
GetHead(Q,&x) 读队头元素,队列非空时,将队头元素赋给x

队列的顺序存储结构

顺序队列

队列的顺序实现分配了一块连续的存储单元,并附设两个指针:队头指针front指向队头元素,队尾指针rear指向队尾元素的下一个位置。
队列的顺序存储类型描述

#define MaxSize 50
typedef char ElemType;
typedef struct
{
	ElemType data[MaxSize];
	int front, rear;
}SqQueue;

初始状态:Q.front == Q.rear == 0(队空)
进队:队不满时,先送值到队尾元素,队尾指针+1
出队:队不空时,先取队头元素值,队头指针+1

假溢出:设队头指针front指向队头元素的前一位置,rear指向队尾元素。当front等于-1时队空,rear等于m-1时为队满。由于“删除”在队头而“插入”在队尾,所以当队尾指针rear等于m-1时,若front不等于-1,则队列中仍有空闲单元,所以队列并不是真满。这时若再有入队操作,会造成假“溢出”。
不能用Q.rear == MaxSize作为队满条件

循环队列

把存储队列元素的表在逻辑上视为一个环。
当队首指针Q.front = MaxSize -1后,再前进一个位置就自动到0,利用取余(%)运算实现
队空:Q.front == Q.rear == 0
队首指针进1:Q.front = (Q.front +1)%MaxSize
队尾指针进1:Q.rear = (Q.rear +1)%MaxSize
队列长度:(Maxsize + Q.rear - Q.front)%MaxSize
指针都按顺时针方向进1
队满时有Q.front = Q.rear
为了区分队空和队满,有三种处理方式:
1、牺牲一个单元(最常用)
以队头指针在队尾指针的下一位置作为队满标志
队满条件:(Q.rear +1)%MaxSize == Q.front

2、增设表示元素个数的数据成员size
队空条件:Q.size = 0
队满条件:Q.size = MaxSize

3、增设tag数据成员
tag=0时,若因删除导致Q.front = Q.rear,则为队空
tag=1时,若因插入导致Q.front = Q.rear,则为队满

循环队列的操作

初始化队列

void InitQueue(SqQueue& Q)
{
	Q.rear = Q.front = 0;
}

判队空

bool QueueEmpty(SqQueue Q)
{
	if (Q.rear == Q.front)
		return true;
	return false;
}

入队

bool EnQueue(SqQueue& Q, ElemType x)
{
	if ((Q.rear + 1) % MaxSize == Q.front)
		return false;
	Q.data[Q.rear] = x;
	Q.rear = (Q.rear + 1) % MaxSize;
	return true;
}

出队

bool DeQueue(SqQueue& Q, ElemType& x)
{
	if (Q.rear == Q.front)
		return false;
	x = Q.data[Q.front] ;
	Q.front = (Q.front + 1) % MaxSize;
	return true;
}

队列的链式存储结构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值