数据结构---栈和队列


一、栈

栈的定义和特点:
栈是限定在表尾进行插入或者删除操作的线性表,表尾称为栈顶,表头称为栈底,不含元素时称为空栈。栈具有后进先出的特点,可以理解为一个弹夹,压入的一个个元素就相当于子弹,后压入的子弹总是先打的。
在这里插入图片描述
在这里插入图片描述

栈的实现
栈的实现有顺序栈和链栈两种
1.顺序栈:采用顺序存储结构实现栈存储结构;
2.链栈:采用链式存储结构实现栈结构;

顺序栈的实现和基本操作

#define maxsize 100
typedef struct {
	int* base;//栈底指针
	int* top;//栈顶指针
	int stackSize;//栈可用最大长度
}sqStack;

base为栈底指针,初始化后base始终指向栈底位置,若base值为null,则表示栈结构不存在;top为栈顶指针,其初值指向栈底,插入新元素时,top++;删除元素时,top–;因此,当top==base,都指向栈底,表示栈空;当栈非空时,top始终指向栈顶元素的上一个位置;
在这里插入图片描述
1.初始化

void initStack(sqStack& s) {
	s.base = new int[maxsize];//为顺序栈动态分配一个最大容量为maxsize的数组空间
	if (!s.base) exit(OVERFLOW);//分配存储空间失败
	s.top = s.base;//初始化top
	s.stackSize = maxsize;//栈的最大存储容量
}

2.入栈

void push(sqStack& s,int e) {
	if (s.top - s.base == s.stackSize) return;//栈满
	*s.top++ = e;//元素e压入栈顶,栈顶指针top加一
}

3.出栈(取栈顶元素并删除)

int pop(sqStack& s, int e) {
	if (s.top == s.base) return;//栈空
	e = *--s.top;//栈顶指针减一,栈顶元素赋予e
	return e;
}

4.取栈顶元素(不删除)

int getTop(sqStack& s) {
	if (s.top != s.base)//栈非空
		return *(s.top - 1);
}

由于顺序栈和顺序表一样,要事先确定存储空间,会难以控制和操作,所以还是应该使用链栈

链栈的实现和基本操作

结点定义

typedef struct stackNode{
	int data;
	struct stacjNode* next;
}stackNode,*linkStack;

1.初始化

void initStack(linkStack& s) {
	s = NULL; //构造一个空栈,栈底指针置空
}

2.入栈

void push(linkStack& s, int e) {
	stackNode *p = new stackNode;//生成新节点
	p->data = e;//给新节点赋值
	p->next = s;//新结点插入栈顶
	s = p;//修改栈顶指针
}

3.出栈

int pop(linkStack& s, int e) {
	if (s == NULL) return;//栈空
	e = s->data;
	stackNode* p = s;//用p暂存栈顶元素空间,以备释放
	s = s->next;//栈顶指针改变
	delete p;//释放原栈顶元素空间
	return e;
}

4.取栈顶元素

int getTop(linkStack& s) {
	if (s != NULL)
		return s->data;
}

栈和递归算法的关系

递归实际上就是借助栈来实现的,所以任何递归的问题其实都可以借助栈转化为非递归的问题

二、队列

队列的定义和特点
与栈相反,队列是一种先进先出的线性表,就像排队买饭,先排队的人总是先买的。他只允许在表的一端插入,而在另外一端删除,允许插入的一端称为队尾,允许删除的一端称为队头

队列的实现
和栈一样,队列也有两种实现方式
1.循环队列(顺序队列):采用顺序存储结构实现队存储结构;
2.链队:采用链式存储结构实现队结构;

循环队列(顺序队列)的实现和操作

为了满足顺序队列中数据从队尾进,队头出且先进先出的要求,我们还需要定义两个指针(top 和 rear)分别用于指向顺序队列中的队头元素和队尾元素。
在这里插入图片描述
初始化时,front=rear=0;当有数据元素入队时,尾指针 rear+1;当需要队头元素出队时,需做 头指针front+1 操作。头指针始终指向队首,尾指针始终指向队尾元素的下一个位置。
在这里插入图片描述
在这里插入图片描述

单纯的顺序队列的缺点:
1.队首有元素出队后,顺序队列之前的数组存储空间将无法再被使用,造成了空间浪费;
2.如果顺序表申请的空间不足够大,则直接造成程序中数组 a 溢出,产生溢出错误;

所以,就有了循环队列
在这里插入图片描述
在循环队列中,front和rear的依环加一可以用对环的大小取模来实现

注意顺序队列当front=rear时,表示队空;但在循环队列中front=rear时,有可能是队空也有可能是循环后队满。所以为了对其进行区分,最简单的解决办法是:牺牲掉数组中的一个存储空间,判断数组满员的条件是:尾指针的下一个位置和头指针相遇,就说明数组满了。

队列长度:(rear - front + max)%max
队列空的标志:队列的头指针等于队列的尾指针(front == rear);
队列满的判断:队列的头指针等于队列的尾指针((rear+1)%max==front)

顺序队列的存储结构定义

#define maxsize 100
typedef struct {
	int* base;//存储空间的基地址
	int front;//头指针
	int rear;//尾指针
}sqQueue;

1.初始化

void initQueue(sqQueue& q) {
	q.base = new int[maxsize];
	if (!q.base) return;//分配存储空间失败
	q.front = q.rear = 0;
}

2.求队列长度

int queueLength(sqQueue& q) {
	return (q.rear - q.front + maxsize) % maxsize;
}

3.入队

void enQueue(sqQueue& q,int e) {
	if ((q.rear + 1) % maxsize == q.front) return;//队满
	q.base[q.rear] = e;
	q.rear = (q.rear + 1) % maxsize;
}

4.出队

int deQueue(sqQueue& q,int e) {
	if (q.front == q.rear) return;//队空
	e = q.base[q.front];
	q.front = (q.front + 1) % maxsize;
	return e;
}

5.取队头元素

int getHead(sqQueue& q) {
	if (q.front != q.rear)//队列非空
		return q.base[q.front];
}

和栈一样,顺序结构的队列有诸多缺点,通常情况我们还是使用链队

链队的实现和操作

链队存储结构

typedef struct qNode{
	int data;
	struct qNode* next;
}qNode,*queuePtr;

typedef struct {
	queuePtr front;
	queuePtr rear;
}linkQueue;

1.初始化
像单链表一样,建立一个头结点,方便后面结点的处理

void initQueue(linkQueue& q) {
	q.front = q.rear = new qNode;
	q.front->next = NULL;//头结点指针域置空
}

2.入队

void enQueue(linkQueue& q,int e) {
	qNode* p = new qNode;
	p->data = e;
	p->next = NULL;
	q.rear->next = p;//将新结点插入到队尾
	q.rear = p;//修改队尾指针
}

3.出队

int deQueue(linkQueue& q, int e) {
	if (q.front == q.rear) return;//队空
	qNode* p = q.front->next;
	e = p->data;
	q.front->next = p->next;//修改头指针的指针域
	if (q.rear == p) q.rear = q.front;//最后一个元素被栅,队尾指针指向头结点
	delete p;
	return e;
}

4.取队头元素

int getHead(linkQueue& q) {
	if (q.front != q.rear)//队列非空
		return q.front->next->data;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值