算法导论6.5-8习题解答(最小堆K路合并)

《算法导论》第六章第五节的第8题,原题为:请给出一个时间为O(nlgk)、用来将k个已排序链表合并为一个排序链表的算法。此处n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并)。

算法思想:
1.
k个链表中取出每个链表的第一个元素,组成一个大小为k的数组arr,然后将数组arr转换为最小堆,那么arr[0]就为最小元素了

2.
取出arr[0],将其放到新的链表中,然后将arr[0]元素在原链表中的下一个元素补到arr[0]处,即arr[0].next,如果 arr[0].next为空,即它所在的链表的元素已经取完了,那么将堆的最后一个元素补到arr[0]处,堆的大小自动减一,循环n-k次即可。

为了方便粘贴,把.h.cpp都弄在一起,首先是两个类ListNode,然后就是两个关于最小堆操作的函数,代码有点长,但是一点都不难,因为你肯定看过最大堆的操作,那么最小堆就大同小异了:
 

#include <iostream>

using namespace std;

class Node

{

public:

    Node* next;

    int data;

    Node();

    Node(int d);

    operator Node() const;

    //只需用到"<"

    bool operator < (const Node& temp);

};

class List

{

public:

    Node* first;

    List();

    void insert(int d);

};

//修正i的位置,在此处已经假设i的子节点都是堆

void min_heapify(Node* &a, int i, int length);

//建立数组的堆

void build_min_heap(Node* &a, int length);

int main()

{

    int K = 5;

    List* list_one  = new List();

    List* list_two = new List();

    List* list_three = new List();

    List* list_four = new List();

    List* list_five = new List();

    for(int i = 0; i < 5; i++)

    {

        list_one->insert(i);

        list_two->insert(i - 3);

        list_three->insert(i + 5);

        list_four->insert(2*i);

        list_five->insert(i - 10);

    }

    Node* arr = new Node[K];

    arr[0] = *(list_one->first);

    arr[1] = *(list_two->first);

    arr[2] = *(list_three->first);

    arr[3] = *(list_four->first);

    arr[4] = *(list_five->first);

    //先对这K个排序

    build_min_heap(arr, K);

    List* list = new List();

    //每次取arr[0]的下一个Node,如果Node为空的话,

    //则把堆末尾的元素补到arr[0],由于有--K,所以堆的大小减一

    while(K > 0)

    {

        list->insert(arr[0].data);

        if(arr[0].next != NULL)

            arr[0] = *(arr[0].next);

        else

            arr[0] = arr[--K];

        min_heapify(arr, 0, K);

    }

    Node* begin = list->first;

    while(begin != NULL)

    {

        cout<<begin->data<<endl;

        begin = begin->next;

    }

    return 0;

}

void min_heapify(Node* &a, int i, int length)

{

    int smallest = i;

    while(smallest <= length - 1)

    {

        int left = 2*smallest + 1;

        int right = 2*smallest + 2;

        int temp = smallest;

        if(left <= length - 1 && a[left] < a[smallest])

        {

            smallest = left;

        }

        if(right <= length - 1 && a[right] < a[smallest])

        {

            smallest = right;

        }

        if(smallest != temp)

        {

            Node exchange = a[smallest];

            a[smallest] = a[temp];

            a[temp] = exchange;

        }

        else

            break;

    }

}

void build_min_heap(Node* &a, int length)

{

    int root = length/2 - 1;

    for(int i = root; i >= 0; i--)

        min_heapify(a, i, length);

}

Node::Node()

{

    next = NULL;

}

Node::Node(int d)

{

    data = d;

    next = NULL;

}

Node::operator Node() const

{

    return data;

}

bool Node::operator<(const Node& temp)

{

    if(data < temp.data)

        return true;

    return false;

}

List::List()

{

    first = NULL;

}

 

void List::insert(int d)

{

    Node* node = new Node(d);

    if(first == NULL)

        first = node;

    else

    {

        Node* temp = first->next;

        Node* prev = first;

        while(temp != NULL)

        {

            prev = temp;

            temp = temp->next;

        }

        prev->next = node;

    }

}

原文链接:http://www.cnblogs.com/shuaiwhu/archive/2011/03/20/2065077.html

 

你可能感兴趣的:(算法导论6.5-8习题解答(最小堆K路合并))