Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;合并链表排序的实现在连接多个节点的子列表时失败_C++_Templates_Mergesort - Fatal编程技术网

C++ C++;合并链表排序的实现在连接多个节点的子列表时失败

C++ C++;合并链表排序的实现在连接多个节点的子列表时失败,c++,templates,mergesort,C++,Templates,Mergesort,我一直在致力于链表的模板化实现,目的是重新发明轮子,偶然发现这种类型的问题,以帮助学习指向类实例处理的指针的细微差别。我遇到的问题与合并子列表有关,在第二次合并(第一次合并,子列表可以有多个节点)失败时,先前的类实例(来自split或mergesorted)似乎超出范围(这不应该对合并有任何影响,因为指针分配是一个始终保留在范围内的前一个列表,直到原始列表节点的分配发生之后) 这里的关键是,所有类实例都有指向原始列表中原始节点的指针,因此只要子列表实例仍在作用域中,直到子列表的开始节点在上一个递

我一直在致力于链表的模板化实现,目的是重新发明轮子,偶然发现这种类型的问题,以帮助学习指向类实例处理的指针的细微差别。我遇到的问题与合并子列表有关,在第二次合并(第一次合并,子列表可以有多个节点)失败时,先前的类实例(来自
split
mergesorted
)似乎超出范围(这不应该对合并有任何影响,因为指针分配是一个始终保留在范围内的前一个列表,直到原始列表节点的分配发生之后)

这里的关键是,所有类实例都有指向原始列表中原始节点的指针,因此只要子列表实例仍在作用域中,直到子列表的开始节点在上一个递归中返回并分配给列表。我正在尝试移动一个完美的100%工作的C实现。因此,这是一个问题我理解为什么我不能像对待C中的结构一样对待类实例,这就是这里的问题——但我不能把我的手指放在解释原因的文档上

list\u t
包含构成列表的结构
节点

/* linked list node */
template <class T>
struct node_t {
    T data;
    node_t<T> *next;
};

template <class T>
class list_t {
    node_t<T> *head, *tail;
    int (*cmp)(const node_t<T>*, const node_t<T>*);

    public:
    list_t (void);                          /* constructors */
    list_t (int(*f)(const node_t<T>*, const node_t<T>*));
    ~list_t (void);                         /* destructor */
    list_t (const list_t&);                 /* copy constructor */
    /* setter for compare function */
    ,,,
    list_t split (void);                    /* split list ~ 1/2 */
    ...
    /* merge lists after mergesort_start */
    node_t<T> *mergesorted (node_t<T> *a, node_t<T> *b);
    void mergesort_run (list_t<T> *l);      /* mergesort function */
    void mergesort (void);                  /* wrapper for mergesort */
};
对于mergesort,我有一个包装器,它调用实际的mergesort函数
mergesort\u run

/* wrapper to the actual mergesort routing in mergesort_run */
template <class T>
void list_t<T>::mergesort(void)
{
    mergesort_run (this);

    /* set tail pointer to last node after sort */
    for (node_t<T> *pn = head; pn; pn = pn->next)
        tail = pn;
}
合并函数,
mergesorted
按排序顺序合并子列表:

template <class T>
node_t<T> *list_t<T>::mergesorted (node_t<T> *a, node_t<T> *b) 
{ 
    node_t<T> *result = nullptr;

    /* Base cases */
    if (!a) 
        return (b); 
    else if (!b) 
        return (a); 

    /* Pick either a or b, and recur */
    if (cmp (a, b) <= 0) { 
        result = a; 
        result->next = mergesorted (a->next, b); 
    } 
    else { 
        result = b; 
        result->next = mergesorted (a, b->next); 
    }

    return result; 
} 
将左子列表拆分为节点
12
11
后,左子列表的开始合并将正常进行。一旦我将
11、12
子列表与
10
合并,则
11、12
子列表的值将消失

MCVE

#include <iostream>

/* linked list node */
template <class T>
struct node_t {
    T data;
    node_t<T> *next;
};

/* default compare function for types w/overload (ascending) */
template <typename T>
int compare_asc (const node_t<T> *a, const node_t<T> *b)
{
    return (a->data > b->data) - (a->data < b->data);
}

/* compare function for types w/overload (descending) */
template <typename T>
int compare_desc (const node_t<T> *a, const node_t<T> *b)
{
    return (a->data < b->data) - (a->data > b->data);
}

template <class T>
class list_t {
    node_t<T> *head, *tail;
    int (*cmp)(const node_t<T>*, const node_t<T>*);

    public:
    list_t (void);                          /* constructors */
    list_t (int(*f)(const node_t<T>*, const node_t<T>*));
    ~list_t (void);                         /* destructor */
    list_t (const list_t&);                 /* copy constructor */
    /* setter for compare function */
    void setcmp (int (*f)(const node_t<T>*, const node_t<T>*));

    node_t<T> *addnode (T data);            /* simple add at end */
    node_t<T> *addinorder (T data);         /* add in order */
    void delnode (T data);                  /* delete node */
    void prnlist (void);                    /* print space separated */

    list_t split (void);                    /* split list ~ 1/2 */

    void insertionsort (void);              /* insertion sort list */

    /* merge lists after mergesort_start */
    node_t<T> *mergesorted (node_t<T> *a, node_t<T> *b);
    void mergesort_run (list_t<T> *l);      /* mergesort function */
    void mergesort (void);                  /* wrapper for mergesort */
};

/* constructor (default) */
template <class T>
list_t<T>::list_t (void)
{
    head = tail = nullptr;
    cmp = compare_asc;
}

/* constructor taking compare function as argument */
template <class T>
list_t<T>::list_t (int(*f)(const node_t<T>*, const node_t<T>*))
{
    head = tail = nullptr;
    cmp = f;
}

/* destructor free all list memory */
template <class T>
list_t<T>::~list_t (void)
{
    node_t<T> *pn = head;
    while (pn) {
        node_t<T> *victim = pn;
        pn = pn->next;
        delete victim;
    }
}

/* copy ctor - copy exising list */
template <class T>
list_t<T>::list_t (const list_t& l)
{
    cmp = l.cmp;                        /* assign compare function ptr */
    head = tail = nullptr;              /* initialize head/tail */

    /* copy data to new list */
    for (node_t<T> *pn = l.head; pn; pn = pn->next)
        this->addnode (pn->data);
}

/* setter compare function */
template <class T>
void list_t<T>::setcmp (int(*f)(const node_t<T>*, const node_t<T>*))
{
    cmp = f;
}

/* add using tail ptr */
template <class T>
node_t<T> *list_t<T>::addnode (T data)
{
    node_t<T> *node = new node_t<T>;        /* allocate/initialize node */
    node->data = data;
    node->next = nullptr;

    if (!head)
        head = tail = node;
    else {
        tail->next = node;
        tail = node;
    }

    return node;
}

template <class T>
node_t<T> *list_t<T>::addinorder (T data)
{
    if (!cmp) {     /* validate compare function not nullptr */
        std::cerr << "error: compare is nullptr.\n";
        return nullptr;
    }

    node_t<T> *node = new node_t<T>;        /* allocate/initialize node */
    node->data = data;
    node->next = nullptr;

    node_t<T> **ppn = &head,                /* ptr-to-ptr to head */
              *pn = head;                   /* ptr to head */

    while (pn && cmp (node, pn) > 0) {      /* node sorts after current */
        ppn = &pn->next;                    /* ppn to address of next */
        pn = pn->next;                      /* advance pointer to next */
    }

    node->next = pn;                        /* set node->next to next */
    if (pn == nullptr)
        tail = node;
    *ppn = node;                            /* set current to node */

    return node;                            /* return node */
}

template <class T>
void list_t<T>::delnode (T data)
{
    node_t<T> **ppn = &head;        /* pointer to pointer to node */
    node_t<T> *pn = head;           /* pointer to node */

    for (; pn; ppn = &pn->next, pn = pn->next) {
        if (pn->data == data) {
            *ppn = pn->next;        /* set address to next */
            delete pn;
            break;
        }
    }
}

template <class T>
void list_t<T>::prnlist (void)
{
    if (!head) {
        std::cout << "empty-list\n";
        return;
    }
    for (node_t<T> *pn = head; pn; pn = pn->next)
        std::cout << " " << pn->data;
    std::cout << '\n';
}

/* split list l into lists a & b */
template <class T>
list_t<T> list_t<T>::split (void)
{
    list_t<T> s;                /* new instance of class */

    node_t<T> *pa = head,       /* pointer to current head */
            *pb = pa->next;     /* 2nd pointer to double-advance */

    while (pb) {                /* while not end of list */
        pb = pb->next;          /* advance 2nd ptr */
        if (pb) {               /* if not nullptr */
            pa = pa->next;      /* advance current ptr */
            pb = pb->next;      /* advance 2nd ptr again */
        }
    }

    s.tail = tail;              /* 2nd half tail will be current tail */
    tail = pa;                  /* current tail is at pa */

    s.head = pa->next;          /* 2nd half head is next ptr */
    pa->next = nullptr;         /* set next ptr NULL to end 1st 1/2 */

    return s;                   /* return new instance */
}

/** insertion sort of linked list.
 *  re-orders list in sorted order.
 */
template <class T>
void list_t<T>::insertionsort (void) 
{ 
    node_t<T> *sorted = head,       /* initialize sorted list to 1st node */
              *pn = head->next;     /* advance original list node to next */

    sorted->next = NULL;            /* initialize sorted->next to NULL */

    while (pn) {                    /* iterate over existing from 2nd node */
        node_t<T> **pps = &sorted,  /* ptr-to-ptr to sorted list */
                *ps = *pps,         /* ptr to sorted list */
                *next = pn->next;   /* save list next as separate pointer */

        while (ps && cmp(ps, pn) < 0) {  /* loop until sorted */
            pps = &ps->next;        /* get address of next node */
            ps = ps->next;          /* get next node pointer */
        }

        *pps = pn;          /* insert existing in sort order as current */
        pn->next = ps;      /* set next as sorted next */
        pn = next;          /* reinitialize existing pointer to next */
    }

    head = sorted;          /* update head to sorted head */

    /* set tail pointer to last node after sort */
    for (pn = head; pn; pn = pn->next)
        tail = pn;
}

/* FIXME mergesort recursion not working */
template <class T>
node_t<T> *list_t<T>::mergesorted (node_t<T> *a, node_t<T> *b) 
{ 
    node_t<T> *result = nullptr;

    /* Base cases */
    if (!a) 
        return (b); 
    else if (!b) 
        return (a); 

    /* Pick either a or b, and recur */
    if (cmp (a, b) <= 0) { 
        result = a; 
        result->next = mergesorted (a->next, b); 
    } 
    else { 
        result = b; 
        result->next = mergesorted (a, b->next); 
    }

    return result; 
} 

/* split and merge splits in sort order */
template <class T>
void list_t<T>::mergesort_run (list_t<T> *l) 
{ 
    /* Base case -- length 0 or 1 */
    if (!l->head || !l->head->next) { 
        return; 
    } 

    /* Split head into 'a' and 'b' sublists */
    list_t<T> la = l->split(); 

    /* Recursively sort the sublists */
    mergesort_run(l); 
    mergesort_run(&la);

    /* merge the two sorted lists together */
    l->head = mergesorted (l->head, la.head);
}

/* wrapper to the actual mergesort routing in mergesort_run */
template <class T>
void list_t<T>::mergesort(void)
{
    mergesort_run (this);

    /* set tail pointer to last node after sort */
    for (node_t<T> *pn = head; pn; pn = pn->next)
        tail = pn;
}

int main (void) {

    list_t<int> l;

    int arr[] = {12, 11, 10, 7, 4, 14, 8, 16, 20, 19, 
                  2, 9, 1, 13, 17, 6, 15, 5, 3, 18};
    unsigned asz = sizeof arr / sizeof *arr;

    for (unsigned i = 0; i < asz; i++)
        l.addnode (arr[i]);

    l.prnlist();
#ifdef ISORT
    l.insertionsort();
#else
    l.mergesort();
#endif
    l.prnlist();
}
合并排序的结果--不好

$ ./bin/ll_merge_post
 12 11 10 7 4 14 8 16 20 19 2 9 1 13 17 6 15 5 3 18
 0 16108560 16108656 16108688 16108560 16108816 16108784 16108848 16108752 16108720 16109072 16108976 16108944 16109008 16108880 16108912 16109136 16109104 16109168 16109040

所以我被卡住了。(这可能是我应该看到但不应该看到的简单的事情)为何子列表的合并失败?在C++结构中处理类实例的关键部分是什么?

< p>在<代码> GiuSoRtTyRun<代码>中,您有一个本地列表<代码> La<代码>,包含了您的源列表的一半。在函数的结尾,您将代码< La>代码>的内容合并回新列表,但变量本身仍指向合并的节点。当运行
la
的析构函数时,这些节点将被删除

如果在执行合并后将
la
的头节点设置为空指针(
la.head=nullptr
),则当析构函数运行时,没有任何节点可供其删除


一个不相关的问题是,在创建新列表(如
split
)时,您没有将
cmp
复制到适当的位置。

FWIW,您的MCVE在使用Visual Studio 2019运行时会崩溃,指针0xdddddd无效(这意味着您正在访问解除分配的内存)。如果您有Windows计算机,也许您应该获取社区版并运行代码。谢谢Paul。我没有在Windows上运行它。(我必须重新启动当前计算机才能进入W10 w/VS 2017)。这里发生了一些有趣的事情。这与
valgrind
输出相对应,但没有解释代码的gcc/gdb处理方式。我有一个较旧的
gcc(Leap上的4.8.5
,但我必须在Arch上尝试,看看它在那里是否得到不同的处理(使用
-std=c++11
编译)另外,您没有为list类实现赋值运算符。我不知道这是否有什么不同,但您正在一个函数中按值返回
list\u t
split
),如果没有实现所有“3的规则”,这可能会产生副作用函数。是的,这是我研究的一个领域。回想一下
split
从完整列表中提取原始节点,并简单地将列表一分为二(就像C实现那样)并按值返回一个结构/类,其中包含指向原始节点的指针。如果这是由于
节点
上的规则3而导致逻辑失败的地方,那么这可能有一定意义,但我之前测试了连接拆分。让我运行另一个快速测试。是的,我建议您启动Visual Studio--错误每次都会重复出现。应该只需要运行几次就可以看出是什么导致了它。是的,但是由于
la
持有的节点是原始节点,在调用析构函数之前对联接列表的赋值应该是正确的??对吗?这也对应于C代码中使用的本地
list\u t la;
,其行为与预期一致。这就是rEAL让我抓挠我。一个本地C结构很好,但是我找不到任何地方用C++实例处理的差别。.davidC.RANKIN分配是很好的,在节点被复制的意义上,但是原始<代码> La<代码>数据不变(所以它和新列表都指向同一个节点)。当代码> La<代码>被破坏时,合并的节点将被删除,而一半的结果是无效的。C代码很好,因为它没有析构函数。因为 Listyt有一个析构函数,C++代码做的C代码不。我现在得到了,该死的本地实例指向相同的节点,但是析构函数运行。s并清除它们——这就是在这种情况下C/C++结构/类处理之间的区别!!(宾果)现在我该如何禁用析构函数?(我通常会将T->head设置为
nullptr
以停止它的运行——这应该在这里起作用)--等等!哇哇!!
la.head=nullptr;
是运行
mergesort\u
结束时所需的全部内容!(添加此项,我将接受)
/* split list l into lists a & b */
void split (list_t *l, list_t *a)
{
    node_t  *pa = l->head,
            *pb = pa->next;

    while (pb) {
        pb = pb->next;
        if (pb) {
            pa = pa->next;
            pb = pb->next;
        }
    }

    a->tail = l->tail;
    l->tail = pa;

    a->head = pa->next;
    pa->next = NULL;
}

/* merge splits in sort order */
node_t *mergesorted (node_t *a, node_t *b) 
{ 
    node_t  *res = NULL;

    /* base cases */
    if (!a) 
        return (b); 
    else if (!b) 
        return (a); 

    /* Pick either a or b, and recurse */
    if (a->data <= b->data) { 
        res = a; 
        res->next = mergesorted (a->next, b); 
    } 
    else { 
        res = b; 
        res->next = mergesorted (a, b->next); 
    } 
    return res; 
} 

/* sorts the linked list by changing next pointers (not data) */
void mergesort (list_t *l) 
{ 
    list_t la;
    node_t *head = l->head; 

    /* Base case -- length 0 or 1 */
    if (!head || !head->next) { 
        return; 
    } 

    /* Split head into 'a' and 'b' sublists */
    split (l, &la); 

    /* Recursively sort the sublists */
    mergesort(l); 
    mergesort(&la); 

    /* answer = merge the two sorted lists together */
    l->head = mergesorted (l->head, la.head);

    /* set tail pointer to last node after sort */
    for (head = l->head; head; head = head->next)
        l->tail = head;
}
    list_t<int> l;

    int arr[] = {12, 11, 10, 7, 4, 14, 8, 16, 20, 19, 
                  2, 9, 1, 13, 17, 6, 15, 5, 3, 18};
    unsigned asz = sizeof arr / sizeof *arr;

    for (unsigned i = 0; i < asz; i++)
        l.addnode (arr[i]);

    l.prnlist();
#ifdef ISORT
    l.insertionsort();
#else
    l.mergesort();
#endif
    l.prnlist();
}
#include <iostream>

/* linked list node */
template <class T>
struct node_t {
    T data;
    node_t<T> *next;
};

/* default compare function for types w/overload (ascending) */
template <typename T>
int compare_asc (const node_t<T> *a, const node_t<T> *b)
{
    return (a->data > b->data) - (a->data < b->data);
}

/* compare function for types w/overload (descending) */
template <typename T>
int compare_desc (const node_t<T> *a, const node_t<T> *b)
{
    return (a->data < b->data) - (a->data > b->data);
}

template <class T>
class list_t {
    node_t<T> *head, *tail;
    int (*cmp)(const node_t<T>*, const node_t<T>*);

    public:
    list_t (void);                          /* constructors */
    list_t (int(*f)(const node_t<T>*, const node_t<T>*));
    ~list_t (void);                         /* destructor */
    list_t (const list_t&);                 /* copy constructor */
    /* setter for compare function */
    void setcmp (int (*f)(const node_t<T>*, const node_t<T>*));

    node_t<T> *addnode (T data);            /* simple add at end */
    node_t<T> *addinorder (T data);         /* add in order */
    void delnode (T data);                  /* delete node */
    void prnlist (void);                    /* print space separated */

    list_t split (void);                    /* split list ~ 1/2 */

    void insertionsort (void);              /* insertion sort list */

    /* merge lists after mergesort_start */
    node_t<T> *mergesorted (node_t<T> *a, node_t<T> *b);
    void mergesort_run (list_t<T> *l);      /* mergesort function */
    void mergesort (void);                  /* wrapper for mergesort */
};

/* constructor (default) */
template <class T>
list_t<T>::list_t (void)
{
    head = tail = nullptr;
    cmp = compare_asc;
}

/* constructor taking compare function as argument */
template <class T>
list_t<T>::list_t (int(*f)(const node_t<T>*, const node_t<T>*))
{
    head = tail = nullptr;
    cmp = f;
}

/* destructor free all list memory */
template <class T>
list_t<T>::~list_t (void)
{
    node_t<T> *pn = head;
    while (pn) {
        node_t<T> *victim = pn;
        pn = pn->next;
        delete victim;
    }
}

/* copy ctor - copy exising list */
template <class T>
list_t<T>::list_t (const list_t& l)
{
    cmp = l.cmp;                        /* assign compare function ptr */
    head = tail = nullptr;              /* initialize head/tail */

    /* copy data to new list */
    for (node_t<T> *pn = l.head; pn; pn = pn->next)
        this->addnode (pn->data);
}

/* setter compare function */
template <class T>
void list_t<T>::setcmp (int(*f)(const node_t<T>*, const node_t<T>*))
{
    cmp = f;
}

/* add using tail ptr */
template <class T>
node_t<T> *list_t<T>::addnode (T data)
{
    node_t<T> *node = new node_t<T>;        /* allocate/initialize node */
    node->data = data;
    node->next = nullptr;

    if (!head)
        head = tail = node;
    else {
        tail->next = node;
        tail = node;
    }

    return node;
}

template <class T>
node_t<T> *list_t<T>::addinorder (T data)
{
    if (!cmp) {     /* validate compare function not nullptr */
        std::cerr << "error: compare is nullptr.\n";
        return nullptr;
    }

    node_t<T> *node = new node_t<T>;        /* allocate/initialize node */
    node->data = data;
    node->next = nullptr;

    node_t<T> **ppn = &head,                /* ptr-to-ptr to head */
              *pn = head;                   /* ptr to head */

    while (pn && cmp (node, pn) > 0) {      /* node sorts after current */
        ppn = &pn->next;                    /* ppn to address of next */
        pn = pn->next;                      /* advance pointer to next */
    }

    node->next = pn;                        /* set node->next to next */
    if (pn == nullptr)
        tail = node;
    *ppn = node;                            /* set current to node */

    return node;                            /* return node */
}

template <class T>
void list_t<T>::delnode (T data)
{
    node_t<T> **ppn = &head;        /* pointer to pointer to node */
    node_t<T> *pn = head;           /* pointer to node */

    for (; pn; ppn = &pn->next, pn = pn->next) {
        if (pn->data == data) {
            *ppn = pn->next;        /* set address to next */
            delete pn;
            break;
        }
    }
}

template <class T>
void list_t<T>::prnlist (void)
{
    if (!head) {
        std::cout << "empty-list\n";
        return;
    }
    for (node_t<T> *pn = head; pn; pn = pn->next)
        std::cout << " " << pn->data;
    std::cout << '\n';
}

/* split list l into lists a & b */
template <class T>
list_t<T> list_t<T>::split (void)
{
    list_t<T> s;                /* new instance of class */

    node_t<T> *pa = head,       /* pointer to current head */
            *pb = pa->next;     /* 2nd pointer to double-advance */

    while (pb) {                /* while not end of list */
        pb = pb->next;          /* advance 2nd ptr */
        if (pb) {               /* if not nullptr */
            pa = pa->next;      /* advance current ptr */
            pb = pb->next;      /* advance 2nd ptr again */
        }
    }

    s.tail = tail;              /* 2nd half tail will be current tail */
    tail = pa;                  /* current tail is at pa */

    s.head = pa->next;          /* 2nd half head is next ptr */
    pa->next = nullptr;         /* set next ptr NULL to end 1st 1/2 */

    return s;                   /* return new instance */
}

/** insertion sort of linked list.
 *  re-orders list in sorted order.
 */
template <class T>
void list_t<T>::insertionsort (void) 
{ 
    node_t<T> *sorted = head,       /* initialize sorted list to 1st node */
              *pn = head->next;     /* advance original list node to next */

    sorted->next = NULL;            /* initialize sorted->next to NULL */

    while (pn) {                    /* iterate over existing from 2nd node */
        node_t<T> **pps = &sorted,  /* ptr-to-ptr to sorted list */
                *ps = *pps,         /* ptr to sorted list */
                *next = pn->next;   /* save list next as separate pointer */

        while (ps && cmp(ps, pn) < 0) {  /* loop until sorted */
            pps = &ps->next;        /* get address of next node */
            ps = ps->next;          /* get next node pointer */
        }

        *pps = pn;          /* insert existing in sort order as current */
        pn->next = ps;      /* set next as sorted next */
        pn = next;          /* reinitialize existing pointer to next */
    }

    head = sorted;          /* update head to sorted head */

    /* set tail pointer to last node after sort */
    for (pn = head; pn; pn = pn->next)
        tail = pn;
}

/* FIXME mergesort recursion not working */
template <class T>
node_t<T> *list_t<T>::mergesorted (node_t<T> *a, node_t<T> *b) 
{ 
    node_t<T> *result = nullptr;

    /* Base cases */
    if (!a) 
        return (b); 
    else if (!b) 
        return (a); 

    /* Pick either a or b, and recur */
    if (cmp (a, b) <= 0) { 
        result = a; 
        result->next = mergesorted (a->next, b); 
    } 
    else { 
        result = b; 
        result->next = mergesorted (a, b->next); 
    }

    return result; 
} 

/* split and merge splits in sort order */
template <class T>
void list_t<T>::mergesort_run (list_t<T> *l) 
{ 
    /* Base case -- length 0 or 1 */
    if (!l->head || !l->head->next) { 
        return; 
    } 

    /* Split head into 'a' and 'b' sublists */
    list_t<T> la = l->split(); 

    /* Recursively sort the sublists */
    mergesort_run(l); 
    mergesort_run(&la);

    /* merge the two sorted lists together */
    l->head = mergesorted (l->head, la.head);
}

/* wrapper to the actual mergesort routing in mergesort_run */
template <class T>
void list_t<T>::mergesort(void)
{
    mergesort_run (this);

    /* set tail pointer to last node after sort */
    for (node_t<T> *pn = head; pn; pn = pn->next)
        tail = pn;
}

int main (void) {

    list_t<int> l;

    int arr[] = {12, 11, 10, 7, 4, 14, 8, 16, 20, 19, 
                  2, 9, 1, 13, 17, 6, 15, 5, 3, 18};
    unsigned asz = sizeof arr / sizeof *arr;

    for (unsigned i = 0; i < asz; i++)
        l.addnode (arr[i]);

    l.prnlist();
#ifdef ISORT
    l.insertionsort();
#else
    l.mergesort();
#endif
    l.prnlist();
}
$ ./bin/ll_merge_post
 12 11 10 7 4 14 8 16 20 19 2 9 1 13 17 6 15 5 3 18
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
$ ./bin/ll_merge_post
 12 11 10 7 4 14 8 16 20 19 2 9 1 13 17 6 15 5 3 18
 0 16108560 16108656 16108688 16108560 16108816 16108784 16108848 16108752 16108720 16109072 16108976 16108944 16109008 16108880 16108912 16109136 16109104 16109168 16109040