1. 程式人生 > >模板庫(五) - 資料結構模板

模板庫(五) - 資料結構模板

寫在前面

模板庫”這一系列文章用來複習 O I OI 模板
由於時間原因,作者無法一一親自除錯其中的程式,也因如此,有一部分程式來自於網際網路,如果您覺得這侵犯了您的合法權益,請聯絡 ( Q

Q 2068926345 ) (QQ2068926345) 刪除。
對於給您造成的不便和困擾,我表示深深的歉意。
本系列文章僅用於學習,禁止任何人或組織用於商業用途。
本系列文章中,標記*的為選學演算法,在 N O
I P NOIP
中較少涉及。

資料結構

佇列

【簡介】

佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端 ( h e a

d ) (head) 進行刪除操作,而在表的後端 ( t a i l ) (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)


【簡介】

( s t a c k ) (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)


【簡介】

堆( h e a p 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 <