简单K路归并C实现

K路归并

对于K>2的归并,先判断归并个数是否满足(N)%(K-1) == 1。若不满足,则补上若干个0使其满足。然后每次选择K个最小的归并,重复此操作至最后只剩一个。
实现时使用了有序单链表来存储待归并的元素。

向单链表插入一个元素

/**
在链表中插入新结点
*/
void insertElem(Link& L, int e)
{
    Link pNode = new Node();
    pNode->elem = e;
    if(!L)
    {
        L = pNode;
        pNode->prior = NULL;
        pNode->next = NULL;
        return;
    }
    Link p = L;
    while(p)
    {
        if(p->elem >= e)
        {
            pNode->prior = p->prior;
            pNode->next = p;
            if(p == L)
            {
                L = pNode;
                p->prior = NULL;
            }
            else
            {
                p->prior->next = pNode;
            }
            p->prior = pNode;
            return;
        }
        if(!p->next)
        {
            p->next = pNode;
            pNode->prior = p;
            pNode->next = NULL;
            return;
        }
        p = p->next;
    }
}

从单链表删除前m个元素

/**
从链表出摘除m个结点,
并把各结点数值依次放在dest中,
把实际摘除的结点数放在n中
*/
void removeElems(Link& L, int dest[], int m, int& n)
{
    if(m <= 0)
    {
        n = 0;
        return;
    }
    int i = 0;
    Link p = L;
    Link temp;
    while(p && i < m)
    {
        dest[i]= p->elem;
        i++;

        temp = p->next;
        dele
te p;
        p = temp;
    }
    L = p;
    n = i;
}

完整实现

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <iomanip>

using namespace std;

typedef struct LINK
{
    int elem;
    LINK* prior;
    LINK* next;
}*Link, Node;

void insertElem(Link& L, int e);
void removeElems(Link& L, int dest[], int m, int& n);
void printElems(Link L);
void printChoice(int dest[], int e, int n);

int main()
{
    Link L = NULL;
    int e;
    int n = 0;
    while(true)
    {
        cout<<"请输入文件大小(非正数表示输入结束):";
        cin>>e;
        if(e <= 0)
            break;
        insertElem(L, e);
        n++;
    }
    if(n < 2)
    {
        cout<<"无需归并"<<endl;
        return 0;
    }
    cout<<"请输入归并路数:";
    cin>>e;
    if(e <= 1)
    {
        cout<<"归并路数必须为大于1的整数"<<endl;
        return 0;
    }

    int* dest = new int[e];

    //补0
    while(e > 2)
    {
        if(n % (e-1) == 1)
            break;
        insertElem(L, 0);
        n++;
    }

    cout<<endl<<"序列                                选择                                花费"<<endl;
    int i;
    for(i = 0; i < 80; i++)
        cout<<'*';
    cout<<endl;

    int size;
    int total = 0;
    while(true)
    {
        printElems(L);
        removeElems(L, dest, e, n);
        if(n < e)
        {
            cout<<endl;
            for(i = 0; i < 80; i++)
                cout<<'*';
            cout<<endl;
            cout<<"归并完成,最终文件序列:"<<endl;
            cout<<dest[0]<<endl;
            cout<<"总花费:"<<total;
            break;
        }
        else
        {
            printChoice(dest, e, n);
            size = 0;
            while(n > 1)
            {
                size += dest[e-n];
                n--;
            }
            size += dest[e-n];
            total += size;
            cout<<size<<endl<<endl;
            insertElem(L, size);
        }
    }

    return 0;
}

/**
在链表中插入新结点
*/
void insertElem(Link& L, int e)
{
    Link pNode = new Node();
    pNode->elem = e;
    if(!L)
    {
        L = pNode;
        pNode->prior = NULL;
        pNode->next = NULL;
        return;
    }
    Link p = L;
    while(p)
    {
        if(p->elem >= e)
        {
            pNode->prior = p->prior;
            pNode->next = p;
            if(p == L)
            {
                L = pNode;
                p->prior = NULL;
            }
            else
            {
                p->prior->next = pNode;
            }
            p->prior = pNode;
            return;
        }
        if(!p->next)
        {
            p->next = pNode;
            pNode->prior = p;
            pNode->next = NULL;
            return;
        }
        p = p->next;
    }
}

/**
从链表出摘除m个结点,
并把各结点数值依次放在dest中,
把实际摘除的结点数放在n中
*/
void removeElems(Link& L, int dest[], int m, int& n)
{
    if(m <= 0)
    {
        n = 0;
        return;
    }
    int i = 0;
    Link p = L;
    Link temp;
    while(p && i < m)
    {
        dest[i] = p->elem;
        i++;


        temp = p->next;
        delete p;
        p = temp;
    }
    L = p;
    n = i;
}

/**
打印链表
*/
void printElems(Link L)
{
    Link p = L;
    string elems;
    char* temp = new char[20];
    while(p)
    {
        sprintf(temp, "%d", p->elem);
        elems.append(temp);
        if(p->next)
            elems.append(", ");
        else
            break;
        p = p->next;
    }

    int len = elems.length();
    int i = 0;
    while(len > 34)
    {
        cout<<setw(36)<<left<<elems.substr(i, 34)<<endl;
        i += 34;
        len -= 34;
    }
    cout<<setw(36)<<left<<elems.substr(i, len);
    delete temp;
}

/**
打印所选结点值数组
*/
void printChoice(int dest[], int e, int n)
{
    string choiceStr;
    char* temp = new char[20];
    while(n > 1)
    {
        sprintf(temp, "%d", dest[e-n]);
        choiceStr.append(temp);
        choiceStr.append(", ");
        n--;
    }
    sprintf(temp, "%d", dest[e-n]);
    choiceStr.append(temp);

    int len = choiceStr.length();
    int i = 0;
    while(len > 34)
    {
        cout<<setw(36)<<left<<choiceStr.substr(i, 34)<<endl;
        i += 34;
        len -= 34;
    }
    cout<<setw(36)<<left<<choiceStr.substr(i, len);
    delete temp;
}

运行结果

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值