模板库(五) - 数据结构模板

写在前面

模板库”这一系列文章用来复习 O I OI OI模板
由于时间原因,作者无法一一亲自调试其中的程序,也因如此,有一部分程序来自于互联网,如果您觉得这侵犯了您的合法权益,请联系 ( Q Q 2068926345 ) (QQ2068926345) (QQ2068926345)删除。
对于给您造成的不便和困扰,我表示深深的歉意。
本系列文章仅用于学习,禁止任何人或组织用于商业用途。
本系列文章中,标记*的为选学算法,在 N O I P NOIP NOIP中较少涉及。

数据结构

队列

【简介】

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端 ( h e a d ) (head) (head)进行删除操作,而在表的后端 ( t a i l ) (tail) (tail)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。

#include<cstdio>
#include<queue>
using namespace std;
queue<int> q;
int n,opt,k;
int main(){
   
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
   
        scanf("%d",&opt);
        if(opt==1) scanf("%d",&k),q.push(k);
        else if(opt==2) q.pop();
        else printf("%d\n",q.front()); 
    } 
    return 0;
}

复杂度(入队,出队,访问队首) Θ ( 1 ) \Theta(1) Θ(1)


【简介】

( s t a c k ) (stack) (stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

【代码实现】
#include<cstdio>
#include<stack>
using namespace std;
int n,opt,k;
stack<int> s;
int main(){
   
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
   
        scanf("%d",&opt);
        if(opt==1) scanf("%d",&k),s.push(k);
        else if(opt==2) s.pop();
        else printf("%d\n",s.top());
    }
    return 0; 
}

复杂度(入栈,出栈,访问栈顶) Θ ( 1 ) \Theta(1) Θ(1)


【简介】

堆( h e a p heap heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。

【代码实现】

二叉堆

#include<cstdio>
#include<queue>
#include<cctype>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
inline int read(){
   
	int x=0,f=0;char ch=getchar();
	while(!isdigit(ch))f|=ch=='-',ch=getchar();
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return f?-x:x;
}
int main(){
   
    int m=read();
    for(int i=1;i<=m;i++){
   
        int a=read();
        if(a==1){
   
            int b=read();
            q.push(b); 
        }
        else if(a==2) printf("%d\n"q.top());
        else q.pop(); 
    }
    return 0;
}

*斐波那契堆

#ifndef _FIBONACCI_TREE_HPP_
#define _FIBONACCI_TREE_HPP_
#include <iomanip>
#include <iostream>
#include <cstdlib>
#include <cmath>
using namespace std;
template <class T>
class FibNode {
   
        public:
        T key;                // 关键字(键值)
        int degree;            // 度数
        FibNode<T> *left;    // 左兄弟
        FibNode<T> *right;    // 右兄弟
        FibNode<T> *child;    // 第一个孩子节点
        FibNode<T> *parent;    // 父节点
        bool marked;        // 是否被删除第一个孩子
        FibNode(T value):key(value), degree(0), marked(false), 
            left(NULL),right(NULL),child(NULL),parent(NULL) {
   
            key    = value;
            degree = 0;
            marked = false;
            left   = this;
            right  = this;
            parent = NULL;
            child  = NULL;
        }
};
template <class T>
class FibHeap {
   
    private:
        int keyNum;         // 堆中节点的总数
        int maxDegree;      // 最大度
        FibNode<T> *min;    // 最小节点(某个最小堆的根节点)
        FibNode<T> **cons;    // 最大度的内存区域
    public:
        FibHeap();
        ~FibHeap();
        // 新建key对应的节点,并将其插入到斐波那契堆中
        void insert(T key);
        // 移除斐波那契堆中的最小节点
        void removeMin();
        // 将other合并到当前堆中
        void combine(FibHeap<T> *other);
        // 获取斐波那契堆中最小键值,并保存到pkey中;成功返回true,否则返回false。
        bool minimum(T *pkey);
        // 将斐波那契堆中键值oldkey更新为newkey
        void update(T oldkey, T newkey);
        // 删除键值为key的节点
        void remove(T key);
        // 斐波那契堆中是否包含键值key
        bool contains(T key);
        // 打印斐波那契堆
        void print();
        // 销毁
        void destroy();
    private:
        // 将node从双链表移除
        void removeNode(FibNode<T> *node);
        // 将node堆结点加入root结点之前(循环链表中)
        void addNode(FibNode<T> *node, FibNode<T> *root);
        // 将双向链表b链接到双向链表a的后面
        void catList(FibNode<T> *a, FibNode<T> *b);
        // 将节点node插入到斐波那契堆中
        void insert(FibNode<T> *node);
        // 将"堆的最小结点"从根链表中移除,
        FibNode<T>* extractMin();
        // 将node链接到root根结点
        void link(FibNode<T>* node, FibNode<T>* root);
        // 创建consolidate所需空间
        void makeCons();
        // 合并斐波那契堆的根链表中左右相同度数的树
        void consolidate();
        // 修改度数
        void renewDegree(FibNode<T> *parent, int degree);
        // 将node从父节点parent的子链接中剥离出来,并使node成为"堆的根链表"中的一员。
        void cut(FibNode<T> *node, FibNode<T> *parent);
        // 对节点node进行"级联剪切"
        void cascadingCut(FibNode<T> *node) ;
        // 将斐波那契堆中节点node的值减少为key
        void decrease(FibNode<T> *node, T key);
        // 将斐波那契堆中节点node的值增加为key
        void increase(FibNode<T> *node, T key);
        // 更新斐波那契堆的节点node的键值为key
        void update(FibNode<T> *node, T key);
        // 在最小堆root中查找键值为key的节点
        FibNode<T>* search(FibNode<T> *root, T key);
        // 在斐波那契堆中查找键值为key的节点
        FibNode<T>* search(T key);
        // 删除结点node
        void remove(FibNode<T> *node);
        // 销毁斐波那契堆
        void destroyNode(FibNode<T> *node);
        // 打印"斐波那契堆"
        void print(FibNode<T> *node, FibNode<T> *prev, int direction);
};
/* 
 * 构造函数
 */
template <class T>
FibHeap<T>::FibHeap()
{
   
    keyNum = 0;
    maxDegree = 0;
    min = NULL;
    cons = NULL;
}
/* 
 * 析构函数
 */
template <class T>
FibHeap<T>::~FibHeap() 
{
   
}
/* 
 * 将node从双链表移除
 */
template <class T>
void FibHeap<T>::removeNode(FibNode<T> *node)
{
   
    node->left->right = node->right;
    node->right->left = node->left;
}
/*
 * 将node堆结点加入root结点之前(循环链表中)
 *   a …… root
 *   a …… node …… root
*/
template <class T>
void FibHeap<T>::addNode(FibNode<T> *node, FibNode<T> *root)
{
   
    node->left        = root->left;
    root->left->right = node;
    node->right       = root;
    root->left        = node;
}
/*
 * 将节点node插入到斐波那契堆中
 */
template <class T>
void FibHeap<T>::insert(FibNode<T> *node)
{
   
    if (keyNum == 0)
        min = node;
    else
       {
   
        addNode(node, min);
        if (node->key < min->key)
            min = node;
    }
    keyNum++;
}
/* 
 * 新建键值为key的节点,并将其插入到斐波那契堆中
 */
template <class T>
void FibHeap<T>::insert(T key)
{
   
    FibNode<T> *node;
    node = new FibNode<T>(key);
    if (node == NULL)
        return ;
    insert(node);
}
/*
 * 将双向链表b链接到双向链表a的后面
 *
 * 注意: 此处a和b都是双向链表
 */
template <class T>
void FibHeap<T>::catList(FibNode<T> *a, FibNode<T> *b)
{
   
    FibNode<T> *tmp;
    tmp            = a->right;
    a->right       = b->right;
    b->right->left = a;
    b->right       = tmp;
    tmp->left      = b;
}
/*
 * 将other合并到当前堆中
 */
template <class T>
void FibHeap<T>::combine(FibHeap<T> *other)
{
   
    if (other==NULL)
        return ;
    if(other->maxDegree > this->maxDegree)
        swap(*this, *other);
    if((this->min) == NULL)                // this无"最小节点"
    {
   
        this->min = other->min;
        this->keyNum = other->keyNum;
        free(other->cons);
        delete other;
    }
    else if((other->min) == NULL)           // this有"最小节点" && other无"最小节点"
    {
   
        free(other->cons);
        delete other;
    }                                       // this有"最小节点" && other有"最小节点"
    else
    {
   
        // 将"other中根链表"添加到"this"中
        catList(this->min, other->min);
        if (this->min->key > other->min->key)
            this->min = other->min;
        this->keyNum += other->keyNum;
        free(other->cons);
        delete other;
    }
}
/*
 * 将"堆的最小结点"从根链表中移除,
 * 这意味着"将最小节点所属的树"从堆中移除!
 */
template <class T>
FibNode<T>* FibHeap<T>::extractMin()
{
   
    FibNode<T> *p = min;
    if (p == p->right)
        min = NULL;
    else
    {
   
        removeNode(p);
        min = p->right;
    }
    p->left = p->right = p;
    return p;
}
/*
 * 将node链接到root根结点
 */
template <class T>
void FibHeap<T>::link(FibNode<T>* node, FibNode<T>* root)
{
   
    // 将node从双链表中移除
    removeNode(node);
    // 将node设为root的孩子
    if (root->child == NULL)
        root->child = node;
    else
        addNode(node, root->child);
    node->parent = root;
    root->degree++;
    node->marked = false;
}
/* 
 * 创建consolidate所需空间
 */
template <class T>
void FibHeap<T>::makeCons()
{
   
    int old = maxDegree;
    // 计算log2(keyNum),"+1"意味着向上取整!
    // ex. log2(13) = 3,向上取整为3+1=4。
    maxDegree = (log(keyNum)/log(2.0)) + 1;
    if (old >= maxDegree)
        return ;
    // 因为度为maxDegree可能被合并,所以要maxDegree+1
    cons = (FibNode<T> **)realloc(cons, 
            sizeof(FibHeap<T> *) * (maxDegree + 1));
}
/* 
 * 合并斐波那契堆的根链表中左右相同度数的树
 */
template <class T>
void FibHeap<T>::consolidate()
{
   
    int i, d, D;
    FibNode<T> *x, *y, *tmp;
    makeCons();//开辟哈希所用空间
    D = maxDegree + 1;
    for (i = 0; i < D; i++)
        cons[i] = NULL;
    // 合并相同度的根节点,使每个度数的树唯一
    while (min != NULL)
    {
   
        x = extractMin();                // 取出堆中的最小树(最小节点所在的树)
        d = x->degree;                    // 获取最小树的度数
        // cons[d] != NULL,意味着有两棵树(x和y)的"度数"相同。
        while (cons[d] != NULL)
        {
   
            y = cons[d];                // y是"与x的度数相同的树" 
            if (x->key > y->key)        // 保证x的键值比y小
                swap(x, y);
            link(y, x);    // 将y链接到x中
            cons[d] = NULL;
            d++;
        }
        cons[d] = x;
    }
    min = NULL;
    // 将cons中的结点重新加到根表中
    for (i=0; i<D; i++)
    {
   
        if (cons[i] != NULL)
        {
   
            if (min == NULL)
                min = cons[i];
            else
            {
   
                addNode(cons[i], min);
                if ((cons[i])->key < min->key)
                    min = cons[i];
            }
        }
    }
}
/*
 * 移除最小节点
 */
template <class T>
void FibHeap<T>::removeMin()
{
   
    if (min==NULL)
        return ;
    FibNode<T> *child = NULL;
    FibNode<T> *m = min;
    // 将min每一个儿子(儿子和儿子的兄弟)都添加到"斐波那契堆的根链表"中
    while (m->child != NULL)
    {
   
        child = m->child;
        removeNode(child);
        if (child->right == child)
            m->child = NULL;
        else
            m->child = child->right;
        addNode(child, min);
        child->parent = NULL;
    }
    // 将m从根链表中移除
    removeNode(m);
    // 若m是堆中唯一节点,则设置堆的最小节点为NULL;
    // 否则,设置堆的最小节点为一个非空节点(m->right),然后再进行调节。
    if (m->right == m)
        min = NULL;
    else
    {
   
        min = m->right;
        consolidate();
    }
    keyNum--;
    delete m;
}
/*
 * 获取斐波那契堆中最小键值,并保存到pkey中;成功返回true,否则返回false。
 */
template <class T>
bool FibHeap<T>::minimum(T *pkey)
{
   
    if (min==NULL || pkey==NULL)
        return false;
    *pkey = min->key;
    return true;
}
/* 
 * 修改度数
 */
template <class T>
void FibHeap<T>::renewDegree(FibNode<T> *parent, int degree)
{
   
    parent->degree -= degree;
    if (parent-> parent != NULL)
        renewDegree(parent->parent, degree);
}
/* 
 * 将node从父节点parent的子链接中剥离出来,
 * 并使node成为"堆的根链表"中的一员。
 */
template <class T>
void FibHeap<T>::cut(FibNode<T> *node, FibNode<T> *parent)
{
   
    removeNode(node);
    renewDegree(parent, node->degree);
    // node没有兄弟
    if (node == node->right) 
        parent->child = NULL;
    else 
        parent->child = node->right;
    node->parent = NULL;
    node->left = node->right = node;
    node->marked = false;
    // 将"node所在树"添加到"根链表"中
    addNode(node, min);
}
/* 
 * 对节点node进行"级联剪切"
 *
 * 级联剪切:如果减小后的结点破坏了最小堆性质,
 *     则把它切下来(即从所在双向链表中删除,并将
 *     其插入到由最小树根节点形成的双向链表中),
 *     然后再从"被切节点的父节点"到所在树根节点递归执行级联剪枝
 */
template <class T>
void FibHeap<T>::cascadingCut(FibNode<T> *node) 
{
   
    FibNode<T> *parent = node->parent;
    if (parent != NULL)
    {
   
        if (node->marked == false) 
            node->marked = true;
        else
        {
   
            cut(node, parent);
            cascadingCut(parent);
        }
    }
}
/* 
 * 将斐波那契堆中节点node的值减少为key
 */
template <class T>
void FibHeap<T>::decrease(FibNode<T> *node, T key)
{
   
    FibNode<T> *parent;
    if (min==NULL ||node==NULL) 
        return ;
    if ( key>=node->key)
    {
   
        cout << "decrease failed: the new key(" << key <<") "
             << "is no smaller than current key(" << node->key <<")" << endl;
        return ;
    }
    node->key = key;
    parent = node->parent;
    if (parent!=NULL && node->key < parent->key)
    {
   
        // 将node从父节点parent中剥离出来,并将node添加到根链表中
        cut(node, parent);
        cascadingCut(parent);
    }
    // 更新最小节点
    if (node->key < min->key)
        min = node;
}
/* 
 * 将斐波那契堆中节点node的值增加为key
 */
template <class T>
void FibHeap<T>::increase(FibNode<T> *node, T key)
{
   
    FibNode<T> *child, *parent, *right;
    if (min==NULL ||node==NULL) 
        return ;
    if (key <= node->key)
    {
   
        cout << "increase failed: the new key(" << key <<") " 
             << "is no greater than current key(" << node->key <<")" << endl;
        return ;
    }
    // 将node每一个儿子(不包括孙子,重孙,...)都添加到"斐波那契堆的根链表"中
    while (node->child != NULL)
    {
   
        child = node->child;
        removeNode(child);               // 将child从node的子链表中删除
        if (child->right == child)
            node->child = NULL;
        else
            node->child = child->right;
        addNode(child, min);       // 将child添加到根链表中
        child->parent = NULL;
    }
    node->degree = 0;
    node->key = key;
    // 如果node不在根链表中,
    //     则将node从父节点parent的子链接中剥离出来,
    //     并使node成为"堆的根链表"中的一员,
    //     然后进行"级联剪切"
    // 否则,则判断是否需要更新堆的最小节点
    parent = node->parent;
    if(parent != NULL)
    {
   
        cut(node, parent);
        cascadingCut(parent);
    }
    else if(min == node)
    {
   
        right = node->right;
        while(right != node)
        {
   
            if(node->key > right->key)
                min = right;
            right = right->right;
        }
    }
}
/* 
 * 更新斐波那契堆的节点node的键值为key
 */
template <class T>
void FibHeap<T>::update(FibNode<T> *node, T key)
{
   
    if(key < node->key)
        decrease(node, key);
    else if(key > node->key)
        increase(node, key);
    else
        cout << "No need to update!!!" << endl;
}
template <class T>
void FibHeap<T>::update(T oldkey, T newkey)
{
   
    FibNode<T> *node;
    node = search(oldkey);
    if (node!=NULL)
        update(node, newkey);
}
/*
 * 在最小堆root中查找键值为key的节点
 */
template <class T>
FibNode<T>* FibHeap<T>::search(FibNode<T> *root, T key)
{
   
    FibNode<T> *t = root;    // 临时节点
    FibNode<T> *p = NULL;    // 要查找的节点
    if (root==NULL)
        return root;
    do
    {
   
        if (t->key == key)
        {
   
            p = t;
            break;
        } 
        else
        {
   
            if ((p = search(t->child, key)) != NULL) 
                break;
        }    
        t = t->right;
    } while (t != root);
    return p;
}
/*
 * 在斐波那契堆中查找键值为key的节点
 */
template <class T>
FibNode<T>* FibHeap<T>::search(T key)
{
   
    if (min==NULL)
        return NULL;
    return search(min, key);
}
/*
 * 在斐波那契堆中是否存在键值为key的节点。
 * 存在返回true,否则返回false。
 */
template <class T>
bool FibHeap<T>::contains(T key)
{
   
    return search(key)!=NULL ? true: false;
}
/*
 * 删除结点node
 */
template <class T>
void FibHeap<T>::remove(FibNode<T> *node)
{
   
    T m = min->key-1;
    decrease(node, m-1);
    removeMin();
}
template <class T>
void FibHeap<T>::remove(T key)
{
   
    FibNode<T> *node;
    if (min==NULL)
        return ;
    node = search(key);
    if (node==NULL)
        return ;
    remove(node);
}
/* 
 * 销毁斐波那契堆
 */
template <class T>
void FibHeap<T>::destroyNode(FibNode<T> *node)
{
   
    FibNode<T> *start = node;
    if(node == NULL)
        return;
    do {
   
        destroyNode(node->child);
        // 销毁node,并将node指向下一个
        node = node->right;
        delete node->left;
    } while(node != start);
}
template <class T>
void FibHeap<T>::destroy()
{
   
    destroyNode(min);
    free(cons);
}
/*
 * 打印"斐波那契堆"
 *
 * 参数说明:
 *     node       -- 当前节点
 *     prev       -- 当前节点的前一个节点(父节点or兄弟节点)
 *     direction  --  1,表示当前节点是一个左孩子;
 *                    2,表示当前节点是一个兄弟节点。
 */
template <class T>
void FibHeap<T>::print(FibNode<T> *node, FibNode<T> *prev, int direction)
{
   
    FibNode<T> *start=node;
    if (node==NULL)
        return ;
    do
    {
   
        if (direction == 1)
            cout << setw(8) << node->key << "(" << node->degree << ") is "<< setw(2) << prev->key << "'s child" << endl;
        else
            cout << setw(8) << node->key << "(" << node->degree << ") is "<< setw(2) << prev->key << "'s next" << endl;
        if (node->child != NULL)
            print(node->child, node, 1);
        // 兄弟节点
        prev = node;
        node = node->right;
        direction = 2;
    } while(node != start);
}
template <class T>
void FibHeap<T>::print()
{
   
    int i=0;
    FibNode<T> *p;
    if (min==NULL)
        return ;
    cout << "== 斐波那契堆的详细信息: ==" << endl;
    p = min;
    do {
   
        i++;
        cout << setw(2) << i << ". " << setw(4) << p->key << "(" << p->degree << ") is root" << endl;
        print(p->child, p, 1);
        p = p->right;
    } while (p != min);
    cout << endl;
}
#endif

*左偏堆

//bzoj 1455
#include <iostream>
#include <cstdio>
using namespace std;
const int N=1000001;
int n,m; int a[N]; bool die[N];
int l[N],r[N],fa[N],dep[N];
inline int read(){
   
	int x=0,f=0;char ch=getchar();
	while(!isdigit(ch))f|=ch=='-',ch=getchar();
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return f?-x:x;
}
int find(int x){
   
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int merge(int x,int y){
   
    if(!x)return y;
    if(!y)return x;
    if(a[x]>a[y]) swap(x,y);
    r[x]=merge(r[x],y);
    if(dep[r[x]]>dep[l[x]])swap(l[x],r[x]);
    dep[x]=dep[r[x]]+1;
    return x;
}
void work(){
   
    char ch[10]; int x,y;
    for(int i=1;i<=m;i++){
   
        scanf("%s",ch);
        if(ch[0]=='M') {
   
            x=read(),y=read();
            if (die[x]||die[y]) continue;
            int f1=find(x),f2=find(y);
            if(f1!=f2){
   
                int t=merge(f1,f2);
                fa[f2]=fa[f1]=t;
            }
        }
        else {
   
            x=read();
            if(die[x])printf("0\n");
            else{
   
                int f1=find(x);die[f1]=1;
                printf("%d\n",a[f1]);
                fa[f1]=merge(l[f1],r[f1]);
                fa[fa[f1]]=fa[f1];
            }
        }
    }
    return;
}
int main(){
   
    n=read();
    for(int i=1;i<=n;i++)a[i]=read(),fa[i]=i;
    m=read();
    work();
    return 0;
}

*配对堆

//Luogu P3371
#include<bits/stdc++.h>
using namespace std;
const int M=2e6+5;
int n,root,id,tot,top,val[M],head[M],nxt[M],to[M],dad[M];
queue<int>dui;
void add(int x,int y){
   
    nxt[++id]=head[x],head[x]=id,to[id]=y,dad[y]=x;
}
int _new(int x){
   
    val[++tot]=x;
    return tot;
}
int merge(int x,int y){
   
    if(!x||!y)return x+y;
    if(val[x]<val[y]){
   
        add(x,y);
        return x;
    }
    else{
   
        add(y,x);
        return y;
    }
}
void pop(){
   
    int t;
    for(int i=head[root]; i; i=nxt[i])if(dad[to[i]]==root)dui.push(to[i]),dad[to[i]</
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值