第三章 从动态数组学习设计

3.1 动态数组与双向链表

/*
 * File:    typedef.h
 */

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

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File:    darray.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DARRAY_H
#define DARRAY_H

DECLS_BEGIN

struct _DArray;
typedef struct _DArray DArray;

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);

Ret    darray_insert(DArray* thiz, size_t index, void* data);
Ret    darray_prepend(DArray* thiz, void* data);
Ret    darray_append(DArray* thiz, void* data);
Ret    darray_delete(DArray* thiz, size_t index);
Ret    darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret    darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int    darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret    darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);

void darray_destroy(DArray* thiz);

DECLS_END

#endif/*DARRAY_H*/

/*
 * File:    darray.c
 */

#include <stdlib.h>
#include <stdint.h>
#include "darray.h"

struct _DArray
{
	void** data;
	size_t size;
	size_t alloc_size;

	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void darray_destroy_data(DArray* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	DArray* thiz = malloc(sizeof(DArray));

	if(thiz != NULL)
	{
		thiz->data  = NULL;
		thiz->size  = 0;
		thiz->alloc_size = 0;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size + need) > thiz->alloc_size)
	{
		/*  thiz->alloc_size * 1.5 + MIN_PRE_ALLOCATE_NR   */
		size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}

static Ret darray_shrink(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR))
	{
		size_t alloc_size = thiz->size + (thiz->size >> 1);

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return RET_OK;
}

Ret darray_insert(DArray* thiz, size_t index, void* data)
{
	Ret ret = RET_OOM;
	size_t cursor = index;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	cursor = cursor < thiz->size ? cursor : thiz->size;

	if(darray_expand(thiz, 1) == RET_OK)
	{
		size_t i = 0;
		for(i = thiz->size; i > cursor; i--)
		{
			thiz->data[i] = thiz->data[i-1];
		}

		thiz->data[cursor] = data;
		thiz->size++;
		
		ret = RET_OK;
	}

	return ret;
}

Ret darray_prepend(DArray* thiz, void* data)
{
	return darray_insert(thiz, 0, data);
}

Ret darray_append(DArray* thiz, void* data)
{
	return darray_insert(thiz, -1, data);
}

Ret darray_delete(DArray* thiz, size_t index)
{
	size_t i = 0;
	Ret ret = RET_OK;

	return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); 

	darray_destroy_data(thiz, thiz->data[index]);
	for(i = index; (i+1) < thiz->size; i++)
	{
		thiz->data[i] = thiz->data[i+1];
	}
	thiz->size--;

	darray_shrink(thiz);

	return RET_OK;
}

Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{

	return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	*data = thiz->data[index];

	return RET_OK;
}

Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	thiz->data[index] = data;

	return RET_OK;
}

size_t   darray_length(DArray* thiz)
{
	size_t length = 0;
	
	return_val_if_fail(thiz != NULL, 0);

	return thiz->size;
}

Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{
	size_t i = 0;	
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	for(i = 0; i < thiz->size; i++)
	{
		ret = visit(ctx, thiz->data[i]);
	}

	return ret;
}

int      darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	for(i = 0; i < thiz->size; i++)
	{
		if(cmp(ctx, thiz->data[i]) == 0)
		{
			break;
		}
	}

	return i;
}

void darray_destroy(DArray* thiz)
{
	size_t i = 0;
	
	if(thiz != NULL)
	{
		for(i = 0; i < thiz->size; i++)
		{
			darray_destroy_data(thiz, thiz->data[i]);
		}
		
		SAFE_FREE(thiz->data);
		SAFE_FREE(thiz);
	}

	return;
}

#ifdef DARRAY_TEST

#include <assert.h>

static int int_cmp(void* ctx, void* data)
{
	return (int)data - (int)ctx;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_darray(void)
{
	//int i = 0;
	//int n = 100;
	//int data = 0;

	intptr_t i = 0;
	intptr_t n = 100;
	intptr_t data = 0;

	DArray* darray = darray_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(darray_append(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);
		assert(darray_find(darray, int_cmp, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(darray_length(darray) == (n-i));
		assert(darray_delete(darray, 0) == RET_OK);
		assert(darray_length(darray) == (n-i-1));
		if((i + 1) < n)
		{
			assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(darray_length(darray) == 0);

	for(i = 0; i < n; i++)
	{
		assert(darray_prepend(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);

	darray_destroy(darray);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(darray_length(NULL) == 0);
	assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(darray_find(NULL, NULL, NULL) < 0);
	assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_darray();
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif

CFILES=darray.c
all:
	gcc -g -shared -fPIC  -lpthread $(CFILES) -o libdarray.so
	gcc -g -DDARRAY_TEST -lpthread $(CFILES)  -o darray_test

clean:
	rm -f *test *.exe *.so

3.2 排序

  • 冒泡排序
  • 快速排序
    先将元素分成两个区,所有小于某个元素的值在第一个区,其他在第二个区。然后分别对这两个区进行快速排序,直到所分的区只剩下一个元素为止。
  • 归并排序
    让左右两部分进行排序,然后把它们合并起来。在排序左右两部分时,同样使用归并排序.
/*
 * File:    typedef.h
 */

#include <stdio.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef intptr_t      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File:    sort.h
 */

#ifndef SORT_H
#define SORT_H

#include "typedef.h"

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp);

#endif/*SORT_H*/

/*
 * File:    sort.c
 */

#include "sort.h"

/*
 *  冒泡排序
 */
Ret bubble_sort(void** p_array, size_t nr, DataCompareFunc cmp)
{
	size_t i     = 0;
	size_t max   = 0;
	size_t right = 0;


	return_val_if_fail(p_array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr < 2){
		return RET_OK;
	}
	
	intptr_t* array = (intptr_t*)p_array;

	for(right = nr - 1; right > 0; right--){
		for(i = 1, max = 0; i < right; i++){
			if(cmp((void *)(array[i]), (void *)(array[max])) > 0){
				max = i;
			}
		}

		if(cmp((void *)(array[max]), (void *)(array[right])) > 0){
			intptr_t data = array[right];
			array[right] = array[max];
			array[max] = data;
		}
	}

	return RET_OK;
}


/*
 *  快速排序
 */
void quick_sort_impl(void** p_array, size_t left, size_t right, DataCompareFunc cmp)
{
	size_t save_left  = left;
	size_t save_right = right;
	
	intptr_t * array = (intptr_t *) p_array;    	

	intptr_t x = array[left];
	/*这个循环,让小于x的元素在左边,大于x的元素在右边*/
	while(left < right){
		while(cmp((void*)(array[right]), (void *) x) >= 0 && left < right) right--;
		if(left != right){
			array[left] = array[right];
			left++;
		}

		while(cmp((void *)(array[left]), (void *) x) <= 0 && left < right)	left++;
		if(left != right){
			array[right] = array[left];
			right--;
		}
	}
	array[left] = x;

	if(save_left < left){
		quick_sort_impl((void **)array, save_left, left-1, cmp);
	}

	if(save_right > left){
		quick_sort_impl((void **)array, left+1, save_right, cmp);
	}

	return;
}

Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1){
		quick_sort_impl(array, 0, nr - 1, cmp);
	}

	return ret;
}

/*
 * 归并排序
 */
static Ret merge_sort_impl(void** p_storage, void** p_array, size_t low, size_t mid, size_t high, DataCompareFunc cmp)
{
	size_t i = low;
	size_t j = low;
	size_t k = mid;

	intptr_t* storage = (intptr_t *) p_storage;
	intptr_t* array = (intptr_t *) p_array;
  
	/* 对左半部分排序 */
	if((low + 1) < mid){
		size_t x = low + ((mid - low) >> 1);
		merge_sort_impl(p_storage, p_array, low, x, mid, cmp);
	}
	
	/* 对右半部分排序 */
	if((mid + 1) < high){
		size_t x = mid + ((high - mid) >> 1);
		merge_sort_impl(p_storage, p_array, mid, x, high, cmp);
	}

	/* 合并两个有序数组 */	
	while(j < mid && k < high){
		if(cmp((void *)(array[j]), (void *)(array[k])) <= 0) {
			storage[i++] = array[j++];
		}
		else{
			storage[i++] = array[k++];
		}
	}

	while(j < mid){
		storage[i++] = array[j++];
	}

	while(k < high){
		storage[i++] = array[k++];
	}

	for(i = low; i < high; i++){
		array[i] = storage[i];
	}

	return RET_OK;
}

Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	void** storage = NULL;
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		storage = (void**)malloc(sizeof(void*) * nr);
		if(storage != NULL)
		{
			ret = merge_sort_impl(storage, array, 0, nr>>1, nr, cmp);

			free(storage);
		}
	}

	return ret;
}


#ifdef SORT_TEST
#include <assert.h>
intptr_t int_cmp(void* a, void* b)
{
	return (intptr_t)a - (intptr_t)b;
}

intptr_t int_cmp_invert(void* a, void* b)
{
	return (intptr_t)b - (intptr_t)a;
}

static void** create_int_array(intptr_t n)
{
	intptr_t i = 0;
	intptr_t* array = (intptr_t*)malloc(sizeof(intptr_t) * n);
	for(i = 0; i < n; i++)
	{
		array[i] = rand();
	}

	return (void**)array;
}

static void sort_test_one_asc(SortFunc sort, intptr_t n)
{
	intptr_t i = 0;
	void** p_array = create_int_array(n);

	sort(p_array, n, int_cmp);

	intptr_t* array =  (intptr_t *)p_array;
	for(i = 1; i < n; i++)
	{
		assert(array[i] >= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test_one_dec(SortFunc sort, intptr_t n)
{
	intptr_t i = 0;
	void** p_array = create_int_array(n);

	sort((void**)p_array, n, int_cmp_invert);


	intptr_t* array =  (intptr_t *)p_array;
	for(i = 1; i < n; i++)
	{
		assert(array[i] <= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test(SortFunc sort)
{
	intptr_t i = 0;
	for(i = 0; i < 1000; i++) {
		sort_test_one_dec(sort, i);
		sort_test_one_asc(sort, i);
	}
	return ;
}

intptr_t main(intptr_t argc, char* argv[])
{
	srand(100);
	sort_test(bubble_sort); // 冒泡排序 测试
	sort_test(quick_sort);  // 快速排序 测试
	sort_test(merge_sort);  // 归并排序 测试

	return 0;
}
#endif/*SORT_TEST*/
all:
	gcc -g sort.c -DSORT_TEST -o sort_test 

clean:
	rm -f *test *.exe *.so

3.3. 有序数组的两个应用

/*
 * File:    typedef.h
 */

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

#ifndef TYPEDEF_H
#define TYPEDEF_H

typedef enum _Ret
{
	RET_OK,
	RET_OOM,
	RET_STOP,
	RET_INVALID_PARAMS,
	RET_FAIL
}Ret;

typedef void     (*DataDestroyFunc)(void* ctx, void* data);
typedef int      (*DataCompareFunc)(void* ctx, void* data);
typedef Ret      (*DataVisitFunc)(void* ctx, void* data);

#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {
#define DECLS_END   }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/

#define return_if_fail(p) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n", \
		__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \
	{printf("%s:%d Warning: "#p" failed.\n",\
	__func__, __LINE__); return (ret);}

#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}

typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);

#endif/*TYPEDEF_H*/

/*
 * File : search.c
 */

#include "typedef.h"

int qsearch(void** array, size_t nr, void* data, DataCompareFunc cmp)
{
	int low    = 0;
	int mid    = 0;
	int high   = nr-1;
	int result = 0;

	return_val_if_fail(array != NULL && cmp != NULL, -1);

	while(low <= high)
	{
		mid  = low + ((high - low) >> 1);
		result = cmp(array[mid], data);

		if(result == 0){
			return mid;
		}else if(result < 0){
			low = mid + 1;
		}else{
			high = mid - 1;
		}
	}

	return -1;
}

#ifdef SEARCH_TEST
#include <assert.h>
int int_cmp(void* a, void* b)
{
	return (int)a - (int)b;
}

static void search_test(size_t n)
{
	int i = 0;
	int* array = (int*)malloc(n * sizeof(int));
	
	for(i = 0; i < n; i++){
		array[i] = i;
	}

	for(i = 0; i < n; i++){
		assert(qsearch((void**)array, n, (void*)i, int_cmp) == i);
	}

	free(array);

	return;
}

int main(int argc, char* argv[])
{
	int i = 0;
	for(i = 1; i < 1000; i++){
		search_test(i);
	}

	return 0;
}
#endif/*QSEARCH_TEST*/

/*
 * File:    sort.h
  */

#ifndef SORT_H
#define SORT_H

#include "typedef.h"

DECLS_BEGIN

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp);
Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp);

DECLS_END

#endif/*SORT_H*/

/*
 * File:    sort.c
 */

#include "sort.h"

Ret bubble_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	size_t i     = 0;
	size_t max   = 0;
	size_t right = 0;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr < 2) 
	{
		return RET_OK;
	}

	for(right = nr - 1; right > 0; right--)
	{
		for(i = 1, max = 0; i < right; i++)
		{
			if(cmp(array[i], array[max]) > 0)
			{
				max = i;
			}
		}

		if(cmp(array[max], array[right]) > 0)
		{
			void* data = array[right];
			array[right] = array[max];
			array[max] = data;
		}
	}

	return RET_OK;
}

void quick_sort_impl(void** array, size_t left, size_t right, DataCompareFunc cmp)
{
	size_t save_left  = left;
	size_t save_right = right;
	void* x = array[left];

	while(left < right)
	{
		while(cmp(array[right], x) >= 0 && left < right) right--;
		if(left != right)
		{
			array[left] = array[right];
			left++;
		}

		while(cmp(array[left], x) <= 0 && left < right)	left++;
		if(left != right)
		{
			array[right] = array[left];
			right--;
		}
	}
	array[left] = x;

	if(save_left < left)
	{
		quick_sort_impl(array, save_left, left-1, cmp);
	}

	if(save_right > left)
	{
		quick_sort_impl(array, left+1, save_right, cmp);
	}

	return;
}

Ret quick_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		quick_sort_impl(array, 0, nr - 1, cmp);
	}

	return ret;
}

static Ret merge_sort_impl(void** storage, void** array, size_t low, size_t mid, size_t high, DataCompareFunc cmp)
{
	size_t i = low;
	size_t j = low;
	size_t k = mid;

	if((low + 1) < mid)
	{
		size_t x = low + ((mid - low) >> 1);
		merge_sort_impl(storage, array, low, x, mid, cmp);
	}
	
	if((mid + 1) < high)
	{
		size_t x = mid + ((high - mid) >> 1);
		merge_sort_impl(storage, array, mid, x, high, cmp);
	}

	
	while(j < mid && k < high)
	{
		if(cmp(array[j], array[k]) <= 0)
		{
			storage[i++] = array[j++];
		}
		else
		{
			storage[i++] = array[k++];
		}
	}

	while(j < mid)
	{
		storage[i++] = array[j++];
	}

	while(k < high)
	{
		storage[i++] = array[k++];
	}

	for(i = low; i < high; i++)
	{
		array[i] = storage[i];
	}

	return RET_OK;
}

Ret merge_sort(void** array, size_t nr, DataCompareFunc cmp)
{
	void** storage = NULL;
	Ret ret = RET_OK;

	return_val_if_fail(array != NULL && cmp != NULL, RET_INVALID_PARAMS);

	if(nr > 1)
	{
		storage = (void**)malloc(sizeof(void*) * nr);
		if(storage != NULL)
		{
			ret = merge_sort_impl(storage, array, 0, nr>>1, nr, cmp);

			free(storage);
		}
	}

	return ret;
}


#ifdef SORT_TEST
#include <assert.h>
int int_cmp(void* a, void* b)
{
	return (int)a - (int)b;
}

int int_cmp_invert(void* a, void* b)
{
	return (int)b - (int)a;
}

static void** create_int_array(int n)
{
	int i = 0;
	int* array = (int*)malloc(sizeof(int) * n);

	for(i = 0; i < n; i++)
	{
		array[i] = rand();
	}

	return (void**)array;
}

static void sort_test_one_asc(SortFunc sort, int n)
{
	int i = 0;
	void** array = create_int_array(n);

	sort(array, n, int_cmp);

	for(i = 1; i < n; i++)
	{
		assert(array[i] >= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test_one_dec(SortFunc sort, int n)
{
	int i = 0;
	void** array = create_int_array(n);

	sort((void**)array, n, int_cmp_invert);

	for(i = 1; i < n; i++)
	{
		assert(array[i] <= array[i-1]);
	}

	free(array);

	return;
}

static void sort_test(SortFunc sort)
{
	int i = 0;
	for(i = 0; i < 1000; i++)
	{
		sort_test_one_dec(sort, i);
		sort_test_one_asc(sort, i);
	}

	return ;
}

int main(int argc, char* argv[])
{
	srand(100);

	sort_test(quick_sort);
	sort_test(merge_sort);
	sort_test(bubble_sort);

	return 0;
}
#endif/*SORT_TEST*/
/*
 * File:    darray.h
 */

#include <stdio.h>
#include "typedef.h"

#ifndef DARRAY_H
#define DARRAY_H

DECLS_BEGIN

struct _DArray;
typedef struct _DArray DArray;

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);

Ret    darray_insert(DArray* thiz, size_t index, void* data);
Ret    darray_prepend(DArray* thiz, void* data);
Ret    darray_append(DArray* thiz, void* data);
Ret    darray_delete(DArray* thiz, size_t index);
Ret    darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret    darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int    darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret    darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);
Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp);

void darray_destroy(DArray* thiz);

DECLS_END

#endif/*DARRAY_H*/

/*
 * File:    darray.c
 */

#include <stdlib.h>
#include "darray.h"

struct _DArray
{
	void** data;
	size_t size;
	size_t alloc_size;

	void* data_destroy_ctx;
	DataDestroyFunc data_destroy;
};

static void darray_destroy_data(DArray* thiz, void* data)
{
	if(thiz->data_destroy != NULL)
	{
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}

	return;
}

DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{
	DArray* thiz = malloc(sizeof(DArray));

	if(thiz != NULL)
	{
		thiz->data  = NULL;
		thiz->size  = 0;
		thiz->alloc_size = 0;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = ctx;
	}

	return thiz;
}

#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size + need) > thiz->alloc_size)
	{
		size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}

static Ret darray_shrink(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR))
	{
		size_t alloc_size = thiz->size + (thiz->size >> 1);

		void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);
		if(data != NULL)
		{
			thiz->data = data;
			thiz->alloc_size = alloc_size;
		}
	}

	return RET_OK;
}

Ret darray_insert(DArray* thiz, size_t index, void* data)
{
	Ret ret = RET_OOM;
	size_t cursor = index;
	return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); 

	cursor = cursor < thiz->size ? cursor : thiz->size;

	if(darray_expand(thiz, 1) == RET_OK)
	{
		size_t i = 0;
		for(i = thiz->size; i > cursor; i--)
		{
			thiz->data[i] = thiz->data[i-1];
		}

		thiz->data[cursor] = data;
		thiz->size++;
		
		ret = RET_OK;
	}

	return ret;
}

Ret darray_prepend(DArray* thiz, void* data)
{
	return darray_insert(thiz, 0, data);
}

Ret darray_append(DArray* thiz, void* data)
{
	return darray_insert(thiz, -1, data);
}

Ret darray_delete(DArray* thiz, size_t index)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); 

	darray_destroy_data(thiz, thiz->data[index]);
	for(i = index; (i+1) < thiz->size; i++)
	{
		thiz->data[i] = thiz->data[i+1];
	}
	thiz->size--;

	darray_shrink(thiz);

	return RET_OK;
}

Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{

	return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	*data = thiz->data[index];

	return RET_OK;
}

Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{
	return_val_if_fail(thiz != NULL && index < thiz->size, 
		RET_INVALID_PARAMS); 

	thiz->data[index] = data;

	return RET_OK;
}

size_t   darray_length(DArray* thiz)
{
	return_val_if_fail(thiz != NULL, 0);

	return thiz->size;
}

Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{
	size_t i = 0;	
	Ret ret = RET_OK;
	return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);

	for(i = 0; i < thiz->size; i++)
	{
		ret = visit(ctx, thiz->data[i]);
	}

	return ret;
}

int      darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{
	size_t i = 0;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	for(i = 0; i < thiz->size; i++)
	{
		if(cmp(ctx, thiz->data[i]) == 0)
		{
			break;
		}
	}

	return i;
}

void darray_destroy(DArray* thiz)
{
	size_t i = 0;
	
	if(thiz != NULL)
	{
		for(i = 0; i < thiz->size; i++)
		{
			darray_destroy_data(thiz, thiz->data[i]);
		}
		
		SAFE_FREE(thiz->data);
		SAFE_FREE(thiz);
	}

	return;
}

Ret    darray_sort(DArray* thiz, SortFunc sort, DataCompareFunc cmp)
{
	return_val_if_fail(thiz != NULL && sort != NULL && cmp != NULL, RET_INVALID_PARAMS);

	return sort(thiz->data, thiz->size, cmp);
}

#ifdef DARRAY_TEST

#include "sort.h"
#include <assert.h>
#include "test_helper.c"

static void darray_assert_sorted(DArray* thiz, DataCompareFunc cmp)
{
	size_t i = 0;
	for(i = 1; i < thiz->size; i++)
	{
		assert(cmp(thiz->data[i], thiz->data[i-1]) >= 0);
	}

	return;
}

static Ret check_and_dec_int(void* ctx, void* data)
{
	int* expected =(int*)ctx;
	assert(*expected == (int)data);

	(*expected)--;

	return RET_OK;
}

static void test_int_darray(void)
{
	int i = 0;
	int n = 100;
	int data = 0;
	DArray* darray = darray_create(NULL, NULL);

	for(i = 0; i < n; i++)
	{
		assert(darray_append(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);
		assert(darray_find(darray, cmp_int, (void*)i) == i);
	}

	for(i = 0; i < n; i++)
	{
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == (i));
		assert(darray_length(darray) == (n-i));
		assert(darray_delete(darray, 0) == RET_OK);
		assert(darray_length(darray) == (n-i-1));
		if((i + 1) < n)
		{
			assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
			assert((int)data == (i+1));
		}
	}
	
	assert(darray_length(darray) == 0);

	for(i = 0; i < n; i++)
	{
		assert(darray_prepend(darray, (void*)i) == RET_OK);
		assert(darray_length(darray) == (i + 1));
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == i);
		assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);
		assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);
		assert(data == 2*i);
		assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);
	}

	i = n - 1;
	assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);

	darray_sort(darray, quick_sort, cmp_int);
	darray_assert_sorted(darray, cmp_int);

	darray_destroy(darray);

	return;
}

static void test_invalid_params(void)
{
	printf("===========Warning is normal begin==============\n");
	assert(darray_length(NULL) == 0);
	assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);
	assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);
	assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);
	assert(darray_find(NULL, NULL, NULL) < 0);
	assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);
	printf("===========Warning is normal end==============\n");

	return;
}

static void single_thread_test(void)
{
	test_int_darray();
	test_invalid_params();

	return;
}

int main(int argc, char* argv[])
{
	single_thread_test();

	return 0;
}
#endif

/* 
 * File :  test_helper.c
 */

static int cmp_int(void* ctx, void* data)
{
	return (int)ctx - (int)data;
}

static Ret print_int(void* ctx, void* data)
{
	printf("%d ", (int)data);

	return RET_OK;
}
all:
	gcc -g -m32 -DDARRAY_TEST -lpthread darray.c sort.c -o darray_test
	gcc -g -m32 -Wall -DSORT_TEST sort.c -o sort_test
	gcc -g -m32 -Wall -DSEARCH_TEST search.c -o search_test
	gcc -g -m32 -Wall -DUNIQUE_TEST unique.c darray.c sort.c -o unique_test

clean:
	rm -f *test *.exe *.so