栈 队列 堆

本文将从数组模拟和STL两方面来简要介绍栈、队列和堆并同时介绍相关的简单用法。

栈是一种能有效帮助我们临时保存数据的数据结构,按照最后进栈的数据最先出栈(Last In First Out,LIFO,后进先出)的规则管理数据。栈是一端开口一端闭合的管道,即只能在某一端插入和删除的特殊线性表。

1.数组

使用数组实现时,栈底位置可以设置在数组的任意一个端点,栈顶随着元素的插入和删除而变化,可以设定一个栈指针来指向其位置。

int stack[maxn], t=0;

进栈

  1. 检查栈是否已满,满则溢出;
  2. 栈指针自增,指向进栈位置;
  3. 将进栈位置赋值为新进栈的元素。
void push(int x)
{
	if(t==maxn) printf("Overflow\n");
	else
	{
		t++;
		stack[t] = x;
	}
}

出栈

  1. 检查是否已为空栈,空则下溢;
  2. 栈指针自减。
void pop()
{
	if(!t) printf("Underflow\n");
	else t--;
}

访问栈顶元素

int top = stack[t];

判断栈是否为空

标志:t = 0

得到栈中元素数量

栈中元素的数量即为栈顶指针t的值。

2.STL

C++的STL中提供了栈的标准库,使用起来更加方便快捷。使用头文件stack

stack<int> s;

进栈s.push(x);

出栈s.pop();

访问栈顶元素s.top();

判断栈是否为空s.empty();

得到栈中元素数量s.size();

3.例题

https://blog.csdn.net/baidu_41248654/article/details/104663035

队列

队列是一个等待处理的行列,是按数据抵达的先后顺序处理进行处理的数据结构,按照最先放入的元素最先被取出(First In First Out,FIFO,先进先出)的规则管理数据。

1.数组

队列可以使用数组Q[m+1]来存储,数组的上界m即是队列所容许的最大容量。在队列的运算中需设头指针head和尾指针tail,一般情况下两个指针的初值为0。

int q[m+1], head=0, tail=0;

入队(形成循环队以克服假溢出)

假溢出:尾指针已经处理到队尾但队列中仍有空位置的情况。

  1. 尾指针自增;
  2. 若尾指针到达队尾,则赋为1;
  3. 判断头尾指针是否重合,若重合则上溢,否则Q[tail]存储新入队的元素。
void push(int x)
{
	tail++;
	if(tail == m) tail = 1;
	if(tail == head) cout<<"Overflow"<<endl;
	else q[tail] = x;
}

出队

头指针自增。

void pop()
{
	head++;
}

访问队首元素

int front = q[head+1];

判断队列是否为空(非循环队)

标志:head == tail

得到队列中元素数量(非循环队)

tail-head的值即为队列中元素数量。

2.STL

C++的STL中提供了队列的标准库,使用起来更加方便快捷。使用头文件queue

queue<int> q;

入队q.push(x);

出队q.pop();

访问队首元素q.front();

判断队列是否为空q.empty();

得到队列中元素数量q.size();

3.例题

https://blog.csdn.net/baidu_41248654/article/details/104278212

堆结构是一种数组对象,它可以被视为一棵完全二叉树。树中每个结点与数组中存放该结点中值的那个元素相对应。

1.数组

图片123

设数组A的长度为len,二叉树的结点个数为size,size≤len,则A[i]存储二叉树中编号为i的结点值(1≤i≤size),而A[size]以后的元素并不属于相应的堆,树的根为A[1],并且利用完全二叉树的性质,我们很容易求第i个结点的父结点(parent(i))、左孩子结点(left(i))、右孩子结点(right(i))的下标了,分别为:i/2、2i、2i+1;

更重要的是,堆具有这样一个性质,对除根以外的每个结点i,A[parent(i)]≥A[i]。即除根结点以外,所有结点的值都不得超过其父结点的值,这样就推出,堆中的最大元素存放在根结点中,且每一结点的子树中的结点值都小于等于该结点的值,这种堆又称为“大根堆”;反之,对除根以外的每个结点i,A[parent(i)]≤A[i]的堆,称为“小根堆”。

插入元素

  • [1] 在堆尾加入一个元素,并把这个结点置为当前结点;
  • [2] 比较当前结点和其父结点的大小:如果当前结点小于父结点则交换它们的值,并把父结点置为当前结点,转到[2];如果当前结点大于父结点则转到[3];
  • [3] 结束。
void put(int x)
{
	int now, next;
	heap[++heap_size] = x;
	now = heap_size;
	while(now > 1)
	{
		next = now>>1;
		if(heap[now] >= heap[next]) break;
		swap(heap[now], heap[next]);
		now = next;
	}
}

取出并删除元素

  • [1] 取出堆的根结点的值;
  • [2] 把堆的最后一个结点(len)放到根的位置上,把根覆盖掉,把堆的长度减一;
  • [3] 把根结点置为当前父结点father;
  • [4] 如果father无儿子(father>len/2),则转到[6],否则把father的两个(或一个)儿子中值最小的置为当前的子结点son,转到[5];
  • [5] 比较father与son的值,如果father<=son,转到[6],否则,交换这两个结点的值,把father指向son,转到[4];
  • [6] 结束。
int get() // heap[1]为堆顶 
{
	int now=1, next, res=heap[1];
	heap[1] = heap[heap_size--];
	while(now*2 <= heap_size)
	{
		next = now*2;
		if(next<heap_size && heap[next+1]<heap[next]) next++;
		if(heap[now] <= heap[next]) break;
		swap(heap[now], heap[next]);
		now = next;
	}
	return res;
}

2.STL

C++的STL中提供了优先队列标准库,一般用来解决一些贪心问题,其底层是用堆来实现的。在优先队列中,任何时刻,队首元素一定是当前队列中优先级最高(优先值最大)的那一个(大根堆),也可以是最小的那一个(小根堆)。使用头文件queue。

priority_queue<int, vector<int>, greater<int> > q; // 小根堆
priority_queue<int, vector<int>, less<int> >q; // 大根堆

建立结构体类型的优先队列需重载运算符,例如:

struct node{
    int t, No;
};
priority_queue<node, vector<node> > q;
bool operator < (const node &s1, const node &s2)
{
    if(s1.t != s2.t) return s1.t > s2.t;
    else return s1.No > s2.No;
}

入队q.push(x);

出队q.pop();

访问队首元素q.top();

判断队列是否为空q.empty();

得到队列中元素数量q.size();

3.例题

https://blog.csdn.net/baidu_41248654/article/details/104294322

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值