无法删除C中双向链表的重复数据

Can't delete the dublicated data of doubly linked list in C

我在从双向链表中删除重复数据时遇到问题。所以这个列表的 data 元素是一个数字数组。 我想用这个 delete_duplicates 代码删除重复数据的节点。 我使用以下 print_list 函数来打印列表。该函数似乎没有错误,因为它很好地打印了带有重复项的未排序的第一个列表。 我还使用此 convert_array_to_list 函数从数组中创建列表。同样,这个函数似乎没有错误,因为第一个列表没有任何问题。 编辑:我用亲爱的@Craig Estey 的回答更改了我的代码。这是最新的代码: 编辑:我写了上面程序的完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

struct doubly_linked_list
{
    int data[200];
    struct doubly_linked_list *prev;
    struct doubly_linked_list *next;
};

void print_list(struct doubly_linked_list *list_head)
{
    int i;

    printf("\n");

    for(i=0; i<200; i++) {

        printf("%d ", list_head->data[i]);
        list_head = list_head->next;
        if (i%25 == 0 & i != 0) {
            printf("\n");
        }
    } 
}

struct doubly_linked_list *convert_array_to_list(int array[], int size, struct doubly_linked_list *list_head)
{
    struct doubly_linked_list *list_first = NULL; //as the first node
    struct doubly_linked_list *list_new = NULL; //as the current node
    int i;
    
    if (size <= 0) //just to check
    {
        printf("Error!");
    }
    
    for(i=0; i<size; i++) {
        struct doubly_linked_list *list_now = (struct doubly_linked_list*)malloc (sizeof (struct doubly_linked_list)); //as the temporary node
        list_now->data[i] = array[i];

        if (NULL == list_now) //just to check
        {
            printf("Error!\n");
            break;
        }
        
        if(list_new == NULL)
        {
            list_now->data[i] = array[i];
            list_new = list_now;
            list_new->prev = NULL;
            list_new->next = NULL;
            list_first = list_new;
            //starting the list as circular
        }
        else
        {
            list_now->data[i] = array[i];
            list_new->next = list_now;
            list_now->prev = list_new;
            list_now->next = NULL;
            list_new = list_now;
            //adding the new node to the end of the list
        }
    }

    return list_first;
}

struct doubly_linked_list *delete_duplicates(struct doubly_linked_list *list_head)
{
    int i;
    struct doubly_linked_list *left;
    struct doubly_linked_list *right;
    struct doubly_linked_list *prev;
    struct doubly_linked_list *next;
    int deleted;
    for(left = list_head;  left != NULL;  left = left->next) {
        prev = left;
        for(right = left->next;  right != NULL;  right = next) {
            next = right->next;
            deleted = 0;
            for (i = 0;  i < sizeof(left->data) / sizeof(left->data[0]);  ++i) {
                deleted = (left->data[i] == right->data[i]);
                if (deleted) {
                    break;
                }
            }
            if (deleted) {
                prev->next = next;
                free(right);
            }
            else {
                prev = right;
            }       
        }
    }
};


int *random_array_generator(int array[], int size)
{
    int i;
    for(i=0; i<size; i++) {
        unsigned short int number = rand() % 50; //the array should be from [0,49]
        array[i] = number;
    }
    return array;
};

int main()
{
    int i;
    int numbers[200];
    srand(time(0));
    
    random_array_generator(numbers, 200);
    
    struct doubly_linked_list *list_head = NULL;
    
    list_head = convert_array_to_list(numbers, 200, list_head);
    
    printf("First list with dublication: \n");
    print_list(list_head);

    printf("\n\n");
    
    list_head = delete_duplicates(list_head);
    
    printf("Second list without dublication: \n");
    print_list(list_head);
    
    return 0;
}

第一个列表的输出是完美的,但它没有打印第二个列表。我调试了它并向 left->data[i]right->data[i] 添加了监视,它们似乎无法指向正确的数据。起初,left->data[0] 具有正确的值,而 right->data[0] 具有无意义的大数值。然后随着循环的进行,随着i的变化,left->data[i]的值也得到这个无意义的大数的值,程序进入delete_duplicates函数。毕竟,当它尝试打印第二个列表时,程序会收到一个名为“Segmentation fault”的错误,它无法访问 list_head->data[i] 值。我无法解决问题,我尝试了很多不同代码的组合,但是程序在指向数组的 next 元素时总是出错,它说它无法访问内存或 分段错误。我将不胜感激你的帮助。 非常感谢!

几个问题...

  1. 在删除 data 元素中字符的单个匹配上的节点后,代码 不会 跳出 i 循环,因此它最多尝试删除同一个节点 200 次。
  2. 认为[我没有仔细看]:删除给定节点后,执行list_head->next->next是一个“释放后使用”的错误。我们需要在 删除之前获取值 (例如)next = list->next
  3. 要将每个每个节点与每个其他节点进行比较,我们需要第二个嵌套循环来进行节点比较。
  4. list_head 可以 never 作为重复项删除,因此 no 需要有一个 return list_head; 作为list_head 不会 改变。
  5. 虽然我们可以有一个单独的 delete_node 函数 [用于其他目的],但实际的删除非常简单,如果 delete_duplicates 直接内联会更容易。
  6. delete_duplicates中,我们已经知道前一个节点是什么,所以使用delete_node(因为它必须重新扫描整个列表以找到前一个节点)。
  7. 选择重复的标准不明确。使用现有代码,如果 data 中的 any 元素匹配,则删除该节点。虽然这 一个 valid 要做的事情,但更常见的是删除一个节点 if all elements匹配。但是,我已经离开了初衷。

这是重构后的代码。注释为:

#include <stdlib.h>

struct doubly_linked_list {
    int data[200];
    struct doubly_linked_list *prev;
    struct doubly_linked_list *next;
};

struct doubly_linked_list *
delete_duplicates(struct doubly_linked_list *list_head)
{
    int i;
    struct doubly_linked_list *left;
    struct doubly_linked_list *right;
    struct doubly_linked_list *prev;
    struct doubly_linked_list *next;
    int del;

    for (left = list_head;  left != NULL;  left = left->next) {
        prev = left;

        for (right = left->next;  right != NULL;  right = next) {
            // point to next node:
            // (1) prevents "use after free" by the iteration expression above
            // (2) more efficient
            next = right->next;

            // say _not_ a duplicate
            del = 0;

            // scan buffer for a match
            for (i = 0;  i < sizeof(left->data) / sizeof(left->data[0]);  ++i) {
                del = (left->data[i] == right->data[i]);
                if (del)
                    break;
            }

            // delete duplicate node
            if (del) {
                prev->next = next;
                free(right);
            }

            // advance previous node
            else
                prev = right;
        }
    }

// NOTE/BUG: list_head will never change so this isn't needed
    return list_head;
}

更新:

Thank you all for your answers. Dear Craig Estey, I used the refactored code you wrote but the output was like, it prints the first element right but then all of the remaining elements were printed as 0. By the way I don't know why my question is closed because of debugging details, I'm still new here though :) – Ozdamar Kevser

有时,这里的人可能会对票数接近的人过于热心,特别是如果 OP 不回应要求澄清的评论。但是,这里已经有了这个答案。

正如我所提到的,我编写了[并编译]了上面的代码,但没有对其进行测试。

我创建了一个测试程序来验证事情。看起来我的重构函数 确实 工作但我没有在节点中设置 prev 指针 [因为我认为它是一个 单独 链表--现已修复]。但是,我不认为这会导致问题 if 向前打印列表。

因此,这可能与您创建或打印列表的方式有关。

这是带有测试程序的完全重构代码:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// NDATA -- number of elements in array
#ifndef NDATA
#define NDATA   200
#endif

// ALLMATCH -- duplicate detection critera
//   0=any element can match (original)
//   1=all must match (suitable for testing)
#ifndef ALLMATCH
#define ALLMATCH    1
#endif

typedef struct node node_t;
struct node {
    node_t *prev;
    node_t *next;
    int idx;                                // easy identifier for debug
    int data[NDATA];
};

node_t *global_head;

unsigned int opt_R;                         // random number seed
int opt_N;                                  // number of nodes to generate

// print_node -- print a node
void
print_node(node_t *head)
{
    int totlen = 0;

    for (int dataidx = 0;  dataidx < NDATA;  ++dataidx) {
        if (dataidx == 0)
            totlen += printf(" NODE  ");

        totlen += printf(" %6d",head->data[dataidx]);

        if (totlen >= 60) {
            printf("\n");
            totlen = 0;
        }
    }

    totlen += printf(" [%d]",head->idx);

    if (totlen > 0)
        printf("\n");
}

// print_list -- print list of nodes
void
print_list(node_t *head,const char *who)
{

    printf("\n");
    printf("%s:\n",who);

    for (;  head != NULL;  head = head->next)
        print_node(head);
}

// delete_duplicates -- delete duplicate nodes in list
void
delete_duplicates(node_t *list_head)
{
    int i;
    node_t *left;
    node_t *right;
    node_t *prev;
    node_t *next;
    int del;

    for (left = list_head;  left != NULL;  left = left->next) {
        prev = left;

        for (right = left->next;  right != NULL;  right = next) {
            // point to next node:
            // (1) prevents "use after free" by the iteration expression above
            // (2) more efficient
            next = right->next;

            // say _not_ a duplicate
#if ALLMATCH
            del = 1;
#else
            del = 0;
#endif

            // scan buffer for a match
            for (i = 0;  i < NDATA;  ++i) {
                // original -- delete if _any_ element matches
#if ! ALLMATCH
                del = (left->data[i] == right->data[i]);
                if (del)
                    break;
                // modified -- delete if _all_ element matches
#else
                if (left->data[i] != right->data[i]) {
                    del = 0;
                    break;
                }
#endif
            }

            // delete duplicate node
            if (del) {
                printf("delete_duplicates: %d is dup of %d\n",
                    right->idx,left->idx);

                prev = right->prev;

                // cross link previous and next nodes (eliminating current)
                if (prev != NULL)
                    prev->next = next;
                if (next != NULL)
                    next->prev = prev;

                free(right);
            }
        }
    }
}

// select_node -- select a random previous node
node_t *
select_node(node_t *head,int count)
{
    int lstidx = rand() % count;

    for (;  lstidx > 0;  --lstidx)
        head = head->next;

    if (head == NULL) {
        printf("find_dup: null head\n");
        exit(1);
    }

    return head;
}

// generate_list -- generate a list with a random number of duplicates
node_t *
generate_list(int count)
{
    node_t *head = NULL;
    node_t *prev = NULL;
    node_t temp;
    int dupcnt = 0;

    for (int lstidx = 0;  lstidx < count;  ++lstidx) {
        int dupflg = (rand() % 100) < 20;

        if (lstidx == 0)
            dupflg = 0;

        node_t *dup;

        // find a node that we'll duplicate
        if (dupflg) {
            dup = select_node(head,lstidx);
            ++dupcnt;
        }

        // generate new random node
        else {
            dup = &temp;
            for (int dataidx = 0;  dataidx < NDATA;  ++dataidx)
                dup->data[dataidx] = rand() & 0xFFFF;
        }

        node_t *newnode = malloc(sizeof(*newnode));

        // copy in the data
        for (int dataidx = 0;  dataidx < NDATA;  ++dataidx)
            newnode->data[dataidx] = dup->data[dataidx];

        // set the node id and links
        newnode->idx = lstidx;
        newnode->prev = prev;
        newnode->next = NULL;

        // append to tail of list
        if (prev != NULL)
            prev->next = newnode;

        // start new list
        else
            head = newnode;

        prev = newnode;
    }

    printf("generate_list: %d dups of %d total nodes\n",dupcnt,count);

    return head;
}

int
main(int argc,char **argv)
{

    --argc;
    ++argv;

    opt_N = 20;
    opt_R = 1;

    for (;  argc > 0;  --argc, ++argv) {
        char *cp = *argv;
        if (*cp != '-')
            break;

        cp += 2;
        switch (cp[-1]) {
        case 'N':
            opt_N = (*cp != 0) ? atoi(cp) : 50;
            break;

        case 'R':
            opt_R = (*cp != 0) ? atoi(cp) : time(NULL);
            break;
        }
    }

    printf("N = %d\n",opt_N);

    printf("R = %u\n",opt_R);
    srand(opt_R);

    global_head = generate_list(opt_N);
    print_list(global_head,"ORIGINAL");

    delete_duplicates(global_head);
    print_list(global_head,"NODUP");

    return 0;
}

这是 -DNDATA=1 的程序输出:

N = 20
R = 1
generate_list: 2 dups of 20 total nodes

ORIGINAL:
 NODE     9158 [0]
 NODE    18547 [1]
 NODE    23807 [2]
 NODE    22764 [3]
 NODE    31949 [4]
 NODE    55211 [5]
 NODE     7931 [6]
 NODE    57670 [7]
 NODE    25282 [8]
 NODE    10232 [9]
 NODE    25282 [10]
 NODE    17293 [11]
 NODE     9562 [12]
 NODE    29283 [13]
 NODE    55199 [14]
 NODE     1946 [15]
 NODE    23858 [16]
 NODE    55223 [17]
 NODE    58456 [18]
 NODE    23858 [19]
delete_duplicates: 10 is dup of 8
delete_duplicates: 19 is dup of 16

NODUP:
 NODE     9158 [0]
 NODE    18547 [1]
 NODE    23807 [2]
 NODE    22764 [3]
 NODE    31949 [4]
 NODE    55211 [5]
 NODE     7931 [6]
 NODE    57670 [7]
 NODE    25282 [8]
 NODE    10232 [9]
 NODE    17293 [11]
 NODE     9562 [12]
 NODE    29283 [13]
 NODE    55199 [14]
 NODE     1946 [15]
 NODE    23858 [16]
 NODE    55223 [17]
 NODE    58456 [18]

更新#2:

So I tried to use your test program in my computer but it didn't work well, it can't escape from printing the list like an infinite loop or so.

当我 运行 上面的程序 [从我的第一次更新] 时,我 没有 看到这个问题。请确保您使用的是我的最新示例完全

我在 [fedora] linux 下使用 gcc。大多数其他系统也应该没问题:

  1. 其他 linux 发行版或 *BSD 系统应该没有问题。
  2. MacOS 的构建方式可能很古怪(因为编译器是 clang 和 OS 的不同 relocatable/executable 格式)。
  3. Windows (visual studio) 可能会有问题,但通常也没有问题。
  4. Windows(cygwinmingw)应该更好

唯一的其他问题可能是您的系统的 rand 实现产生了不同的随机数,这暴露了我算法中的一个缺陷,因为使用的测试值不同。

And about my program, I tried so many options to delete the duplicates but still couldn't figure out. I edit my question and add the full program so you could debug it that way.

我还没有看到你最新的完整程序的最新更新。

I use the same printing function so it doesn't seem to have a problem at all, the poblem occurs when I try to delete the duplicated data. Thanks a lot. – Ozdamar Kevser

一些可能的调试思路:

  1. 运行调试器下的程序(例如gdb
  2. 运行 valgrind
  3. 下的程序
  4. -fsanitize=address编译程序

此外,“问题”的确切性质是什么?

我能想到的唯一可能与我的程序不同的是 head 作为列表的使用。

有两种用途:

  1. head 是列表的第一个 有效节点(这是我所做的)。
  2. head 是指向“虚拟”节点的指针。 prev 是列表 headnext 是列表 tail。 IMO,这是“列表”结构的“穷人”实现。

就我个人而言,我不喜欢这两个选项(尤其是 (2))。为了使事情更清楚和灵活,我更喜欢创建一个单独的列表结构(distinct 来自节点结构)。这类似于 (2),但更清晰、更明确。它还允许额外的信息,例如列表计数。

这是一个进一步重构的版本。它还 运行 使用不同的随机值多次测试:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define sysfault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

// NDATA -- number of elements in array
#ifndef NDATA
#define NDATA   1
#endif

// ALLMATCH -- duplicate detection critera
//   0=any element can match (original)
//   1=all must match (suitable for testing)
#ifndef ALLMATCH
#define ALLMATCH    1
#endif

typedef struct node node_t;
struct node {
    node_t *prev;
    node_t *next;
    int idx;                                // easy identifier for debug
    int data[NDATA];
};

typedef struct list {
    int count;
    node_t *head;
    node_t *tail;
} list_t;

list_t *global_list;                        // list that may have duplicates
list_t *nodup_list;                         // same list _without_ duplicates

int opt_N;                                  // number of nodes to generate
unsigned int opt_R;                         // random number seed
int opt_T;                                  // number of tests

// node_print -- print a node
void
node_print(node_t *cur)
{
    int totlen = 0;

    for (int dataidx = 0;  dataidx < NDATA;  ++dataidx) {
        if (dataidx == 0)
            totlen += printf(" NODE  ");

        totlen += printf(" %6d",cur->data[dataidx]);

        if (totlen >= 60) {
            printf("\n");
            totlen = 0;
        }
    }

    totlen += printf(" [%d]",cur->idx);

    if (totlen > 0)
        printf("\n");
}

// list_print -- print list of nodes (forward)
void
list_print(list_t *list,const char *who)
{
    node_t *cur;

    printf("\n");
    printf("%s: (%d elements)\n",who,list->count);

    for (cur = list->head;  cur != NULL;  cur = cur->next)
        node_print(cur);
}

// list_rprint -- print list of nodes (reverse)
void
list_rprint(list_t *list,const char *who)
{
    node_t *cur;

    printf("\n");
    printf("%s: (%d elements)\n",who,list->count);

    for (cur = list->tail;  cur != NULL;  cur = cur->prev)
        node_print(cur);
}

// node_equal -- compare two nodes
// RETURNS: 0=mismatch, 1=equal
int
node_equal(node_t *lhs,node_t *rhs)
{
    int match;

    // say _not_ a match
#if ALLMATCH
    match = 1;
#else
    match = 0;
#endif

    // scan buffer for a match
    for (int dataidx = 0;  dataidx < NDATA;  ++dataidx) {
        // original -- delete if _any_ element matches
#if ! ALLMATCH
        match = (lhs->data[dataidx] == rhs->data[dataidx]);
        if (match)
            break;

        // modified -- delete if _all_ element matches
#else
        if (lhs->data[dataidx] != rhs->data[dataidx]) {
            match = 0;
            break;
        }
#endif
    }

    return match;
}

// list_unlink -- unlink node from list
node_t *
list_unlink(list_t *list,node_t *del)
{
    node_t *prev;
    node_t *next;

    next = del->next;
    prev = del->prev;

    // cross link previous and next nodes (eliminating current)
    if (prev != NULL)
        prev->next = next;
    if (next != NULL)
        next->prev = prev;

    if (list->head == del)
        list->head = next;

    if (list->tail == del)
        list->tail = prev;

    list->count -= 1;

    free(del);

    return next;
}

// delete_duplicates -- delete duplicate nodes in list
void
delete_duplicates(list_t *list)
{
    node_t *left;
    node_t *right;
    node_t *next;
    int del;

    for (left = list->head;  left != NULL;  left = left->next) {
        for (right = left->next;  right != NULL;  right = next) {
            // decide if the node is a duplicate
            del = node_equal(left,right);

            // delete duplicate node
            if (del) {
                printf("delete_duplicates: %d is dup of %d\n",
                    right->idx,left->idx);
                next = list_unlink(list,right);
            }

            // advance to next node
            else
                next = right->next;
        }
    }
}

// list_select -- select a random previous node
node_t *
list_select(list_t *list)
{
    int lstidx = rand() % list->count;
    node_t *cur = list->head;

    for (;  lstidx > 0;  --lstidx)
        cur = cur->next;

    if (cur == NULL)
        sysfault("list_select: null cur\n");

    return cur;
}

// list_append -- append to list
void
list_append(list_t *list,node_t *src)
{
    node_t *newnode = malloc(sizeof(*newnode));

    // copy in the data
    for (int dataidx = 0;  dataidx < NDATA;  ++dataidx)
        newnode->data[dataidx] = src->data[dataidx];

    node_t *tail = list->tail;

    // set the node id and links
    newnode->idx = list->count++;
    newnode->prev = tail;
    newnode->next = NULL;

    // start of new list
    if (list->head == NULL)
        list->head = newnode;

    // set tail's forward link
    if (tail != NULL)
        tail->next = newnode;

    // set new node's backward link
    newnode->prev = tail;

    // make new node the tail of the list
    list->tail = newnode;
}

// list_generate -- generate a list with a random number of duplicates
void
list_generate(int count)
{
    node_t temp;
    int dupcnt = 0;

    // list that can have dups
    global_list = calloc(1,sizeof(*global_list));

    // list without dups
    nodup_list = calloc(1,sizeof(*nodup_list));

    for (int lstidx = 0;  lstidx < count;  ++lstidx) {
        int dupflg = (rand() % 100) < 20;

        if (lstidx == 0)
            dupflg = 0;

        node_t *cur;

        // find a node that we'll duplicate
        if (dupflg) {
            cur = list_select(global_list);
            ++dupcnt;
        }

        // generate new random node
        else {
            cur = &temp;
            for (int dataidx = 0;  dataidx < NDATA;  ++dataidx)
                cur->data[dataidx] = rand() & 0xFFFF;

            list_append(nodup_list,cur);
        }

        list_append(global_list,cur);
    }

    printf("list_generate: %d dups of %d total nodes\n",dupcnt,count);
}

// list_destroy -- destroy a list
list_t *
list_destroy(list_t *list)
{

    // free all nodes in list
    node_t *next;
    for (node_t *cur = list->head;  cur != NULL;  cur = next) {
        next = cur->next;
        free(cur);
    }

    // free the list itself
    free(list);

    list = NULL;

    return list;
}

// list_compare -- compare two lists
void
list_compare(list_t *lhslist,list_t *rhslist)
{
    node_t *lhs = lhslist->head;
    node_t *rhs = rhslist->head;

    if (lhslist->count != rhslist->count)
        sysfault("list_compare: count mismatch -- lhs=%d rhs=%d\n",
            lhslist->count,rhslist->count);

    while (1) {
        if (lhs == NULL)
            break;
        if (rhs == NULL)
            break;

        int same = node_equal(lhs,rhs);

        if (! same) {
            printf("list_compare: mismatch\n");
            node_print(lhs);
            node_print(rhs);
            sysfault("list_compare: aborting\n");
        }

        lhs = lhs->next;
        rhs = rhs->next;
    }

    printf("list_compare: complete\n");
}

// dotest -- do a test
void
dotest(int tstno)
{

    if (tstno > 1)
        printf("\n");
    for (int sep = 1;  sep <= 80;  ++sep)
        fputc('-',stdout);
    fputc('\n',stdout);

    printf("TEST %d of %d\n",tstno,opt_T);

    list_generate(opt_N);

    list_print(global_list,"global_list/ORIGINAL");
    list_print(nodup_list,"nodup_list");

    delete_duplicates(global_list);
    list_print(global_list,"global_list/NODUP");
    list_rprint(global_list,"global_list/REVERSE");

    printf("\n");
    list_compare(global_list,nodup_list);

    global_list = list_destroy(global_list);
    nodup_list = list_destroy(nodup_list);
}

int
main(int argc,char **argv)
{

    --argc;
    ++argv;

    opt_N = 20;
    opt_R = 1;
    opt_T = 5;

    for (;  argc > 0;  --argc, ++argv) {
        char *cp = *argv;
        if (*cp != '-')
            break;

        cp += 2;
        switch (cp[-1]) {
        case 'N':
            opt_N = (*cp != 0) ? atoi(cp) : 50;
            break;

        case 'R':
            opt_R = (*cp != 0) ? atoi(cp) : time(NULL);
            break;

        case 'T':
            opt_T = (*cp != 0) ? atoi(cp) : 10;
            break;
        }
    }

    printf("N = %d\n",opt_N);

    printf("R = %u\n",opt_R);
    srand(opt_R);

    if (opt_T <= 0)
        opt_T = 1;
    printf("T = %d\n",opt_T);

    for (int tstno = 1;  tstno < opt_T;  ++tstno)
        dotest(tstno);

    return 0;
}

下面是程序输出。

请注意,我还 built/ran 下的程序:

  1. valgrind 没有 错误
  2. 使用 -fsanitize=address 编译(无错误)
N = 20
R = 1
T = 5
--------------------------------------------------------------------------------
TEST 1 of 5
list_generate: 2 dups of 20 total nodes

global_list/ORIGINAL: (20 elements)
 NODE     9158 [0]
 NODE    18547 [1]
 NODE    23807 [2]
 NODE    22764 [3]
 NODE    31949 [4]
 NODE    55211 [5]
 NODE     7931 [6]
 NODE    57670 [7]
 NODE    25282 [8]
 NODE    10232 [9]
 NODE    25282 [10]
 NODE    17293 [11]
 NODE     9562 [12]
 NODE    29283 [13]
 NODE    55199 [14]
 NODE     1946 [15]
 NODE    23858 [16]
 NODE    55223 [17]
 NODE    58456 [18]
 NODE    23858 [19]

nodup_list: (18 elements)
 NODE     9158 [0]
 NODE    18547 [1]
 NODE    23807 [2]
 NODE    22764 [3]
 NODE    31949 [4]
 NODE    55211 [5]
 NODE     7931 [6]
 NODE    57670 [7]
 NODE    25282 [8]
 NODE    10232 [9]
 NODE    17293 [10]
 NODE     9562 [11]
 NODE    29283 [12]
 NODE    55199 [13]
 NODE     1946 [14]
 NODE    23858 [15]
 NODE    55223 [16]
 NODE    58456 [17]
delete_duplicates: 10 is dup of 8
delete_duplicates: 19 is dup of 16

global_list/NODUP: (18 elements)
 NODE     9158 [0]
 NODE    18547 [1]
 NODE    23807 [2]
 NODE    22764 [3]
 NODE    31949 [4]
 NODE    55211 [5]
 NODE     7931 [6]
 NODE    57670 [7]
 NODE    25282 [8]
 NODE    10232 [9]
 NODE    17293 [11]
 NODE     9562 [12]
 NODE    29283 [13]
 NODE    55199 [14]
 NODE     1946 [15]
 NODE    23858 [16]
 NODE    55223 [17]
 NODE    58456 [18]

global_list/REVERSE: (18 elements)
 NODE    58456 [18]
 NODE    55223 [17]
 NODE    23858 [16]
 NODE     1946 [15]
 NODE    55199 [14]
 NODE    29283 [13]
 NODE     9562 [12]
 NODE    17293 [11]
 NODE    10232 [9]
 NODE    25282 [8]
 NODE    57670 [7]
 NODE     7931 [6]
 NODE    55211 [5]
 NODE    31949 [4]
 NODE    22764 [3]
 NODE    23807 [2]
 NODE    18547 [1]
 NODE     9158 [0]

list_compare: complete

--------------------------------------------------------------------------------
TEST 2 of 5
list_generate: 5 dups of 20 total nodes

global_list/ORIGINAL: (20 elements)
 NODE    35165 [0]
 NODE    41751 [1]
 NODE    23273 [2]
 NODE    43220 [3]
 NODE    23273 [4]
 NODE    41751 [5]
 NODE    40628 [6]
 NODE    34321 [7]
 NODE     7554 [8]
 NODE    34369 [9]
 NODE    41751 [10]
 NODE    61575 [11]
 NODE    56809 [12]
 NODE    54433 [13]
 NODE    34321 [14]
 NODE     9063 [15]
 NODE    24321 [16]
 NODE    35165 [17]
 NODE    19164 [18]
 NODE    30614 [19]

nodup_list: (15 elements)
 NODE    35165 [0]
 NODE    41751 [1]
 NODE    23273 [2]
 NODE    43220 [3]
 NODE    40628 [4]
 NODE    34321 [5]
 NODE     7554 [6]
 NODE    34369 [7]
 NODE    61575 [8]
 NODE    56809 [9]
 NODE    54433 [10]
 NODE     9063 [11]
 NODE    24321 [12]
 NODE    19164 [13]
 NODE    30614 [14]
delete_duplicates: 17 is dup of 0
delete_duplicates: 5 is dup of 1
delete_duplicates: 10 is dup of 1
delete_duplicates: 4 is dup of 2
delete_duplicates: 14 is dup of 7

global_list/NODUP: (15 elements)
 NODE    35165 [0]
 NODE    41751 [1]
 NODE    23273 [2]
 NODE    43220 [3]
 NODE    40628 [6]
 NODE    34321 [7]
 NODE     7554 [8]
 NODE    34369 [9]
 NODE    61575 [11]
 NODE    56809 [12]
 NODE    54433 [13]
 NODE     9063 [15]
 NODE    24321 [16]
 NODE    19164 [18]
 NODE    30614 [19]

global_list/REVERSE: (15 elements)
 NODE    30614 [19]
 NODE    19164 [18]
 NODE    24321 [16]
 NODE     9063 [15]
 NODE    54433 [13]
 NODE    56809 [12]
 NODE    61575 [11]
 NODE    34369 [9]
 NODE     7554 [8]
 NODE    34321 [7]
 NODE    40628 [6]
 NODE    43220 [3]
 NODE    23273 [2]
 NODE    41751 [1]
 NODE    35165 [0]

list_compare: complete

--------------------------------------------------------------------------------
TEST 3 of 5
list_generate: 3 dups of 20 total nodes

global_list/ORIGINAL: (20 elements)
 NODE    42040 [0]
 NODE    20010 [1]
 NODE    31920 [2]
 NODE    31920 [3]
 NODE    52399 [4]
 NODE    36692 [5]
 NODE     6936 [6]
 NODE    42076 [7]
 NODE    18458 [8]
 NODE    47939 [9]
 NODE     9978 [10]
 NODE    49978 [11]
 NODE    42281 [12]
 NODE    16358 [13]
 NODE    42040 [14]
 NODE    51092 [15]
 NODE    18458 [16]
 NODE    43105 [17]
 NODE    59897 [18]
 NODE     9915 [19]

nodup_list: (17 elements)
 NODE    42040 [0]
 NODE    20010 [1]
 NODE    31920 [2]
 NODE    52399 [3]
 NODE    36692 [4]
 NODE     6936 [5]
 NODE    42076 [6]
 NODE    18458 [7]
 NODE    47939 [8]
 NODE     9978 [9]
 NODE    49978 [10]
 NODE    42281 [11]
 NODE    16358 [12]
 NODE    51092 [13]
 NODE    43105 [14]
 NODE    59897 [15]
 NODE     9915 [16]
delete_duplicates: 14 is dup of 0
delete_duplicates: 3 is dup of 2
delete_duplicates: 16 is dup of 8

global_list/NODUP: (17 elements)
 NODE    42040 [0]
 NODE    20010 [1]
 NODE    31920 [2]
 NODE    52399 [4]
 NODE    36692 [5]
 NODE     6936 [6]
 NODE    42076 [7]
 NODE    18458 [8]
 NODE    47939 [9]
 NODE     9978 [10]
 NODE    49978 [11]
 NODE    42281 [12]
 NODE    16358 [13]
 NODE    51092 [15]
 NODE    43105 [17]
 NODE    59897 [18]
 NODE     9915 [19]

global_list/REVERSE: (17 elements)
 NODE     9915 [19]
 NODE    59897 [18]
 NODE    43105 [17]
 NODE    51092 [15]
 NODE    16358 [13]
 NODE    42281 [12]
 NODE    49978 [11]
 NODE     9978 [10]
 NODE    47939 [9]
 NODE    18458 [8]
 NODE    42076 [7]
 NODE     6936 [6]
 NODE    36692 [5]
 NODE    52399 [4]
 NODE    31920 [2]
 NODE    20010 [1]
 NODE    42040 [0]

list_compare: complete

--------------------------------------------------------------------------------
TEST 4 of 5
list_generate: 6 dups of 20 total nodes

global_list/ORIGINAL: (20 elements)
 NODE    15513 [0]
 NODE    16533 [1]
 NODE    13803 [2]
 NODE    20659 [3]
 NODE    20659 [4]
 NODE    48896 [5]
 NODE    60065 [6]
 NODE     2789 [7]
 NODE    20659 [8]
 NODE    13803 [9]
 NODE      583 [10]
 NODE    38589 [11]
 NODE    38589 [12]
 NODE    40616 [13]
 NODE    20659 [14]
 NODE    64965 [15]
 NODE    31603 [16]
 NODE    15513 [17]
 NODE     9035 [18]
 NODE    12131 [19]

nodup_list: (14 elements)
 NODE    15513 [0]
 NODE    16533 [1]
 NODE    13803 [2]
 NODE    20659 [3]
 NODE    48896 [4]
 NODE    60065 [5]
 NODE     2789 [6]
 NODE      583 [7]
 NODE    38589 [8]
 NODE    40616 [9]
 NODE    64965 [10]
 NODE    31603 [11]
 NODE     9035 [12]
 NODE    12131 [13]
delete_duplicates: 17 is dup of 0
delete_duplicates: 9 is dup of 2
delete_duplicates: 4 is dup of 3
delete_duplicates: 8 is dup of 3
delete_duplicates: 14 is dup of 3
delete_duplicates: 12 is dup of 11

global_list/NODUP: (14 elements)
 NODE    15513 [0]
 NODE    16533 [1]
 NODE    13803 [2]
 NODE    20659 [3]
 NODE    48896 [5]
 NODE    60065 [6]
 NODE     2789 [7]
 NODE      583 [10]
 NODE    38589 [11]
 NODE    40616 [13]
 NODE    64965 [15]
 NODE    31603 [16]
 NODE     9035 [18]
 NODE    12131 [19]

global_list/REVERSE: (14 elements)
 NODE    12131 [19]
 NODE     9035 [18]
 NODE    31603 [16]
 NODE    64965 [15]
 NODE    40616 [13]
 NODE    38589 [11]
 NODE      583 [10]
 NODE     2789 [7]
 NODE    60065 [6]
 NODE    48896 [5]
 NODE    20659 [3]
 NODE    13803 [2]
 NODE    16533 [1]
 NODE    15513 [0]

list_compare: complete