LeftistHeap左式堆的C++实现

算法导论4.14:

构造一个堆,包含k个堆中所有元素。算法的复杂度是多少?

思路

这题可以用Divide and Conquer,迭代分组合并两个堆。

假设每个堆元素最多为n个,用数组实现的算法因为每次merge比较复杂,会有O(nk*log(n))的复杂度,用链表实现因为直接连起来就可以,所以复杂度只有O(log(k)log(n))。

所以这题最好使用链表实现堆来写,但书上给的堆都是用数组实现的,所以就自己写一个左式堆(LeftistHeap)吧,左式堆天然地支持快速合并,用来实现这个算法再合适不过了。之后用一个vector把k个堆装起来,迭代地k_merge前一半的堆和后一半的堆就实现了算法。

代码

//LeftisHeap.h
#ifndef LeftistHeap_H
#define LeftistHeap_H

template<class Comparable>
class LeftistHeap
{
public:
    LeftistHeap(){ root = nullptr; }
    LeftistHeap(const LeftistHeap &rhs)
    {
        root = clone(rhs.root);
    }
    ~LeftistHeap()
    {
        makeEmpty();
    }
    LeftistHeap& operator=(const LeftistHeap &rhs)
    {
        if (this != &rhs)
        {
            makeEmpty();
            root = clone(rhs.root);
        }
        return *this;
    }
    bool isEmpty()const
    {
        return root == nullptr;
    }
    const Comparable& findMax()const
    {
        if (!root)
            return -1;
        return root->element;
    }
    void insert(const Comparable x)
    {
        root = merge(new LeftistNode(x), root);
    }
    void deleteMax()
    {
        if (!isEmpty())
        {
            LeftistNode *old = root;
            root = merge(root->left, root->right);
            delete old;
        }
    }
    void deleteMax(Comparable &x)
    {
        x = findMax();
        deleteMax();
    }
    void makeEmpty()
    {
        reclaimMemory(root);
        root = nullptr;
    }
    void merge(LeftistHeap &rhs)
    {
        if (this == &rhs)
            return;
        root = merge(root, rhs.root);
        rhs.root = nullptr;
    }
    void print()
    {
        LeftistHeap backup_heap;
        vector<Comparable> print_v;
        while (this->root)
        {
            print_v.push_back(this->findMax());
            backup_heap.insert(this->findMax());
            this->deleteMax();
        }
        for (vector<Comparable>::size_type i = 0; i < print_v.size(); i++)
        {
            cout << print_v[i] << " ";
        }
        cout << endl;
        *this = backup_heap;
    }


private:
    struct LeftistNode
    {
        Comparable element;
        LeftistNode *left;
        LeftistNode *right;
        int npl;

        LeftistNode(const Comparable &e, LeftistNode *l = nullptr, LeftistNode *r = nullptr, int x = 0)
            :element(e), left(l), right(r), npl(x){}
    };
    LeftistNode *root;

    LeftistNode *merge(LeftistNode *h1, LeftistNode *h2)
    {
        if (h1 == nullptr)
            return h2;
        if (h2 == nullptr)
            return h1;
        if (h1->element > h2->element)
            return merge1(h1, h2);
        else
            return merge1(h2, h1);
    }
    LeftistNode *merge1(LeftistNode *h1, LeftistNode *h2)
    {
        if (h1->left == nullptr)
            h1->left = h2;
        else
        {
            h1->right = merge(h1->right, h2);
            if (h1->left->npl < h1->right->npl)
                swapChildren(h1);
            h1->npl = h1->right->npl + 1;
        }
        return h1;
    }
    void swapChildren(LeftistNode *h1)
    {
        if (h1 != nullptr)
        {
            LeftistNode *h = h1->left;
            h1->left = h1->right;
            h1->right = h;
        }
    }

    void LeftistHeap::reclaimMemory(LeftistNode *t)
    {
        if (t != nullptr)
        {
            reclaimMemory(t->left);
            reclaimMemory(t->right);
            delete t;
        }
    }

    LeftistNode *clone(const LeftistNode *t)
    {
        if (t == nullptr)
            return nullptr;
        return new LeftistNode(t->element, clone(t->left), clone(t->right), t->npl);
    }

};

#endif
//main_k_merge.cpp
#include "LeftistHeap.h"
#include <iostream>
#include <vector>

using namespace std;

template <class T>
vector<LeftistHeap<T> > build_heaps()
{
    vector<LeftistHeap<T> > ret;
    int i = 1;

    while (true)
    {
        T data = -1;

        cout << "Input the Heap No." << i
            << " ~, input neg numbers to end Heap, C^Z to end"
            << endl;

        if (!(cin >> data))
            break;

        LeftistHeap<T> *h = new LeftistHeap<T>;
        do
        {
            if (data < 0)
                break;

            h->insert(data);
        } while (cin >> data);

        ret.push_back(*h);
        i++;
    }

    return ret;
}

LeftistHeap<int> merge_k(vector<LeftistHeap<int> > &heaps)
{
    if (heaps.size() < 2)
        return heaps[0];
    if (heaps.size() == 2)
    {
        heaps[0].merge(heaps[1]);
        return heaps[0];
    }

    vector<LeftistHeap<int> > v1(heaps.begin(), heaps.begin() + heaps.size()/2);
    vector<LeftistHeap<int> > v2(heaps.begin() + heaps.size() / 2, heaps.end());

    LeftistHeap<int> merged = merge_k(v1);
    LeftistHeap<int> merge_2 = merge_k(v2);

    merged.merge(merge_2);
    return merged;
}

int main()
{
    vector<LeftistHeap<int> > heap_sets = build_heaps<int>();

    cout << "Input heaps:" << endl;
    for (vector<LeftistHeap<int> >::size_type i = 0; i != heap_sets.size(); i++)
    {
        heap_sets[i].print();
        cout << endl;
    }

    LeftistHeap<int>  merged_heap = merge_k(heap_sets);

    cout << "The merged heap: " << endl;
    merged_heap.print();

    system("pause");
    return 0;
}

参考资料

《数据结构与算法设计:C++实现》

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值