Generic double circular linked list - 通用双向循环链表C语言实现

cheungmine

双向循环链表是计算机数据结构里面最基础的一种。我采用C语言实现,可以存储任何数据类型。这个双向链表(dlist)用来替换单向链表(list),可以获得更好的效率。


本文内容不提供任何保障,任何人在不声明版权所有的前提下本文内容可以被用于任何目的。


双向链表文件:

unitype.h

dlist.h

dlist.c


测试项目文件:

main.c


下面是全部的源代码:

/****************************************************************************************
* unitype.h *
* 2008-03-15 Last created by cheungmine. *
* All rights reserved by cheungmine. *
****************************************************************************************/
#ifndef UNITYPE_H__
#define UNITYPE_H__
/* Standard C header files included */
#include <stdio.h>
#include <string.h>
#include <assert.h>
/*============================================================================*/
typedef signed char int8_t;
typedef unsigned char uint8_t, uchar_t, byte_t;
typedef short int16_t;
typedef unsigned short uint16_t, word_t, ushort_t; /* sizeof (uint16) must == 2 */
typedef int int32_t;
typedef unsigned int uint32_t, dword_t; /* sizeof (uint32) must == 4 */
#if defined(_WIN32) || defined(_WINCE)
typedef __int64 int64_t;
typedef unsigned __int64 uint64, qword_t;
#else /* linux */
typedef long long int64_t;
typedef unsigned long long uint64_t, qword_t;
#endif
typedef float float32_t;
typedef double float64_t;
typedef int bool_t, lresult_t;
#define bool_true 1
#define bool_false 0
#define res_success 0
#define res_error -1
#define res_false 1
#ifndef IN
#define IN
#endif
#ifndef OUT
#define OUT
#endif
#ifndef INOUT
#define INOUT
#endif
#ifndef OPTIONAL
#define OPTIONAL
#endif
#ifdef _DEBUG
#include <stdarg.h>
static void DBG_TRACE(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
#else
static void DBG_TRACE(const char *fmt, ...){}
#endif
/*============================================================================*/
#endif /* UNITYPE_H__ */

 

/*******************************************************************************
* dlist.h *
* Generic double circular linked list - can hold any type data. *
* cheungmine *
* Mar. 22, 2008. All Rights Reserved. *
* *
* ........................................... *
* dlist | ______ ______ ______ ______ | *
* _________ +->| node | | node | | node | | node | | *
* |size/head|---->| next+->| next+->| next+->| next+---- *
* --------- --+prev |<-+prev |<-+prev |<-+prev |<-- *
* | ------ ------ ------ ------ | *
* | front/head back/tail | *
* | begin end | *
* |...........................................| *
* *
******************************************************************************/
#ifndef DLIST_H_INCLUDED__
#define DLIST_H_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
#include "unitype.h"
#include <malloc.h>
/**
* dlist node type
*/
typedef struct _dlistnode_t
{
struct _dlistnode_t *_next;
struct _dlistnode_t *_prev;
union{
void *data;
struct _dlist_t *list;
const char *str;
int32_t val;
};
}dlistnode_t;

/**
* dlist type
*/
typedef struct _dlist_t
{
size_t _size; /* count of all nodes */
dlistnode_t *_head; /* point to the front node of list */
}dlist_t, *dlist_p;

/**
* A prototype of callbacke function called by:
* - dlist_destroy()
* - dlist_traverse()
* - dlist_nodes_free()
* 0 for no use
*/
typedef void(*pfunc_dlist_callback)(dlistnode_t* node, void *param);

/**
* A prototype of callback function called by:
* - dlist_sort()
* Returns:
* 0: a = b
* 1: a > b
* -1: a < b
*/
typedef int(*pfunc_dlist_compare_callback)(dlistnode_t* a, dlistnode_t* b, void *param);

/**
* A prototype example of free node data function implemented by caller:
*/
static void my_dlistnode_data_free(dlistnode_t *node, void *param)
{
printf(" free node: %d/n", node->val);
/* free(node->data); */
}

/**
* A prototype example of traverse implemented by caller:
*/
static void my_traverse_dlistnode_printf(dlistnode_t *node, void *param)
{
printf(" node: %ld/n", node->val);
}

/**
* An example of compare list node used by bubble sort ascend
*/
static int my_dlist_sort_nodes_ascend(dlistnode_t* a, dlistnode_t* b, void *param)
{
if (a->val > b->val)
return 1;
else if (a->val < b->val)
return -1;
else
return 0;
}

/**
* An example of compare list node used by bubble sort descend
*/
static int my_dlist_sort_nodes_descend(dlistnode_t* a, dlistnode_t* b, void *param)
{
if (a->val < b->val)
return 1;
else if (a->val > b->val)
return -1;
else
return 0;
}
/*===============================================================================
* *
* dlist public functions *
* *
*==============================================================================*/
/**
* Allocates a empty list from heap, this creates a new list
*/
dlist_t* dlist_create();

/**
* Clears a list and free all memory, the list cannot be used later
* Since the nodes data are allocated by caller, so caller MUST provide a callback
* function to free the node.
*/
void dlist_destroy(dlist_t *lst, pfunc_dlist_callback pfcbFreeNodeData, void *param);

/**
* Removes all nodes except for list itself
*/
void dlist_clear(dlist_t *lst, pfunc_dlist_callback pfcb, void *param);

/**
* Traverses a list, applied callback functionn for each node. So pfcbTraverseNode MUST be valid.
* If tail_to_head is bool_true, traverse is make from tail to head otherwise is from head to tail
*/
void dlist_traverse(dlist_t *lst, pfunc_dlist_callback pfcbTraverseNode, void *param, bool_t tail_to_head);

/**
* Creates a new node assigned with data, not allocates for data
*/
dlistnode_t* dlist_node_create(void* data);

/**
* Free the nodes from begin to end. If end node is 0, only free the begin node
*/
void dlist_nodes_free(dlistnode_t* begin_node, dlistnode_t* end_node, pfunc_dlist_callback pfcbFreeNodeData, void *param);

/**
* Calculate size of nodes from begin to end
*/
size_t dlist_nodes_size(dlistnode_t* begin_node, dlistnode_t* end_node);

/**
* Get head node of a list
*/
dlistnode_t* dlist_head_node(dlist_t *lst);

/**
* Get tail node of a list
*/
dlistnode_t* dlist_tail_node(dlist_t *lst);

/**
* Gets node by index: 0-based. 0 is head, -1 is tail.
* If index isnot a valid index (==-1 || >=0 && <size), return 0
*/
dlistnode_t* dlist_node_at(const dlist_t* lst, size_t index);

/**
* Appends a node to the back of list
*/
void dlist_push_back(dlist_t *lst, dlistnode_t *back_node);

/**
* Inserts a node as head of list
*/
void dlist_push_front(dlist_t *lst, dlistnode_t *front_node);

/**
* Removes the front node from a list and returns the node removed
*/
dlistnode_t* dlist_pop_front(dlist_t *lst);

/**
* Removes the back node from a list and returns the node removed
*/
dlistnode_t* dlist_pop_back(dlist_t *lst);

/**
* Inserts a node after the node into a list
*/
bool_t dlist_insert_after(dlist_t *lst, dlistnode_t *prev_node, dlistnode_t *ins_node);

/**
* Inserts a node before the node into a list
*/
bool_t dlist_insert_before(dlist_t *lst, dlistnode_t *back_node, dlistnode_t *ins_node);

/**
* Cut nodes from begin node to end node off the list, returns the node prior to
* the begin node cut off.
* Caller should free the nodes lead by begin node.
* When the begin and end nodes are the same one, it will only cut off that.
* When return 0 indicates list is empty (size==0)
* It can be explained that why not providing the way to cut off a single node here.
* NOTE: begin node must be prior to end node in sequence.
*
* dlistnode_t *begin = dlist_node_at(lst, 2);
* dlistnode_t *end = dlist_node_at(lst, 5);
* dlistnode_t *node = dlist_slice(lst, begin, end);
* dlist_nodes_free(begin, end, 0, 0);
*
* YOU CAN NOT APPLY dlist_nodes_free TO NODE WHICH IS NOT SLICED FROM LIST
* The following snippet is ILLEGITIMATE:
*
* dlistnode_t *begin = dlist_node_at(lst, 2);
* dlist_nodes_free(begin, begin, 0, 0);
*
* While the following snippet is correct:
* dlistnode_t *begin = dlist_node_at(lst, 2);
* dlist_slice(lst, begin, 0);
* dlist_nodes_free(begin, begin, 0, 0);
*/
dlistnode_t* dlist_slice(dlist_t* lst, dlistnode_t* begin, dlistnode_t* end);

/**
* Gets count of nodes in the list
*/
size_t dlist_size(const dlist_t* lst);

/**
* Appends the second list to the first list
*/
void dlist_concat(dlist_t *first, dlist_t *second);

/**
* Reverse list. For example the initial nodes are:0,1,2,3,
* after dlist_reverse will be: 3,2,1,0
*/
void dlist_reverse(dlist_t* lst);

/**
* Swap two nodes in list: front node must preceding the back node, only the situations below can be accepted:
* 1) a==b
* 2) a->b
* 3) a->...->b
* NOTE:
* b->a or b->...->a is unaccepted, that will cause an exception
*/
void dlist_swap_nodes(dlist_t* lst, dlistnode_t *ahead, dlistnode_t *back);

/**
* Bubble sort list nodes by ascend: 0,1,2,3,...,9
*/
void dlist_bubble_sort(dlist_t* lst, pfunc_dlist_compare_callback pfcbCompareNodes, void *param);

/**
* Merge sort src list to dst list. Caller can free src after merging.
* dst and src lists MUST be sorted by the same dlist_compare_callback as dlist_merge_sort
*/
void dlist_merge_sort(dlist_t* dst, dlist_t* src, pfunc_dlist_compare_callback pfcbCompareNodes, void *param);
#ifdef __cplusplus
}
#endif
#endif /* DLIST_H_INCLUDED__ */

 

 

/****************************************************************************************
* dlist.c *
* Generic sequential linked list node structure -- can hold any type data. *
* cheungmine *
* May. 22, 2008. All rights reserved. *
****************************************************************************************/
#include "dlist.h"
#include <assert.h>
#define DLIST_USE_TAIL_NODE(lst) (lst->_head->_prev)
#define DLIST_IS_HEAD_NODE(lst, node) (node==lst->_head)
#define DLIST_IS_TAIL_NODE(lst, node) (node->_next==lst->_head)
/*===============================================================================
* *
* dlist public functions *
* *
*==============================================================================*/
dlist_t* dlist_create()
{
dlist_t *dl = (dlist_t*) malloc (sizeof(dlist_t));
assert(dl);
dl->_size = 0;
dl->_head = 0;
return dl;
}

void dlist_destroy(dlist_t *lst, pfunc_dlist_callback pfcbFreeNodeData, void *param)
{
dlist_clear(lst, pfcbFreeNodeData, param);
free(lst);
}

void dlist_clear(dlist_t *lst, pfunc_dlist_callback pfcb, void *param)
{
dlistnode_t *node;
if (pfcb) {
while((node = dlist_pop_front(lst)) != 0){
(*pfcb)(node, param);
free(node);
}
}
else {
while((node = dlist_pop_front(lst)) != 0){
free(node);
}
}
assert (lst->_head==0 && lst->_size==0);
}
void dlist_traverse(dlist_t *lst, pfunc_dlist_callback pfcbTraverseNode, void *param, bool_t tail_to_head)
{
dlistnode_t* node;
assert(pfcbTraverseNode);
if (tail_to_head) {
node = DLIST_USE_TAIL_NODE(lst);
while (node) {
(*pfcbTraverseNode)(node, param);
if (DLIST_IS_HEAD_NODE(lst, node))
break;
node = node->_prev;
}
}
else {
node = lst->_head;
while (node) {
(*pfcbTraverseNode)(node, param);
if (DLIST_IS_TAIL_NODE(lst, node))
break;
node = node->_next;
}
}
}
dlistnode_t* dlist_pop_front(dlist_t *lst)
{
dlistnode_t *pop_node = 0;

if (lst->_head)
{
if (lst->_size==1){
pop_node = lst->_head;
pop_node->_next = pop_node->_prev = 0;
lst->_size = 0;
lst->_head = 0;
}
else{
assert(lst->_size>1);
pop_node = lst->_head;
lst->_head = pop_node->_next;
DLIST_USE_TAIL_NODE(lst) = pop_node->_prev;
DLIST_USE_TAIL_NODE(lst)->_next = lst->_head;
pop_node->_next = pop_node->_prev = 0;
lst->_size--;
}
}
assert(lst->_size >= 0);
return pop_node;
}

dlistnode_t* dlist_pop_back(dlist_t *lst)
{
dlistnode_t *pop_node = 0;

if (lst->_head)
{
if (lst->_size==1){
pop_node = lst->_head;
pop_node->_next = pop_node->_prev = 0;
lst->_size = 0;
lst->_head = 0;
}
else{
assert(lst->_size>1);
pop_node = DLIST_USE_TAIL_NODE(lst);
DLIST_USE_TAIL_NODE(lst) = pop_node->_prev;
assert(pop_node->_next==lst->_head);
pop_node->_prev->_next = pop_node->_next;
pop_node->_next = pop_node->_prev = 0;
lst->_size--;
}
}
assert(lst->_size >= 0);
return pop_node;
}

dlistnode_t* dlist_node_create(void* data)
{
dlistnode_t *node = (dlistnode_t*) malloc (sizeof(dlistnode_t));
assert(node);
node->_next = node->_prev = 0;
node->data = data;
return node;
}

void dlist_push_back(dlist_t *lst, dlistnode_t *back_node)
{
dlistnode_t *tail;
if (lst->_head) {
assert(lst->_size>0);
tail = DLIST_USE_TAIL_NODE(lst);
back_node->_prev = tail;
back_node->_next = tail->_next;
tail->_next = back_node;
lst->_head->_prev = back_node;
lst->_size++;
}
else {
assert(lst->_size==0);
lst->_head = back_node->_next = back_node->_prev = back_node;
lst->_size = 1;
}
}

void dlist_push_front(dlist_t *lst, dlistnode_t *front_node)
{
if (lst->_head) {
assert(lst->_size>0);
front_node->_next = lst->_head;
DLIST_USE_TAIL_NODE(lst)->_next = front_node;
front_node->_prev = DLIST_USE_TAIL_NODE(lst);
lst->_head->_prev = front_node;
lst->_head = front_node;
lst->_size++;
}
else {
assert(lst->_size==0);
lst->_head = front_node->_next = front_node->_prev = front_node;
lst->_size = 1;
}
}

void dlist_nodes_free(dlistnode_t* node, dlistnode_t* end_node, pfunc_dlist_callback pfcbFreeNodeData, void *param)
{
dlistnode_t* free_node;
while (node) {
free_node = node;
node = node->_next;

if (pfcbFreeNodeData)
(*pfcbFreeNodeData) (free_node, param);
free(free_node);
if (!end_node) /* only free node */
break;
if (node==end_node) {
if (pfcbFreeNodeData)
(*pfcbFreeNodeData) (node, param);
free(node);
break;
}
}
}

size_t dlist_size(const dlist_t* lst)
{
return lst->_size;
}

dlistnode_t* dlist_node_at(const dlist_t* lst, size_t index)
{
size_t i;
dlistnode_t *node;

assert(index==-1 || index==0 || index < lst->_size);
if (!lst->_head || index==0)
return lst->_head;
assert(lst->_head);
if (index==-1)
return lst->_head->_prev;
/* bad index */
if (index >= lst->_size)
return 0;
i = 0;
if (index <= lst->_size/2) {
/* To search from the head on */
node = lst->_head;
while (i < index) {
node = node->_next;
i++;
}
}
else {
/* It would be much quickly to search from the end on than the head */
node = DLIST_USE_TAIL_NODE(lst); /* tail node */
index = lst->_size - index - 1;
while (i < index) {
node = node->_prev;
i++;
}
}
return node;
}

void dlist_reverse(dlist_t* lst)
{
dlistnode_t *node;
dlistnode_t *next;
dlistnode_t *prev;
node = lst->_head;
while (node) {
next = node->_next;
prev = node->_prev;
node->_next = prev;
node->_prev = next;
prev = node;
node = next;
if (node==lst->_head) {
lst->_head = prev;
break;
}
}
}

size_t dlist_nodes_size(dlistnode_t* node, dlistnode_t* end_node)
{
size_t n = 0;
if (node==end_node || !end_node)
return 1;
while (node) {
n++;
node = node->_next;
if (node && node==end_node){
n++;
break;
}
}
return n;
}

dlistnode_t* dlist_slice(dlist_t* lst, dlistnode_t* begin, dlistnode_t* end)
{
dlistnode_t *n1, *n2; /* ...n1->begin->...->end->n2...*/
size_t c = dlist_nodes_size(begin, end);
if (c==0)
return lst->_head;
assert(lst->_head);
n1 = begin->_prev;
n2 = end->_next;
assert(n1 && n2);
n1->_next = n2;
n2->_prev = n1;
/* cut nodes off list */
begin->_prev = 0;
end->_next = 0;
if (lst->_head != begin) {
lst->_size -= c;
return n1;
}
else {
assert(lst->_head==begin);
if (DLIST_USE_TAIL_NODE(lst)==end) {
lst->_head = 0;
lst->_size = 0;
return 0;
}
else {
lst->_size -= c;
lst->_head = n1;
return n1;
}
}
return n1;
}

dlistnode_t* dlist_head_node(dlist_t *lst)
{
return lst->_head;
}

dlistnode_t* dlist_tail_node(dlist_t *lst)
{
return DLIST_USE_TAIL_NODE(lst);
}
bool_t dlist_insert_after(dlist_t *lst, dlistnode_t *prev_node, dlistnode_t *ins_node)
{
assert(lst);
if (!lst->_head) {
if (prev_node)
return bool_false;
dlist_push_front(lst, ins_node);
return bool_true;
}
else {
assert(lst->_head);
if (!prev_node)
return bool_false;
lst->_size++;
ins_node->_prev = prev_node;
ins_node->_next = prev_node->_next;
prev_node->_next->_prev = ins_node;
prev_node->_next = ins_node;
return bool_true;
}
}

bool_t dlist_insert_before(dlist_t *lst, dlistnode_t *back_node, dlistnode_t *ins_node)
{
assert(lst);
if (!lst->_head) {
if (back_node)
return bool_false;
dlist_push_back(lst, ins_node);
return bool_true;
}
else {
assert(lst->_head);
if (!back_node)
return bool_false;
if (lst->_head==back_node) {
dlist_push_front(lst, ins_node);
}
else {
lst->_size++;
ins_node->_next = back_node;
ins_node->_prev = back_node->_prev;
back_node->_prev->_next = ins_node;
back_node->_prev = ins_node;
}
return bool_true;
}
}

void dlist_concat(dlist_t *first, dlist_t *second)
{
assert(first && second);
if (first->_head) {
if (second->_head) {
dlistnode_t *second_tail = DLIST_USE_TAIL_NODE(second);
DLIST_USE_TAIL_NODE(first)->_next = second->_head;
DLIST_USE_TAIL_NODE(second)->_next = first->_head;
DLIST_USE_TAIL_NODE(second) = DLIST_USE_TAIL_NODE(first);
DLIST_USE_TAIL_NODE(first) = second_tail;

first->_size += second->_size;
second->_head = 0;
second->_size = 0;
}
}
else {
assert(!first->_head);
if (second->_head) {
first->_head = second->_head;
first->_size = second->_size;
second->_head = 0;
second->_size = 0;
}
}
}

void dlist_swap_nodes(dlist_t* lst, dlistnode_t *a, dlistnode_t *b)
{
dlistnode_t *p, *n;
assert(a && b);

if (a==b) {
/* [p]->[a|b]->[n] */
return;
}
else if (a->_next==b && b->_next==a) {
if (lst->_head==a)
lst->_head = b;
else
lst->_head = a;
}
else if (a->_next==b) {
/* [p]->[a]->[b]->[n] */
p = a->_prev;
n = b->_next;
p->_next = b;
b->_next = a;
a->_next = n;
n->_prev = a;
a->_prev = b;
b->_prev = p;
if (lst->_head==a) {
lst->_head = b;
}
}
else if (b->_next==a) {
/* [head:a]->...->[tail:b] */
p = b->_prev;
n = a->_next;
p->_next = a;
a->_next = b;
b->_next = n;
n->_prev = b;
b->_prev = a;
a->_prev = p;
if (lst->_head==a) {
lst->_head = b;
}
}
else {
/* [p]->[a]->[a1...b1]->[b]->[n] */
dlistnode_t *a1, *b1;
p = a->_prev;
n = b->_next;
a1 = a->_next;
b1 = b->_prev;
p->_next = b;
b->_next = a1;
b1->_next = a;
a->_next = n;
a1->_prev = b;
b->_prev = p;
n->_prev = a;
a->_prev = b1;
}
}

void dlist_sort_ascend(dlist_t* lst, pfunc_dlist_compare_callback pfcbCompareNodes, void *param)
{
int flag = 1;

dlistnode_t *first = 0;
dlistnode_t *second = 0;
dlistnode_t *last_sink = 0;
first = lst->_head;
while (flag==1) {
flag = 0;
while(first) {
second = first->_next;
assert(second);
if (second==lst->_head)
break;
if (second==last_sink)
break;
if (pfcbCompareNodes) {
if ((*pfcbCompareNodes)(first, second, param) > 0) {
flag = 1;
dlist_swap_nodes(lst, first, second);
last_sink = first;
}
}
else if (first->val > second->val) {
flag = 1;
dlist_swap_nodes(lst, first, second);
last_sink = first;
}

first = second;
}
}
}

void dlist_bubble_sort(dlist_t* lst, pfunc_dlist_compare_callback pfcbCompareNodes, void *param)
{
int flag = 1;

dlistnode_t *first = 0;
dlistnode_t *second = 0;
dlistnode_t *last_sink = 0;
while (flag==1) {
flag = 0;
first = lst->_head;
while(first) {
second = first->_next;
assert(second);
if (second==lst->_head)
break;
if (second==last_sink)
break;
if (pfcbCompareNodes) {
if ((*pfcbCompareNodes)(first, second, param) > 0) {
flag = 1;
dlist_swap_nodes(lst, first, second);
last_sink = first;
}
else
first = second;
}
else {
if (first->val > second->val) {
flag = 1;
dlist_swap_nodes(lst, first, second);
last_sink = first;
}
else
first = second;
}
}
}
}

void dlist_merge_sort(dlist_t* dst, dlist_t* src, pfunc_dlist_compare_callback pfcbCompareNodes, void *param)
{
dlistnode_t *dst_node;
dlistnode_t *src_node;
assert(dst && src);
if (!dst->_head) {
dlist_concat(dst, src);
return;
}
dst_node = dst->_head;
src_node = src->_head;

while (src_node) {
if (pfcbCompareNodes) {
if ((*pfcbCompareNodes)(dst_node, src_node, 0) > 0) {
dlist_insert_before(dst, dst_node, dlist_pop_front(src));
src_node = src->_head;
}
else {
dst_node = dst_node->_next;
if (dst_node==dst->_head) {
dlist_concat(dst, src);
return;
}
}
}
else {
if (dst_node->val > src_node->val) {
dlist_insert_before(dst, dst_node, dlist_pop_front(src));
src_node = src->_head;
}
else {
dst_node = dst_node->_next;

if (dst_node==dst->_head) {
dlist_concat(dst, src);
return;
}
}
}
}
}

 

测试文件:

// Test for dlist
// main.c
// by cheungmine
//
/* Detecting memory leaks only for windows .
* Place the following snippet where leak to be tested:
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
*/
#if defined(WIN32) && defined(_DEBUG)
#ifndef _CRTDBG_MAP_ALLOC
#pragma message( __FILE__": _CRTDBG_MAP_ALLOC defined only for DEBUG on Win32." )
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#endif
#endif
#include "../dlist.h"
void test_reverse();
void test_concat();
void test_slice();
void test_insert();
void test_swap();
void test_more_swap();
void test_sort_ascend();
void test_sort_descend();
void test_merge_sort();

///
int main()
{
// test_reverse();
// test_concat();
// test_slice();
// test_insert();
// test_swap();
// test_more_swap();
// test_sort_ascend();
// test_sort_descend();
test_merge_sort();
return 0;
}
///
void test_reverse()
{
//
// dlist_create
// dlist_traverse
// dlist_reverse
// dlist_destroy
//
int i;
dlistnode_t *nod;
dlist_p A;

printf("dlist_create A ok/n");
A = dlist_create();
for (i=0; i<10; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_reverse(A);
printf("dlist_traverse A (%d nodes) after dlist_reverse called:/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_destroy(A, 0, 0);
printf("dlist_destroy/n");
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}
void test_concat()
{
//
// dlist_create
// dlist_traverse
// dlist_concat
// dlist_destroy
//

int i;
dlistnode_t *nod;
dlist_p A, B;

A = dlist_create();
for (i=0; i<5; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

B = dlist_create();
for (i=0; i<4; i++){
nod = dlist_node_create(i+10);
dlist_push_back(B, nod);
}
printf("dlist_traverse B (%d nodes):/n", dlist_size(B));
dlist_traverse(B, my_traverse_dlistnode_printf, 0, 0);
dlist_concat(A, B);
printf("dlist_traverse B after concat to A (%d nodes):/n", dlist_size(B));
dlist_traverse(B, my_traverse_dlistnode_printf, 0, 0);
dlist_destroy(B, 0, 0);
printf("dlist_traverse A after dlist_concat with B (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_slice()
{
//
// dlist_node_at
// dlist_slice
//

int i;
dlistnode_t *nod;
dlist_p A;

A = dlist_create();
for (i=0; i<10; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
nod = dlist_node_create(11);
dlist_push_front(A, nod);
nod = dlist_node_create(10);
dlist_push_front(A, nod);
nod = dlist_node_create(12);
dlist_push_back(A, nod);
nod = dlist_node_at(A, 0);
printf("dlist_node_at 0: %d/n", nod->val);
nod = dlist_node_at(A, 1);
printf("dlist_node_at 1: %d/n", nod->val);
nod = dlist_node_at(A, -1);
printf("dlist_node_at -1: %d/n", nod->val);
printf("dlist_traverse A after push nodes(%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

nod = dlist_node_at(A, 1);
dlist_slice(A, nod, nod);
dlist_nodes_free(nod, 0, 0, 0);
printf("dlist_traverse A after dlist_slice(%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_insert()
{
//
// dlist_head_node
// dlist_tail_node
// dlist_insert_after
// dlist_insert_before
//

int i;
dlistnode_t *nod;
dlist_p A;
A = dlist_create();
for (i=0; i<10; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
nod = dlist_node_create(100);
dlist_insert_after(A, dlist_head_node(A), nod);

nod = dlist_node_create(200);
dlist_insert_after(A, dlist_tail_node(A), nod);
nod = dlist_node_create(300);
dlist_insert_before(A, dlist_head_node(A), nod);
nod = dlist_node_create(400);
dlist_insert_after(A, dlist_tail_node(A), nod);
nod = dlist_node_create(350);
dlist_insert_before(A, dlist_tail_node(A), nod);
nod = dlist_node_create(99);
dlist_insert_after(A, dlist_node_at(A, 5), nod);
nod = dlist_node_create(60);
dlist_insert_before(A, dlist_node_at(A, 6), nod);

nod = dlist_pop_back(A);
dlist_nodes_free(nod, nod, 0, 0);
nod = dlist_pop_front(A);
dlist_nodes_free(nod, 0, 0, 0);
printf("dlist_traverse A after insertion (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);


dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_swap()
{
//
// dlist_swap_nodes
//

int i;
dlistnode_t *nod;
dlist_p A;
A = dlist_create();
for (i=0; i<10; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 3), dlist_node_at(A, 4));
printf("dlist_traverse A after swap 3 with 4 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 3), dlist_node_at(A, 4));
printf("dlist_traverse A after swap 3 with 4 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 3), dlist_node_at(A, 7));
printf("dlist_traverse A after swap 3 with 7 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 3), dlist_node_at(A, 7));
printf("dlist_traverse A after swap 3 with 7 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 7), dlist_node_at(A, 9));
printf("dlist_traverse A after swap 7 with 9 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 7), dlist_node_at(A, 9));
printf("dlist_traverse A after swap 7 with 9 (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 0), dlist_node_at(A, -1));
printf("dlist_traverse A after swap head with tail (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_node_at(A, 0), dlist_node_at(A, -1));
printf("dlist_traverse A after swap head with tail (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_swap_nodes(A, dlist_node_at(A, -1)->_prev, dlist_node_at(A, -1));
printf("dlist_traverse A after swap pre-tail with tail (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_swap_nodes(A, dlist_node_at(A, 0), dlist_node_at(A, 0)->_next);
printf("dlist_traverse A after swap head with post-head (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_more_swap()
{
//
// dlist_clear
// dlist_swap_nodes
//

int i;
dlistnode_t *nod;
dlist_p A;
A = dlist_create();
for (i=0; i<2; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_swap_nodes(A, dlist_head_node(A), dlist_tail_node(A));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
/* Below is a bad call for we suppose that dlist_swap_nodes requires the swapped nodes: ahead precedes back */
dlist_swap_nodes(A, dlist_tail_node(A), dlist_head_node(A));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_clear(A, 0, 0);
for (i=0; i<3; i++){
nod = dlist_node_create(i);
dlist_push_back(A, nod);
}
// 0,1,2
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
// 1,0,2
dlist_swap_nodes(A, dlist_node_at(A, 0), dlist_node_at(A, 1));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
// 1,2,0
dlist_swap_nodes(A, dlist_node_at(A, 1), dlist_node_at(A, 2));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
// 1,0,2
dlist_swap_nodes(A, dlist_node_at(A, 1), dlist_node_at(A, 2));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
// 0,1,2
dlist_swap_nodes(A, dlist_node_at(A, 0), dlist_node_at(A, 1));
printf("dlist_traverse A after dlist_swap_nodes (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_sort_ascend()
{
//
// dlist_bubble_sort
//

int i;
dlistnode_t *nod;
dlist_p A;
int v[] = {2,46,5,17,1,2,3,99,12,56,66,21};
A = dlist_create();
for (i=0; i<sizeof(v)/sizeof(v[0]); i++){
nod = dlist_node_create(v[i]);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_bubble_sort(A, 0, 0);
printf("dlist_traverse A after dlist_bubble_sort (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}

void test_sort_descend()
{
//
// dlist_bubble_sort
//

int i;
dlistnode_t *nod;
dlist_p A;
int v[] = {2,46,5,17,1,2,3,99,12,56,66,21};
A = dlist_create();
for (i=0; i<sizeof(v)/sizeof(v[0]); i++){
nod = dlist_node_create(v[i]);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
dlist_bubble_sort(A, my_dlist_sort_nodes_descend, 0);
printf("dlist_traverse A after dlist_bubble_sort (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}
void test_merge_sort()
{
//
// dlist_bubble_sort
// dlist_merge_sort
//

int i;
dlistnode_t *nod;
dlist_p A, B;
int vA[] = {2,46,5,17,1,2,3,99,12,56,66,21};
int vB[] = {67,54,32,97,11,12,23,9,112,46,37,22};
// create list A
A = dlist_create();
for (i=0; i<sizeof(vA)/sizeof(vA[0]); i++){
nod = dlist_node_create(vA[i]);
dlist_push_back(A, nod);
}
printf("dlist_traverse A (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
// create list B
B = dlist_create();
for (i=0; i<sizeof(vB)/sizeof(vB[0]); i++){
nod = dlist_node_create(vB[i]);
dlist_push_back(B, nod);
}
printf("dlist_traverse B (%d nodes):/n", dlist_size(B));
dlist_traverse(B, my_traverse_dlistnode_printf, 0, 0);
// sort A and B with same compare function
dlist_bubble_sort(A, my_dlist_sort_nodes_ascend, 0);
dlist_bubble_sort(B, my_dlist_sort_nodes_ascend, 0);
printf("dlist_traverse A after dlist_bubble_sort (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
printf("dlist_traverse B after dlist_bubble_sort (%d nodes):/n", dlist_size(B));
dlist_traverse(B, my_traverse_dlistnode_printf, 0, 0);
// merge sort A with B
dlist_merge_sort(A, B, my_dlist_sort_nodes_ascend, 0);
printf("dlist_traverse A after dlist_merge_sort (%d nodes):/n", dlist_size(A));
dlist_traverse(A, my_traverse_dlistnode_printf, 0, 0);
printf("dlist_traverse B after dlist_merge_sort (%d nodes):/n", dlist_size(B));
dlist_traverse(B, my_traverse_dlistnode_printf, 0, 0);

dlist_destroy(B, 0, 0);
dlist_destroy(A, 0, 0);
#if defined(_CRTDBG_MAP_ALLOC)
_CrtDumpMemoryLeaks();
#endif
}