本文将从数组模拟和STL两方面来简要介绍栈、队列和堆并同时介绍相关的简单用法。
栈
栈是一种能有效帮助我们临时保存数据的数据结构,按照最后进栈的数据最先出栈(Last In First Out,LIFO,后进先出)的规则管理数据。栈是一端开口一端闭合的管道,即只能在某一端插入和删除的特殊线性表。
1.数组
使用数组实现时,栈底位置可以设置在数组的任意一个端点,栈顶随着元素的插入和删除而变化,可以设定一个栈指针来指向其位置。
int stack[maxn], t=0;
进栈
- 检查栈是否已满,满则溢出;
- 栈指针自增,指向进栈位置;
- 将进栈位置赋值为新进栈的元素。
void push(int x)
{
if(t==maxn) printf("Overflow\n");
else
{
t++;
stack[t] = x;
}
}
出栈
- 检查是否已为空栈,空则下溢;
- 栈指针自减。
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;
- 判断头尾指针是否重合,若重合则上溢,否则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